blob: e19f517c1aeec291d8e62b4edc65687d9d9ec950 [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
14import com.intel.jndn.utils.Client;
15import java.io.IOException;
16import java.util.List;
17import net.named_data.jndn.ControlParameters;
18import net.named_data.jndn.Data;
19import net.named_data.jndn.Face;
20import net.named_data.jndn.ForwardingFlags;
21import net.named_data.jndn.Interest;
22import net.named_data.jndn.Name;
23import net.named_data.jndn.encoding.EncodingException;
24import net.named_data.jndn.security.SecurityException;
25import org.apache.logging.log4j.LogManager;
26import org.apache.logging.log4j.Logger;
27
28/**
29 * Helper class for interacting with an NDN forwarder daemon; see
30 * http://redmine.named-data.net/projects/nfd/wiki/Management for explanations
31 * of the various protocols used.
32 *
33 * @author Andrew Brown <andrew.brown@intel.com>
34 */
35public class NFD {
36
37 public final static long DEFAULT_TIMEOUT = 2000;
38 private static final Logger logger = LogManager.getLogger();
39
40 /**
41 * Ping a forwarder on an existing face to verify that the forwarder is
42 * working and responding to requests; this version sends a discovery packet
43 * to /localhost/nfd which should always respond if the requestor is on the
44 * same machine as the NDN forwarding daemon.
45 *
46 * @param face
47 * @return true if successful, false otherwise
48 */
49 public static boolean pingLocal(Face face) {
50 return ping(face, new Name("/localhost/nfd"));
51 }
52
53 /**
54 * Request a name on an existing face to verify the forwarder is working and
55 * responding to requests. Note that the name must be served or cached on
56 * the forwarder for this to return true.
57 *
58 * @param face
59 * @param name
60 * @return true if successful, false otherwise
61 */
62 public static boolean ping(Face face, Name name) {
63 // build interest
64 Interest interest = new Interest(name);
65 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
66 interest.setMustBeFresh(true);
67
68 // send packet
69 Data data = Client.getDefault().getSync(face, interest);
70 return data != null;
71 }
72
73 /**
74 * Retrieve a list of faces and their status from the given forwarder; calls
75 * /localhost/nfd/faces/list which requires a local Face (all non-local
76 * packets are dropped)
77 *
78 * @param forwarder Only a localhost Face
79 * @return
80 * @throws Exception
81 */
82 public static List<FaceStatus> getFaceList(Face forwarder) throws Exception {
83 // build management Interest packet; see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
84 Interest interest = new Interest(new Name("/localhost/nfd/faces/list"));
85 interest.setMustBeFresh(true);
86 interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
87 interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
88
89 // TODO verify that all faces are being returned; right now they don't
90 // match up with the results from nfd-status-http-server but no
91 // additional segments are present;
92 // see http://redmine.named-data.net/projects/nfd/wiki/StatusDataset
93 // send packet
94 Data data = Client.getDefault().getSync(forwarder, interest);
95 if (data == null) {
96 throw new Exception("Failed to retrieve list of faces from the forwarder.");
97 }
98
99 // parse packet
100 return FaceStatus.decode(data);
101 }
102
103 /**
104 * Helper method to register a new face on the forwarder; as mentioned at
105 * http://named-data.net/doc/NFD/current/manpages/nfdc.html, this is more
106 * for debugging; use 'register' instead
107 *
108 * @param forwarder Only a localhost Face
109 * @param faceId
110 * @param prefix
111 * @return
112 * @throws Exception
113 */
114 public static boolean addNextHop(Face forwarder, int faceId, Name prefix) throws Exception {
115 // build command name
116 Name command = new Name("/localhost/nfd/fib/add-nexthop");
117 ControlParameters parameters = new ControlParameters();
118 parameters.setName(prefix);
119 parameters.setFaceId(faceId);
120 command.append(parameters.wireEncode());
121
122 // send the interest
123 return sendCommandAndErrorCheck(forwarder, new Interest(command));
124 }
125
126 /**
127 * Create a new face on the given forwarder. Ensure the forwarding face is
128 * on the local machine (management requests are to /localhost/...) and that
129 * command signing has been set up (e.g. forwarder.setCommandSigningInfo()).
130 *
131 * @param forwarder Only a localhost Face
132 * @param uri
133 * @return
134 * @throws java.lang.Exception
135 */
136 public static int createFace(Face forwarder, String uri) throws Exception {
137 Name command = new Name("/localhost/nfd/faces/create");
138 ControlParameters parameters = new ControlParameters();
139 parameters.setUri(uri);
140 command.append(parameters.wireEncode());
141
142 // send the interest
143 ControlResponse response = sendCommand(forwarder, new Interest(command));
144
145 // check for body
146 if (response.Body.isEmpty()) {
147 throw new Exception("Failed to create face: " + uri);
148 }
149
150 // return
151 return response.Body.get(0).getFaceId();
152 }
153
154 /**
155 * Register a route on the forwarder; see
156 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
157 * usage and http://redmine.named-data.net/projects/nfd/wiki/RibMgmt for
158 * protocol documentation. Ensure the forwarding face is on the local
159 * machine (management requests are to /localhost/...) and that command
160 * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
161 *
162 * @param forwarder Only a localhost Face
163 * @param controlParameters
164 * @return
165 * @throws Exception
166 */
167 public static boolean register(Face forwarder, ControlParameters controlParameters) throws Exception {
168 // build command name
169 Name command = new Name("/localhost/nfd/rib/register");
170 command.append(controlParameters.wireEncode());
171
172 // send the interest
173 return sendCommandAndErrorCheck(forwarder, new Interest(command));
174 }
175
176 /**
177 * Register a route on a forwarder; this will create a new face on the
178 * forwarder to the given URI/route pair. See register(Face,
179 * ControlParameters) for more details documentation.
180 *
181 * @param forwarder Only a localhost Face
182 * @param uri
183 * @param cost
184 * @param route
185 * @return true for successful registration
186 * @throws java.lang.Exception
187 */
188 public static boolean register(Face forwarder, String uri, Name route, int cost) throws Exception {
189 // create the new face
190 int faceId = createFace(forwarder, uri);
191
192 // run base method
193 return register(forwarder, faceId, route, cost);
194 }
195
196 /**
197 * Register a route on a forwarder; this will not create a new face since it
198 * is provided a faceId. See register(Face, ControlParameters) for full
199 * documentation
200 *
201 * @param forwarder Only a localhost Face
202 * @param faceId
203 * @param route
204 * @param cost
205 * @return true for successful registration
206 * @throws java.lang.Exception
207 */
208 public static boolean register(Face forwarder, int faceId, Name route, int cost) throws Exception {
209 // build command name
210 ControlParameters parameters = new ControlParameters();
211 parameters.setName(route);
212 parameters.setFaceId(faceId);
213 parameters.setCost(cost);
214 ForwardingFlags flags = new ForwardingFlags();
215 flags.setCapture(true);
216 flags.setChildInherit(true);
217 parameters.setForwardingFlags(flags);
218
219 // run base method
220 return register(forwarder, parameters);
221 }
222
223 /**
224 * Set a strategy on the forwarder; see
225 * http://named-data.net/doc/NFD/current/manpages/nfdc.html for command-line
226 * usage and http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice
227 * for protocol documentation. Ensure the forwarding face is on the local
228 * machine (management requests are to /localhost/...) and that command
229 * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
230 *
231 * @param forwarder Only a localhost Face
232 * @param prefix
233 * @param strategy
234 * @return true for successful command
235 * @throws Exception
236 */
237 public static boolean setStrategy(Face forwarder, Name prefix, Name strategy) throws Exception {
238 // build command name
239 Name command = new Name("/localhost/nfd/strategy-choice/set");
240 ControlParameters parameters = new ControlParameters();
241 parameters.setName(prefix);
242 parameters.setStrategy(strategy);
243 command.append(parameters.wireEncode());
244
245 // send the interest
246 return sendCommandAndErrorCheck(forwarder, new Interest(command));
247 }
248
249 /**
250 * Send an interest as a command to the forwarder; this method will convert
251 * the interest to a command interest and block until a response is received
252 * from the forwarder. Ensure the forwarding face is on the local machine
253 * (management requests are to /localhost/...) and that command signing has
254 * been set up (e.g. forwarder.setCommandSigningInfo()).
255 *
256 * @param forwarder Only a localhost Face
257 * @param interest As described at
258 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
259 * requested interest must have encoded ControlParameters appended to the
260 * interest name
261 * @return
262 * @throws net.named_data.jndn.security.SecurityException
263 * @throws java.io.IOException
264 * @throws net.named_data.jndn.encoding.EncodingException
265 */
266 public static ControlResponse sendCommand(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
267 forwarder.makeCommandInterest(interest);
268
269 // send command packet
270 Data data = Client.getDefault().getSync(forwarder, interest);
271 if (data == null) {
272 throw new IOException("Failed to receive command response.");
273 }
274
275 // return response
276 return ControlResponse.decode(data);
277 }
278
279 /**
280 * Send an interest as a command to the forwarder; this method will convert
281 * the interest to a command interest and block until a response is received
282 * from the forwarder.
283 *
284 * @param forwarder Only a localhost Face
285 * @param interest As described at
286 * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
287 * requested interest must have encoded ControlParameters appended to the
288 * interest name
289 * @return
290 * @throws net.named_data.jndn.security.SecurityException
291 * @throws java.io.IOException
292 * @throws net.named_data.jndn.encoding.EncodingException
293 */
294 public static boolean sendCommandAndErrorCheck(Face forwarder, Interest interest) throws SecurityException, IOException, EncodingException {
295 ControlResponse response = sendCommand(forwarder, interest);
296 if (response.StatusCode < 400) {
297 return true;
298 } else {
299 logger.warn("Command sent but failed: " + response.StatusCode + " " + response.StatusText);
300 return false;
301 }
302 }
303}