blob: a1bf1688c4ac41fecbd92b5a832822b4b230c98d [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
Andrew Brown211d2b62015-02-18 11:12:02 -0800102 // parse packet
103 return StatusDataset.wireDecode(data.getContent(), FaceStatus.class);
104 }
Andrew Brownc46c1602015-02-18 10:45:56 -0800105
Andrew Brown211d2b62015-02-18 11:12:02 -0800106 /**
Andrew Brown63bed362015-02-18 11:28:50 -0800107 * Retrieve a list of FIB entries and their NextHopRecords from the given
108 * forwarder; calls /localhost/nfd/fib/list which requires a local Face (all
109 * non-local packets are dropped).
110 *
111 * @param forwarder Only a localhost Face
112 * @return
113 * @throws Exception
114 */
115 public static List<FibEntry> getFibList(Face forwarder) throws Exception {
116 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
117 Interest interest = new Interest(new Name("/localhost/nfd/fib/list"));
118 interest.setMustBeFresh(true);
119 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
120 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
121
122 // TODO verify that all faces are being returned; right now they don't
123 // match up with the results from nfd-status-http-server but no
124 // additional segments are present;
125 // see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
126 // send packet
Andrew Brown07466442015-02-24 09:07:02 -0800127 Data data = SegmentedClient.getDefault().getSync(forwarder, interest);
Andrew Brown63bed362015-02-18 11:28:50 -0800128 if (data == null) {
129 throw new Exception("Failed to retrieve list of fib entries from the forwarder.");
130 }
131
132 // parse packet
133 return StatusDataset.wireDecode(data.getContent(), FibEntry.class);
134 }
135
136 /**
Andrew Brown211d2b62015-02-18 11:12:02 -0800137 * Retrieve a list of routing entries from the RIB; calls
138 * /localhost/nfd/rib/list which requires a local Face (all non-local packets
139 * are dropped)
140 *
141 * @param forwarder Only a localhost Face
142 * @return
143 * @throws Exception
144 */
145 public static List<RibEntry> getRouteList(Face forwarder) throws Exception {
146 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
147 Interest interest = new Interest(new Name("/localhost/nfd/rib/list"));
148 interest.setMustBeFresh(true);
149 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
150 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
Andrew Brownc46c1602015-02-18 10:45:56 -0800151
Andrew Brown211d2b62015-02-18 11:12:02 -0800152 // send packet
Andrew Brown07466442015-02-24 09:07:02 -0800153 Data data = SegmentedClient.getDefault().getSync(forwarder, interest);
Andrew Brown211d2b62015-02-18 11:12:02 -0800154 if (data == null) {
155 throw new Exception("Failed to retrieve list of faces from the forwarder.");
156 }
Andrew Brownc46c1602015-02-18 10:45:56 -0800157
Andrew Brown211d2b62015-02-18 11:12:02 -0800158 // parse packet
159 return StatusDataset.wireDecode(data.getContent(), RibEntry.class);
160 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800161
Andrew Brown211d2b62015-02-18 11:12:02 -0800162 /**
163 * Helper method to register a new face on the forwarder; as mentioned at
164 * http://named-data.net/doc/NFD/current/manpages/nfdc.html, this is more for
165 * debugging; use 'register' instead
166 *
167 * @param forwarder Only a localhost Face
168 * @param faceId
169 * @param prefix
170 * @return
171 * @throws Exception
172 */
173 public static boolean addNextHop(Face forwarder, int faceId, Name prefix) throws Exception {
174 // build command name
175 Name command = new Name("/localhost/nfd/fib/add-nexthop");
176 ControlParameters parameters = new ControlParameters();
177 parameters.setName(prefix);
178 parameters.setFaceId(faceId);
179 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800180
Andrew Brown211d2b62015-02-18 11:12:02 -0800181 // send the interest
182 return sendCommandAndErrorCheck(forwarder, new Interest(command));
183 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800184
Andrew Brown211d2b62015-02-18 11:12:02 -0800185 /**
186 * Create a new face on the given forwarder. Ensure the forwarding face is on
187 * the local machine (management requests are to /localhost/...) and that
188 * command signing has been set up (e.g. forwarder.setCommandSigningInfo()).
189 *
190 * @param forwarder Only a localhost Face
191 * @param uri
192 * @return
193 * @throws java.lang.Exception
194 */
195 public static int createFace(Face forwarder, String uri) throws Exception {
196 Name command = new Name("/localhost/nfd/faces/create");
197 ControlParameters parameters = new ControlParameters();
198 parameters.setUri(uri);
199 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800200
Andrew Brown211d2b62015-02-18 11:12:02 -0800201 // send the interest
202 ControlResponse response = sendCommand(forwarder, new Interest(command));
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800203
Andrew Brown211d2b62015-02-18 11:12:02 -0800204 // check for body and that status code is OK (TODO: 200 should be replaced with a CONSTANT like ControlResponse.STATUS_OK)
205 if (response.getBody().isEmpty() || response.getStatusCode() != 200) {
206 throw new Exception("Failed to create face: " + uri + " " + response.getStatusText());
207 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800208
Andrew Brown211d2b62015-02-18 11:12:02 -0800209 // return
210 return response.getBody().get(0).getFaceId();
211 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800212
Andrew Brown211d2b62015-02-18 11:12:02 -0800213 /**
214 * Register a route on the forwarder; see
215 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
216 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
217 * protocol documentation. Ensure the forwarding face is on the local machine
218 * (management requests are to /localhost/...) and that command signing has
219 * been set up (e.g. forwarder.setCommandSigningInfo()).
220 *
221 * @param forwarder Only a localhost Face
222 * @param controlParameters
223 * @return
224 * @throws Exception
225 */
226 public static boolean register(Face forwarder, ControlParameters controlParameters) throws Exception {
227 // build command name
228 Name command = new Name("/localhost/nfd/rib/register");
229 command.append(controlParameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800230
Andrew Brown211d2b62015-02-18 11:12:02 -0800231 // send the interest
232 return sendCommandAndErrorCheck(forwarder, new Interest(command));
233 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800234
Andrew Brown211d2b62015-02-18 11:12:02 -0800235 /**
236 * Register a route on a forwarder; this will create a new face on the
237 * forwarder to the given URI/route pair. See register(Face,
238 * ControlParameters) for more details documentation.
239 *
240 * @param forwarder Only a localhost Face
241 * @param uri
242 * @param cost
243 * @param route
244 * @return true for successful registration
245 * @throws java.lang.Exception
246 */
247 public static boolean register(Face forwarder, String uri, Name route, int cost) throws Exception {
248 // create the new face
249 int faceId = createFace(forwarder, uri);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800250
Andrew Brown211d2b62015-02-18 11:12:02 -0800251 // run base method
252 return register(forwarder, faceId, route, cost);
253 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800254
Andrew Brown211d2b62015-02-18 11:12:02 -0800255 /**
256 * Register a route on a forwarder; this will not create a new face since it
257 * is provided a faceId. See register(Face, ControlParameters) for full
258 * documentation
259 *
260 * @param forwarder Only a localhost Face
261 * @param faceId
262 * @param route
263 * @param cost
264 * @return true for successful registration
265 * @throws java.lang.Exception
266 */
267 public static boolean register(Face forwarder, int faceId, Name route, int cost) throws Exception {
268 // build command name
269 ControlParameters parameters = new ControlParameters();
270 parameters.setName(route);
271 parameters.setFaceId(faceId);
272 parameters.setCost(cost);
273 ForwardingFlags flags = new ForwardingFlags();
274 flags.setCapture(true);
275 flags.setChildInherit(true);
276 parameters.setForwardingFlags(flags);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800277
Andrew Brown211d2b62015-02-18 11:12:02 -0800278 // run base method
279 return register(forwarder, parameters);
280 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800281
Andrew Brown211d2b62015-02-18 11:12:02 -0800282 /**
Andrew Brown63bed362015-02-18 11:28:50 -0800283 * Unregister a route on a forwarder; see
284 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
285 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
286 * protocol documentation. Ensure the forwarding face is on the local machine
287 * (management requests are to /localhost/...) and that command signing has
288 * been set up (e.g. forwarder.setCommandSigningInfo()
289 *
290 * @param forwarder
Andrew Brown07466442015-02-24 09:07:02 -0800291 * @param controlParameters
Andrew Brown63bed362015-02-18 11:28:50 -0800292 * @return
293 */
Andrew Brown07466442015-02-24 09:07:02 -0800294 public static boolean unregister(Face forwarder, ControlParameters controlParameters) throws Exception {
Andrew Brown63bed362015-02-18 11:28:50 -0800295 // build command name
296 Name command = new Name("/localhost/nfd/rib/unregister");
297 command.append(controlParameters.wireEncode());
298
299 // send the interest
300 return sendCommandAndErrorCheck(forwarder, new Interest(command));
301 }
302
303 /**
Andrew Brown07466442015-02-24 09:07:02 -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
312 * @param route
313 * @return
314 */
315 public static boolean unregister(Face forwarder, Name route) throws Exception {
316 // build command name
317 ControlParameters controlParameters = new ControlParameters();
318 controlParameters.setName(route);
319
320 // send the interest
321 return unregister(forwarder, controlParameters);
322 }
323
324 /**
325 * 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 * @param faceId
335 * @return
336 */
337 public static boolean unregister(Face forwarder, Name route, int faceId) throws Exception {
338 // build command name
339 ControlParameters controlParameters = new ControlParameters();
340 controlParameters.setName(route);
341 controlParameters.setFaceId(faceId);
342
343 // send the interest
344 return unregister(forwarder, controlParameters);
345 }
346
347 /**
348 * Unregister a route on a forwarder; see
349 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
350 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
351 * protocol documentation. Ensure the forwarding face is on the local machine
352 * (management requests are to /localhost/...) and that command signing has
353 * been set up (e.g. forwarder.setCommandSigningInfo()
354 *
355 * @param forwarder
356 * @param route
357 * @param uri
358 * @return
359 */
360 public static boolean unregister(Face forwarder, Name route, String uri) throws Exception {
361 int faceId = -1;
362 for(FaceStatus face : getFaceList(forwarder)){
363 if(face.getUri().matches(uri)){
364 faceId = face.getFaceId();
365 break;
366 }
367 }
368
369 if(faceId == -1){
370 throw new Exception("Face not found: " + uri);
371 }
372
373 // send the interest
374 return unregister(forwarder, route, faceId);
375 }
376
377 /**
Andrew Brown211d2b62015-02-18 11:12:02 -0800378 * Set a strategy on the forwarder; see
379 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
380 * usage and http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice
381 * for protocol documentation. Ensure the forwarding face is on the local
382 * machine (management requests are to /localhost/...) and that command
383 * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
384 *
385 * @param forwarder Only a localhost Face
386 * @param prefix
387 * @param strategy
388 * @return true for successful command
389 * @throws Exception
390 */
391 public static boolean setStrategy(Face forwarder, Name prefix, Name strategy) throws Exception {
392 // build command name
393 Name command = new Name("/localhost/nfd/strategy-choice/set");
394 ControlParameters parameters = new ControlParameters();
395 parameters.setName(prefix);
396 parameters.setStrategy(strategy);
397 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800398
Andrew Brown211d2b62015-02-18 11:12:02 -0800399 // send the interest
400 return sendCommandAndErrorCheck(forwarder, new Interest(command));
401 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800402
Andrew Brown211d2b62015-02-18 11:12:02 -0800403 /**
404 * Send an interest as a command to the forwarder; this method will convert
405 * the interest to a command interest and block until a response is received
406 * from the forwarder. Ensure the forwarding face is on the local machine
407 * (management requests are to /localhost/...) and that command signing has
408 * been set up (e.g. forwarder.setCommandSigningInfo()).
409 *
410 * @param forwarder Only a localhost Face
411 * @param interest As described at
412 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
413 * requested interest must have encoded ControlParameters appended to the
414 * interest name
415 * @return
416 * @throws net.named_data.jndn.security.SecurityException
417 * @throws java.io.IOException
418 * @throws net.named_data.jndn.encoding.EncodingException
419 */
420 public static ControlResponse sendCommand(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
421 forwarder.makeCommandInterest(interest);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800422
Andrew Brown211d2b62015-02-18 11:12:02 -0800423 // send command packet
424 Data data = Client.getDefault().getSync(forwarder, interest);
425 if (data == null) {
426 throw new IOException("Failed to receive command response.");
427 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800428
Andrew Brown211d2b62015-02-18 11:12:02 -0800429 // return response
430 ControlResponse response = new ControlResponse();
431 response.wireDecode(data.getContent().buf());
432 return response;
433 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800434
Andrew Brown211d2b62015-02-18 11:12:02 -0800435 /**
436 * Send an interest as a command to the forwarder; this method will convert
437 * the interest to a command interest and block until a response is received
438 * from the forwarder.
439 *
440 * @param forwarder Only a localhost Face
441 * @param interest As described at
442 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
443 * requested interest must have encoded ControlParameters appended to the
444 * interest name
445 * @return
446 * @throws net.named_data.jndn.security.SecurityException
447 * @throws java.io.IOException
448 * @throws net.named_data.jndn.encoding.EncodingException
449 */
450 public static boolean sendCommandAndErrorCheck(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
451 ControlResponse response = sendCommand(forwarder, interest);
452 if (response.getStatusCode() < 400) {
453 return true;
454 } else {
455 logger.warning("Command sent but failed: " + response.getStatusCode() + " " + response.getStatusText());
456 return false;
457 }
458 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800459}