blob: e05b2a930b200c47780efe53e16fb5c837741d65 [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;
20import java.io.IOException;
21import java.util.List;
22import net.named_data.jndn.ControlParameters;
23import net.named_data.jndn.Data;
24import net.named_data.jndn.Face;
25import net.named_data.jndn.ForwardingFlags;
26import net.named_data.jndn.Interest;
27import net.named_data.jndn.Name;
28import net.named_data.jndn.encoding.EncodingException;
29import net.named_data.jndn.security.SecurityException;
Andrew Brownc46c1602015-02-18 10:45:56 -080030import java.util.logging.Logger;
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080031
32/**
33 * Helper class for interacting with an NDN forwarder daemon; see
34 * http://redmine.named-data.net/projects/nfd/wiki/Management for explanations
35 * of the various protocols used.
36 *
37 * @author Andrew Brown <andrew.brown@intel.com>
38 */
39public class NFD {
40
Andrew Brown211d2b62015-02-18 11:12:02 -080041 public final static long DEFAULT_TIMEOUT = 2000;
42 static private final Logger logger = Logger.getLogger(NFD.class.getName());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080043
Andrew Brown211d2b62015-02-18 11:12:02 -080044 /**
45 * Ping a forwarder on an existing face to verify that the forwarder is
46 * working and responding to requests; this version sends a discovery packet
47 * to /localhost/nfd which should always respond if the requestor is on the
48 * same machine as the NDN forwarding daemon.
49 *
50 * @param face
51 * @return true if successful, false otherwise
52 */
53 public static boolean pingLocal(Face face) {
54 return ping(face, new Name("/localhost/nfd"));
55 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080056
Andrew Brown211d2b62015-02-18 11:12:02 -080057 /**
58 * Request a name on an existing face to verify the forwarder is working and
59 * responding to requests. Note that the name must be served or cached on the
60 * forwarder for this to return true.
61 *
62 * @param face
63 * @param name
64 * @return true if successful, false otherwise
65 */
66 public static boolean ping(Face face, Name name) {
67 // build interest
68 Interest interest = new Interest(name);
69 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
70 interest.setMustBeFresh(true);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080071
Andrew Brown211d2b62015-02-18 11:12:02 -080072 // send packet
73 Data data = Client.getDefault().getSync(face, interest);
74 return data != null;
75 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080076
Andrew Brown211d2b62015-02-18 11:12:02 -080077 /**
78 * Retrieve a list of faces and their status from the given forwarder; calls
79 * /localhost/nfd/faces/list which requires a local Face (all non-local
80 * packets are dropped)
81 *
82 * @param forwarder Only a localhost Face
83 * @return
84 * @throws Exception
85 */
86 public static List<FaceStatus> getFaceList(Face forwarder) throws Exception {
87 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
88 Interest interest = new Interest(new Name("/localhost/nfd/faces/list"));
89 interest.setMustBeFresh(true);
90 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
91 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -080092
Andrew Brown63bed362015-02-18 11:28:50 -080093 // TODO verify that all faces are being returned; right now they don't
Andrew Brown211d2b62015-02-18 11:12:02 -080094 // match up with the results from nfd-status-http-server but no
95 // additional segments are present;
96 // see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
97 // send packet
98 Data data = Client.getDefault().getSync(forwarder, interest);
99 if (data == null) {
100 throw new Exception("Failed to retrieve list of faces from the forwarder.");
101 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800102
Andrew Brown211d2b62015-02-18 11:12:02 -0800103 // parse packet
104 return StatusDataset.wireDecode(data.getContent(), FaceStatus.class);
105 }
Andrew Brownc46c1602015-02-18 10:45:56 -0800106
Andrew Brown211d2b62015-02-18 11:12:02 -0800107 /**
Andrew Brown63bed362015-02-18 11:28:50 -0800108 * Retrieve a list of FIB entries and their NextHopRecords from the given
109 * forwarder; calls /localhost/nfd/fib/list which requires a local Face (all
110 * non-local packets are dropped).
111 *
112 * @param forwarder Only a localhost Face
113 * @return
114 * @throws Exception
115 */
116 public static List<FibEntry> getFibList(Face forwarder) throws Exception {
117 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
118 Interest interest = new Interest(new Name("/localhost/nfd/fib/list"));
119 interest.setMustBeFresh(true);
120 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
121 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
122
123 // TODO verify that all faces are being returned; right now they don't
124 // match up with the results from nfd-status-http-server but no
125 // additional segments are present;
126 // see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
127 // send packet
128 Data data = Client.getDefault().getSync(forwarder, interest);
129 if (data == null) {
130 throw new Exception("Failed to retrieve list of fib entries from the forwarder.");
131 }
132
133 // parse packet
134 return StatusDataset.wireDecode(data.getContent(), FibEntry.class);
135 }
136
137 /**
Andrew Brown211d2b62015-02-18 11:12:02 -0800138 * Retrieve a list of routing entries from the RIB; calls
139 * /localhost/nfd/rib/list which requires a local Face (all non-local packets
140 * are dropped)
141 *
142 * @param forwarder Only a localhost Face
143 * @return
144 * @throws Exception
145 */
146 public static List<RibEntry> getRouteList(Face forwarder) throws Exception {
147 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
148 Interest interest = new Interest(new Name("/localhost/nfd/rib/list"));
149 interest.setMustBeFresh(true);
150 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
151 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
Andrew Brownc46c1602015-02-18 10:45:56 -0800152
Andrew Brown211d2b62015-02-18 11:12:02 -0800153 // send packet
154 Data data = Client.getDefault().getSync(forwarder, interest);
155 if (data == null) {
156 throw new Exception("Failed to retrieve list of faces from the forwarder.");
157 }
Andrew Brownc46c1602015-02-18 10:45:56 -0800158
Andrew Brown211d2b62015-02-18 11:12:02 -0800159 // parse packet
160 return StatusDataset.wireDecode(data.getContent(), RibEntry.class);
161 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800162
Andrew Brown211d2b62015-02-18 11:12:02 -0800163 /**
164 * Helper method to register a new face on the forwarder; as mentioned at
165 * http://named-data.net/doc/NFD/current/manpages/nfdc.html, this is more for
166 * debugging; use 'register' instead
167 *
168 * @param forwarder Only a localhost Face
169 * @param faceId
170 * @param prefix
171 * @return
172 * @throws Exception
173 */
174 public static boolean addNextHop(Face forwarder, int faceId, Name prefix) throws Exception {
175 // build command name
176 Name command = new Name("/localhost/nfd/fib/add-nexthop");
177 ControlParameters parameters = new ControlParameters();
178 parameters.setName(prefix);
179 parameters.setFaceId(faceId);
180 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800181
Andrew Brown211d2b62015-02-18 11:12:02 -0800182 // send the interest
183 return sendCommandAndErrorCheck(forwarder, new Interest(command));
184 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800185
Andrew Brown211d2b62015-02-18 11:12:02 -0800186 /**
187 * Create a new face on the given forwarder. Ensure the forwarding face is on
188 * the local machine (management requests are to /localhost/...) and that
189 * command signing has been set up (e.g. forwarder.setCommandSigningInfo()).
190 *
191 * @param forwarder Only a localhost Face
192 * @param uri
193 * @return
194 * @throws java.lang.Exception
195 */
196 public static int createFace(Face forwarder, String uri) throws Exception {
197 Name command = new Name("/localhost/nfd/faces/create");
198 ControlParameters parameters = new ControlParameters();
199 parameters.setUri(uri);
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 ControlResponse response = sendCommand(forwarder, new Interest(command));
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800204
Andrew Brown211d2b62015-02-18 11:12:02 -0800205 // check for body and that status code is OK (TODO: 200 should be replaced with a CONSTANT like ControlResponse.STATUS_OK)
206 if (response.getBody().isEmpty() || response.getStatusCode() != 200) {
207 throw new Exception("Failed to create face: " + uri + " " + response.getStatusText());
208 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800209
Andrew Brown211d2b62015-02-18 11:12:02 -0800210 // return
211 return response.getBody().get(0).getFaceId();
212 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800213
Andrew Brown211d2b62015-02-18 11:12:02 -0800214 /**
215 * Register a route on the forwarder; see
216 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
217 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
218 * protocol documentation. Ensure the forwarding face is on the local machine
219 * (management requests are to /localhost/...) and that command signing has
220 * been set up (e.g. forwarder.setCommandSigningInfo()).
221 *
222 * @param forwarder Only a localhost Face
223 * @param controlParameters
224 * @return
225 * @throws Exception
226 */
227 public static boolean register(Face forwarder, ControlParameters controlParameters) throws Exception {
228 // build command name
229 Name command = new Name("/localhost/nfd/rib/register");
230 command.append(controlParameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800231
Andrew Brown211d2b62015-02-18 11:12:02 -0800232 // send the interest
233 return sendCommandAndErrorCheck(forwarder, new Interest(command));
234 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800235
Andrew Brown211d2b62015-02-18 11:12:02 -0800236 /**
237 * Register a route on a forwarder; this will create a new face on the
238 * forwarder to the given URI/route pair. See register(Face,
239 * ControlParameters) for more details documentation.
240 *
241 * @param forwarder Only a localhost Face
242 * @param uri
243 * @param cost
244 * @param route
245 * @return true for successful registration
246 * @throws java.lang.Exception
247 */
248 public static boolean register(Face forwarder, String uri, Name route, int cost) throws Exception {
249 // create the new face
250 int faceId = createFace(forwarder, uri);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800251
Andrew Brown211d2b62015-02-18 11:12:02 -0800252 // run base method
253 return register(forwarder, faceId, route, cost);
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 not create a new face since it
258 * is provided a faceId. See register(Face, ControlParameters) for full
259 * documentation
260 *
261 * @param forwarder Only a localhost Face
262 * @param faceId
263 * @param route
264 * @param cost
265 * @return true for successful registration
266 * @throws java.lang.Exception
267 */
268 public static boolean register(Face forwarder, int faceId, Name route, int cost) throws Exception {
269 // build command name
270 ControlParameters parameters = new ControlParameters();
271 parameters.setName(route);
272 parameters.setFaceId(faceId);
273 parameters.setCost(cost);
274 ForwardingFlags flags = new ForwardingFlags();
275 flags.setCapture(true);
276 flags.setChildInherit(true);
277 parameters.setForwardingFlags(flags);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800278
Andrew Brown211d2b62015-02-18 11:12:02 -0800279 // run base method
280 return register(forwarder, parameters);
281 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800282
Andrew Brown211d2b62015-02-18 11:12:02 -0800283 /**
Andrew Brown63bed362015-02-18 11:28:50 -0800284 * Unregister a route on a forwarder; see
285 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
286 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
287 * protocol documentation. Ensure the forwarding face is on the local machine
288 * (management requests are to /localhost/...) and that command signing has
289 * been set up (e.g. forwarder.setCommandSigningInfo()
290 *
291 * @param forwarder
292 * @param route
293 * @return
294 */
295 public static boolean unregister(Face forwarder, Name route) throws Exception{
296 // build command name
297 ControlParameters controlParameters = new ControlParameters();
298 controlParameters.setName(route);
299
300 // build command name
301 Name command = new Name("/localhost/nfd/rib/unregister");
302 command.append(controlParameters.wireEncode());
303
304 // send the interest
305 return sendCommandAndErrorCheck(forwarder, new Interest(command));
306 }
307
308 /**
Andrew Brown211d2b62015-02-18 11:12:02 -0800309 * Set a strategy on the forwarder; see
310 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
311 * usage and http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice
312 * for protocol documentation. Ensure the forwarding face is on the local
313 * machine (management requests are to /localhost/...) and that command
314 * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
315 *
316 * @param forwarder Only a localhost Face
317 * @param prefix
318 * @param strategy
319 * @return true for successful command
320 * @throws Exception
321 */
322 public static boolean setStrategy(Face forwarder, Name prefix, Name strategy) throws Exception {
323 // build command name
324 Name command = new Name("/localhost/nfd/strategy-choice/set");
325 ControlParameters parameters = new ControlParameters();
326 parameters.setName(prefix);
327 parameters.setStrategy(strategy);
328 command.append(parameters.wireEncode());
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800329
Andrew Brown211d2b62015-02-18 11:12:02 -0800330 // send the interest
331 return sendCommandAndErrorCheck(forwarder, new Interest(command));
332 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800333
Andrew Brown211d2b62015-02-18 11:12:02 -0800334 /**
335 * Send an interest as a command to the forwarder; this method will convert
336 * the interest to a command interest and block until a response is received
337 * from the forwarder. Ensure the forwarding face is on the local machine
338 * (management requests are to /localhost/...) and that command signing has
339 * been set up (e.g. forwarder.setCommandSigningInfo()).
340 *
341 * @param forwarder Only a localhost Face
342 * @param interest As described at
343 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
344 * requested interest must have encoded ControlParameters appended to the
345 * interest name
346 * @return
347 * @throws net.named_data.jndn.security.SecurityException
348 * @throws java.io.IOException
349 * @throws net.named_data.jndn.encoding.EncodingException
350 */
351 public static ControlResponse sendCommand(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
352 forwarder.makeCommandInterest(interest);
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800353
Andrew Brown211d2b62015-02-18 11:12:02 -0800354 // send command packet
355 Data data = Client.getDefault().getSync(forwarder, interest);
356 if (data == null) {
357 throw new IOException("Failed to receive command response.");
358 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800359
Andrew Brown211d2b62015-02-18 11:12:02 -0800360 // return response
361 ControlResponse response = new ControlResponse();
362 response.wireDecode(data.getContent().buf());
363 return response;
364 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800365
Andrew Brown211d2b62015-02-18 11:12:02 -0800366 /**
367 * Send an interest as a command to the forwarder; this method will convert
368 * the interest to a command interest and block until a response is received
369 * from the forwarder.
370 *
371 * @param forwarder Only a localhost Face
372 * @param interest As described at
373 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
374 * requested interest must have encoded ControlParameters appended to the
375 * interest name
376 * @return
377 * @throws net.named_data.jndn.security.SecurityException
378 * @throws java.io.IOException
379 * @throws net.named_data.jndn.encoding.EncodingException
380 */
381 public static boolean sendCommandAndErrorCheck(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
382 ControlResponse response = sendCommand(forwarder, interest);
383 if (response.getStatusCode() < 400) {
384 return true;
385 } else {
386 logger.warning("Command sent but failed: " + response.getStatusCode() + " " + response.getStatusText());
387 return false;
388 }
389 }
Andrew Brown2f1fdbf2015-01-21 10:52:29 -0800390}