Adding LINEAR examples for ccn_emu_live
[nepi.git] / examples / ccn_emu_live / planetlab_4_nodes_linear.py
1 #!/usr/bin/env python\r
2 \r
3 ###############################################################################\r
4 #\r
5 #    NEPI, a framework to manage network experiments\r
6 #\r
7 #    This program is free software: you can redistribute it and/or modify\r
8 #    it under the terms of the GNU General Public License as published by\r
9 #    the Free Software Foundation, either version 3 of the License, or\r
10 #    (at your option) any later version.\r
11 #\r
12 #    This program is distributed in the hope that it will be useful,\r
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 #    GNU General Public License for more details.\r
16 #\r
17 #    You should have received a copy of the GNU General Public License\r
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
19 #\r
20 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>\r
21 #\r
22 ###############################################################################\r
23 \r
24 from nepi.execution.ec import ExperimentController \r
25 from nepi.execution.runner import ExperimentRunner\r
26 from nepi.util.netgraph import TopologyType\r
27 import nepi.data.processing.ccn.parser as ccn_parser\r
28 \r
29 import networkx\r
30 import socket\r
31 import os\r
32 import numpy\r
33 from scipy import stats\r
34 from matplotlib import pyplot\r
35 import math\r
36 import random\r
37 \r
38 from optparse import OptionParser\r
39 \r
40 usage = ("usage: %prog -s <pl-slice> -u <pl-user> -p <pl-password> "\r
41      "-k <pl-ssh-key> -N <nodes>")\r
42 \r
43 parser = OptionParser(usage = usage)\r
44 parser.add_option("-s", "--pl-slice", dest="pl_slice",\r
45         help="PlanetLab slicename", type="str")\r
46 parser.add_option("-u", "--pl-user", dest="pl_user",\r
47         help="PlanetLab web username", type="str")\r
48 parser.add_option("-p", "--pl-password", dest="pl_password",\r
49         help="PlanetLab web password", type="str")\r
50 parser.add_option("-k", "--pl-ssh-key", dest="pl_ssh_key",\r
51         help="Path to private SSH key associated with the PL account",\r
52         type="str")\r
53 parser.add_option("-N", "--nodes", dest="nodes",\r
54         help="Comma separated list of Planetlab nodes",\r
55         type="str")\r
56 \r
57 (options, args) = parser.parse_args()\r
58 \r
59 pl_slice = options.pl_slice\r
60 pl_ssh_key = options.pl_ssh_key\r
61 pl_user = options.pl_user\r
62 pl_password = options.pl_password\r
63 NODES = options.nodes.strip().split(",")\r
64 \r
65 def avg_interest_rtt(ec, run):\r
66     logs_dir = ec.run_dir\r
67     \r
68     # Parse downloaded CCND logs\r
69     (graph,\r
70       content_names,\r
71       interest_expiry_count,\r
72       interest_dupnonce_count,\r
73       interest_count,\r
74       content_count) = ccn_parser.process_content_history_logs(\r
75         logs_dir, ec.netgraph.topology)\r
76 \r
77     # statistics on RTT\r
78     rtts = [content_names[content_name]["rtt"] \\r
79             for content_name in content_names.keys()]\r
80 \r
81     # sample mean and standard deviation\r
82     sample = numpy.array(rtts)\r
83     n, min_max, mean, var, skew, kurt = stats.describe(sample)\r
84     std = math.sqrt(var)\r
85     ci = stats.t.interval(0.95, n-1, loc = mean, \r
86             scale = std/math.sqrt(n))\r
87 \r
88     global metrics\r
89     metrics.append((mean, ci[0], ci[1]))\r
90     \r
91     return mean\r
92 \r
93 def normal_law(ec, run, sample):\r
94     print "SAMPLE", sample\r
95 \r
96     x = numpy.array(sample)\r
97     n = len(sample)\r
98     std = x.std()\r
99     se = std / math.sqrt(n)\r
100     m = x.mean()\r
101     se95 = se * 2\r
102     \r
103     return m * 0.05 >= se95\r
104 \r
105 def post_process(ec, runs):\r
106     global metrics\r
107     \r
108     # plot convergence graph\r
109     y = numpy.array([float(m[0]) for m in metrics])\r
110     low = numpy.array([float(m[1]) for m in metrics])\r
111     high = numpy.array([float(m[2]) for m in metrics])\r
112     error = [y - low, high - y]\r
113     x = range(1,runs + 1)\r
114 \r
115     # plot average RTT and confidence interval for each iteration\r
116     pyplot.errorbar(x, y, yerr = error, fmt='o')\r
117     pyplot.plot(x, y, 'r-')\r
118     pyplot.xlim([0.5, runs + 0.5])\r
119     pyplot.xticks(numpy.arange(1, len(y)+1, 1))\r
120     pyplot.xlabel('Iteration')\r
121     pyplot.ylabel('Average RTT')\r
122     pyplot.grid()\r
123     pyplot.savefig("plot.png")\r
124     pyplot.show()\r
125 \r
126 content_name = "ccnx:/test/bunny.ts"\r
127 \r
128 repofile = os.path.join(\r
129         os.path.dirname(os.path.realpath(__file__)), \r
130         "repoFile1.0.8.2")\r
131 \r
132 def get_simulator(ec):\r
133     simulator = ec.filter_resources("LinuxNS3Simulation")\r
134 \r
135     if not simulator:\r
136         node = ec.register_resource("LinuxNode")\r
137         ec.set(node, "hostname", "localhost")\r
138 \r
139         simu = ec.register_resource("LinuxNS3Simulation")\r
140         ec.register_connection(simu, node)\r
141         return simu\r
142 \r
143     return simulator[0]\r
144 \r
145 def add_collector(ec, trace_name, subdir, newname = None):\r
146     collector = ec.register_resource("Collector")\r
147     ec.set(collector, "traceName", trace_name)\r
148     ec.set(collector, "subDir", subdir)\r
149     if newname:\r
150         ec.set(collector, "rename", newname)\r
151 \r
152     return collector\r
153 \r
154 def add_dce_host(ec, nid):\r
155     simu = get_simulator(ec)\r
156     \r
157     host = ec.register_resource("ns3::Node")\r
158     ec.set(host, "enableStack", True)\r
159     ec.register_connection(host, simu)\r
160 \r
161     # Annotate the graph\r
162     ec.netgraph.annotate_node(nid, "host", host)\r
163     \r
164 def add_dce_ccnd(ec, nid):\r
165     # Retrieve annotation from netgraph\r
166     host = ec.netgraph.node_annotation(nid, "host")\r
167     \r
168     # Add dce ccnd to the dce node\r
169     ccnd = ec.register_resource("ns3::LinuxDceCCND")\r
170     ec.set (ccnd, "stackSize", 1<<20)\r
171     ec.set (ccnd, "debug", 7)\r
172     ec.set (ccnd, "capacity", 50000)\r
173     ec.set (ccnd, "StartTime", "1s")\r
174     ec.set (ccnd, "StopTime", STOP_TIME)\r
175     ec.register_connection(ccnd, host)\r
176 \r
177     # Collector to retrieve ccnd log\r
178     collector = add_collector(ec, "stderr", str(nid), "log")\r
179     ec.register_connection(collector, ccnd)\r
180 \r
181     # Annotate the graph\r
182     ec.netgraph.annotate_node(nid, "ccnd", ccnd)\r
183 \r
184 def add_dce_ccnr(ec, nid):\r
185     # Retrieve annotation from netgraph\r
186     host = ec.netgraph.node_annotation(nid, "host")\r
187     \r
188     # Add a CCN content repository to the dce node\r
189     ccnr = ec.register_resource("ns3::LinuxDceCCNR")\r
190     ec.set (ccnr, "repoFile1", repofile) \r
191     ec.set (ccnr, "stackSize", 1<<20)\r
192     ec.set (ccnr, "StartTime", "2s")\r
193     ec.set (ccnr, "StopTime", STOP_TIME)\r
194     ec.register_connection(ccnr, host)\r
195 \r
196 def add_dce_ccncat(ec, nid):\r
197     # Retrieve annotation from netgraph\r
198     host = ec.netgraph.node_annotation(nid, "host")\r
199    \r
200     # Add a ccncat application to the dce host\r
201     ccncat = ec.register_resource("ns3::LinuxDceCCNCat")\r
202     ec.set (ccncat, "contentName", content_name)\r
203     ec.set (ccncat, "stackSize", 1<<20)\r
204     ec.set (ccncat, "StartTime", "8s")\r
205     ec.set (ccncat, "StopTime", STOP_TIME)\r
206     ec.register_connection(ccncat, host)\r
207 \r
208 def add_dce_fib_entry(ec, nid1, nid2):\r
209     # Retrieve annotations from netgraph\r
210     host1 = ec.netgraph.node_annotation(nid1, "host")\r
211     net = ec.netgraph.edge_net_annotation(nid1, nid2)\r
212     ip2 = net[nid2]\r
213 \r
214     # Add FIB entry between peer hosts\r
215     ccndc = ec.register_resource("ns3::LinuxDceFIBEntry")\r
216     ec.set (ccndc, "protocol", "udp") \r
217     ec.set (ccndc, "uri", "ccnx:/") \r
218     ec.set (ccndc, "host", ip2)\r
219     ec.set (ccndc, "stackSize", 1<<20)\r
220     ec.set (ccndc, "StartTime", "2s")\r
221     ec.set (ccndc, "StopTime", STOP_TIME)\r
222     ec.register_connection(ccndc, host1)\r
223 \r
224 def add_dce_net_iface(ec, nid1, nid2):\r
225     # Retrieve annotations from netgraph\r
226     host = ec.netgraph.node_annotation(nid1, "host")\r
227     net = ec.netgraph.edge_net_annotation(nid1, nid2)\r
228     ip1 = net[nid1]\r
229     prefix = net["prefix"]\r
230 \r
231     dev = ec.register_resource("ns3::PointToPointNetDevice")\r
232     ec.set(dev,"DataRate", "5Mbps")\r
233     ec.set(dev, "ip", ip1)\r
234     ec.set(dev, "prefix", prefix)\r
235     ec.register_connection(host, dev)\r
236 \r
237     queue = ec.register_resource("ns3::DropTailQueue")\r
238     ec.register_connection(dev, queue)\r
239 \r
240     return dev\r
241 \r
242 def add_pl_host(ec, nid):\r
243     hostname = NODES[nid]\r
244 \r
245     # Add a planetlab host to the experiment description\r
246     host = ec.register_resource("PlanetlabNode")\r
247     ec.set(host, "hostname", hostname)\r
248     ec.set(host, "username", pl_slice)\r
249     ec.set(host, "identity", pl_ssh_key)\r
250     ec.set(host, "cleanExperiment", True)\r
251     ec.set(host, "cleanProcesses", True)\r
252 \r
253     # Annotate the graph\r
254     ec.netgraph.annotate_node(nid, "hostname", hostname)\r
255     ec.netgraph.annotate_node(nid, "host", host)\r
256     \r
257     # Annotate the graph node with an ip address\r
258     ip = socket.gethostbyname(hostname)\r
259     ec.netgraph.annotate_node_ip(nid, ip)\r
260 \r
261 def add_pl_ccnd(ec, nid):\r
262     # Retrieve annotation from netgraph\r
263     host = ec.netgraph.node_annotation(nid, "host")\r
264     \r
265     # Add a CCN daemon to the planetlab node\r
266     ccnd = ec.register_resource("LinuxCCND")\r
267     ec.set(ccnd, "debug", 7)\r
268     ec.register_connection(ccnd, host)\r
269     \r
270     # Collector to retrieve ccnd log\r
271     collector = add_collector(ec, "stderr", str(nid), "log")\r
272     ec.register_connection(collector, ccnd)\r
273 \r
274     # Annotate the graph\r
275     ec.netgraph.annotate_node(nid, "ccnd", ccnd)\r
276 \r
277 def add_pl_ccnr(ec, nid):\r
278     # Retrieve annotation from netgraph\r
279     ccnd = ec.netgraph.node_annotation(nid, "ccnd")\r
280     \r
281     # Add a CCN content repository to the planetlab node\r
282     ccnr = ec.register_resource("LinuxCCNR")\r
283 \r
284     ec.set(ccnr, "repoFile1", repofile)\r
285     ec.register_connection(ccnr, ccnd)\r
286 \r
287 def add_pl_ccncat(ec, nid):\r
288     # Retrieve annotation from netgraph\r
289     ccnd = ec.netgraph.node_annotation(nid, "ccnd")\r
290     \r
291     # Add a CCN cat application to the planetlab node\r
292     ccncat = ec.register_resource("LinuxCCNCat")\r
293     ec.set(ccncat, "contentName", content_name)\r
294     ec.register_connection(ccncat, ccnd)\r
295 \r
296 def add_pl_fib_entry(ec, nid1, nid2):\r
297     # Retrieve annotations from netgraph\r
298     ccnd1 = ec.netgraph.node_annotation(nid1, "ccnd")\r
299     hostname2 = ec.netgraph.node_annotation(nid2, "hostname")\r
300     \r
301     # Add a FIB entry between one planetlab node and its peer\r
302     entry = ec.register_resource("LinuxFIBEntry")\r
303     ec.set(entry, "host", hostname2)\r
304     ec.register_connection(entry, ccnd1)\r
305 \r
306     # Collector to retrieve peering ping output (to measure neighbors delay)\r
307     ec.enable_trace(entry, "ping")\r
308     collector = add_collector(ec, "ping", str(nid1))\r
309     ec.register_connection(collector, entry)\r
310 \r
311     return entry\r
312 \r
313 def add_node(ec, nid):\r
314     ### Add CCN nodes (ec.netgraph holds the topology graph)\r
315     add_dce_host(ec, nid)\r
316     add_dce_ccnd(ec, nid)\r
317         \r
318     if nid == ec.netgraph.targets()[0]:\r
319         add_dce_ccnr(ec, nid)\r
320 \r
321     if nid == ec.netgraph.sources()[0]:\r
322         add_dce_ccncat(ec, nid)\r
323 \r
324 def add_edge(ec, nid1, nid2):\r
325     #### Add connections between CCN nodes\r
326     add_pl_fib_entry(ec, nid1, nid2)\r
327     add_pl_fib_entry(ec, nid2, nid1)\r
328 \r
329 def add_node(ec, nid):\r
330     ### Add CCN nodes (ec.netgraph holds the topology graph)\r
331     add_pl_host(ec, nid)\r
332     add_pl_ccnd(ec, nid)\r
333         \r
334     if nid == ec.netgraph.targets()[0]:\r
335         add_pl_ccnr(ec, nid)\r
336 \r
337     if nid == ec.netgraph.sources()[0]:\r
338         add_pl_ccncat(ec, nid)\r
339 \r
340 def wait_guids(ec):\r
341     return ec.filter_resources("LinuxCCNCat")\r
342 \r
343 if __name__ == '__main__':\r
344 \r
345     metrics = []\r
346 \r
347     # topology translation to NEPI model\r
348     ec = ExperimentController("pl_4n_linear",\r
349         topo_type = TopologyType.LINEAR, \r
350         node_count = 4,\r
351         assign_st = True,\r
352         assign_ips = True,\r
353         add_node_callback = add_node,\r
354         add_edge_callback = add_edge)\r
355 \r
356     #### Run experiment until metric convergence\r
357     rnr = ExperimentRunner()\r
358     runs = rnr.run(ec,\r
359             min_runs = 10,\r
360             max_runs = 100, \r
361             compute_metric_callback = avg_interest_rtt,\r
362             evaluate_convergence_callback = normal_law,\r
363             wait_guids = wait_guids(ec))\r
364    \r
365     ### post processing\r
366     post_process(ec, runs)\r
367 \r
368 \r