dos2unix'ed
[nepi.git] / examples / ccn_emu_live / dce_4_nodes_linear.py
1 #!/usr/bin/env python
2 #
3 #    NEPI, a framework to manage network experiments
4 #    Copyright (C) 2013 INRIA
5 #
6 #    This program is free software: you can redistribute it and/or modify
7 #    it under the terms of the GNU General Public License version 2 as
8 #    published by the Free Software Foundation;
9 #
10 #    This program is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #    GNU General Public License for more details.
14 #
15 #    You should have received a copy of the GNU General Public License
16 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
20
21 from nepi.execution.ec import ExperimentController 
22 from nepi.execution.runner import ExperimentRunner
23 from nepi.util.netgraph import TopologyType
24 import nepi.data.processing.ccn.parser as ccn_parser
25
26 import networkx
27 import socket
28 import os
29 import numpy
30 from scipy import stats
31 from matplotlib import pyplot
32 import math
33 import random
34
35 def avg_interest_rtt(ec, run):
36     logs_dir = ec.run_dir
37     
38     # Parse downloaded CCND logs
39     (graph,
40       content_names,
41       interest_expiry_count,
42       interest_dupnonce_count,
43       interest_count,
44       content_count) = ccn_parser.process_content_history_logs(
45         logs_dir, ec.netgraph.topology)
46
47     # statistics on RTT
48     rtts = [content_names[content_name]["rtt"] \
49             for content_name in content_names]
50
51     # sample mean and standard deviation
52     sample = numpy.array(rtts)
53     n, min_max, mean, var, skew, kurt = stats.describe(sample)
54     std = math.sqrt(var)
55     ci = stats.t.interval(0.95, n-1, loc = mean, 
56             scale = std/math.sqrt(n))
57
58     global metrics
59     metrics.append((mean, ci[0], ci[1]))
60     
61     return mean
62
63 def normal_law(ec, run, sample):
64     x = numpy.array(sample)
65     n = len(sample)
66     std = x.std()
67     se = std / math.sqrt(n)
68     m = x.mean()
69     se95 = se * 2
70     
71     return m * 0.05 >= se95
72
73 def post_process(ec, runs):
74     global metrics
75     
76     # plot convergence graph
77     y = numpy.array([float(m[0]) for m in metrics])
78     low = numpy.array([float(m[1]) for m in metrics])
79     high = numpy.array([float(m[2]) for m in metrics])
80     error = [y - low, high - y]
81     x = range(1,runs + 1)
82
83     # plot average RTT and confidence interval for each iteration
84     pyplot.errorbar(x, y, yerr = error, fmt='o')
85     pyplot.plot(x, y, 'r-')
86     pyplot.xlim([0.5, runs + 0.5])
87     pyplot.xticks(numpy.arange(1, len(y)+1, 1))
88     pyplot.xlabel('Iteration')
89     pyplot.ylabel('Average RTT')
90     pyplot.grid()
91     pyplot.savefig("plot.png")
92     pyplot.show()
93
94 content_name = "ccnx:/test/bunny.ts"
95
96 STOP_TIME = "5000s"
97
98 repofile = os.path.join(
99         os.path.dirname(os.path.realpath(__file__)), 
100         "repoFile1.0.8.2")
101
102 def get_simulator(ec):
103     simulator = ec.filter_resources("linux::ns3::Simulation")
104
105     if not simulator:
106         node = ec.register_resource("linux::Node")
107         ec.set(node, "hostname", "localhost")
108
109         simu = ec.register_resource("linux::ns3::Simulation")
110         ec.register_connection(simu, node)
111         return simu
112
113     return simulator[0]
114
115 def add_collector(ec, trace_name, subdir, newname = None):
116     collector = ec.register_resource("Collector")
117     ec.set(collector, "traceName", trace_name)
118     ec.set(collector, "subDir", subdir)
119     if newname:
120         ec.set(collector, "rename", newname)
121
122     return collector
123
124 def add_dce_host(ec, nid):
125     simu = get_simulator(ec)
126     
127     host = ec.register_resource("ns3::Node")
128     ec.set(host, "enableStack", True)
129     ec.register_connection(host, simu)
130
131     # Annotate the graph
132     ec.netgraph.annotate_node(nid, "host", host)
133     
134 def add_dce_ccnd(ec, nid):
135     # Retrieve annotation from netgraph
136     host = ec.netgraph.node_annotation(nid, "host")
137     
138     # Add dce ccnd to the dce node
139     ccnd = ec.register_resource("linux::ns3::dce::CCND")
140     ec.set (ccnd, "stackSize", 1<<20)
141     ec.set (ccnd, "debug", 7)
142     ec.set (ccnd, "capacity", 50000)
143     ec.set (ccnd, "StartTime", "1s")
144     ec.set (ccnd, "StopTime", STOP_TIME)
145     ec.register_connection(ccnd, host)
146
147     # Collector to retrieve ccnd log
148     collector = add_collector(ec, "stderr", str(nid), "log")
149     ec.register_connection(collector, ccnd)
150
151     # Annotate the graph
152     ec.netgraph.annotate_node(nid, "ccnd", ccnd)
153
154 def add_dce_ccnr(ec, nid):
155     # Retrieve annotation from netgraph
156     host = ec.netgraph.node_annotation(nid, "host")
157     
158     # Add a CCN content repository to the dce node
159     ccnr = ec.register_resource("linux::ns3::dce::CCNR")
160     ec.set (ccnr, "repoFile1", repofile) 
161     ec.set (ccnr, "stackSize", 1<<20)
162     ec.set (ccnr, "StartTime", "2s")
163     ec.set (ccnr, "StopTime", STOP_TIME)
164     ec.register_connection(ccnr, host)
165
166 def add_dce_ccncat(ec, nid):
167     # Retrieve annotation from netgraph
168     host = ec.netgraph.node_annotation(nid, "host")
169    
170     # Add a ccncat application to the dce host
171     ccncat = ec.register_resource("linux::ns3::dce::CCNCat")
172     ec.set (ccncat, "contentName", content_name)
173     ec.set (ccncat, "stackSize", 1<<20)
174     ec.set (ccncat, "StartTime", "8s")
175     ec.set (ccncat, "StopTime", STOP_TIME)
176     ec.register_connection(ccncat, host)
177
178 def add_dce_fib_entry(ec, nid1, nid2):
179     # Retrieve annotations from netgraph
180     host1 = ec.netgraph.node_annotation(nid1, "host")
181     net = ec.netgraph.edge_net_annotation(nid1, nid2)
182     ip2 = net[nid2]
183
184     # Add FIB entry between peer hosts
185     ccndc = ec.register_resource("linux::ns3::dce::FIBEntry")
186     ec.set (ccndc, "protocol", "udp") 
187     ec.set (ccndc, "uri", "ccnx:/") 
188     ec.set (ccndc, "host", ip2)
189     ec.set (ccndc, "stackSize", 1<<20)
190     ec.set (ccndc, "StartTime", "2s")
191     ec.set (ccndc, "StopTime", STOP_TIME)
192     ec.register_connection(ccndc, host1)
193
194 def add_dce_net_iface(ec, nid1, nid2):
195     # Retrieve annotations from netgraph
196     host = ec.netgraph.node_annotation(nid1, "host")
197     net = ec.netgraph.edge_net_annotation(nid1, nid2)
198     ip1 = net[nid1]
199     prefix = net["prefix"]
200
201     dev = ec.register_resource("ns3::PointToPointNetDevice")
202     ec.set(dev,"DataRate", "5Mbps")
203     ec.set(dev, "ip", ip1)
204     ec.set(dev, "prefix", prefix)
205     ec.register_connection(host, dev)
206
207     queue = ec.register_resource("ns3::DropTailQueue")
208     ec.register_connection(dev, queue)
209
210     return dev
211
212 def add_edge(ec, nid1, nid2):
213     ### Add network interfaces to hosts
214     p2p1 = add_dce_net_iface(ec, nid1, nid2)
215     p2p2 = add_dce_net_iface(ec, nid2, nid1)
216
217     # Create point to point link between interfaces
218     chan = ec.register_resource("ns3::PointToPointChannel")
219     ec.set(chan, "Delay", "0ms")
220
221     ec.register_connection(chan, p2p1)
222     ec.register_connection(chan, p2p2)
223
224     #### Add routing between CCN nodes
225     add_dce_fib_entry(ec, nid1, nid2)
226     add_dce_fib_entry(ec, nid2, nid1)
227
228 def add_node(ec, nid):
229     ### Add CCN nodes (ec.netgraph holds the topology graph)
230     add_dce_host(ec, nid)
231     add_dce_ccnd(ec, nid)
232         
233     if nid == ec.netgraph.targets()[0]:
234         add_dce_ccnr(ec, nid)
235
236     if nid == ec.netgraph.sources()[0]:
237         add_dce_ccncat(ec, nid)
238
239 def wait_guids(ec):
240     return ec.filter_resources("linux::ns3::dce::CCNCat")
241
242 if __name__ == '__main__':
243
244     metrics = []
245
246     # topology translation to NEPI model
247     ec = ExperimentController("dce_4n_linear",
248         topo_type = TopologyType.LINEAR, 
249         node_count = 4,
250         assign_st = True,
251         assign_ips = True,
252         add_node_callback = add_node,
253         add_edge_callback = add_edge)
254
255     #### Run experiment until metric convergence
256     rnr = ExperimentRunner()
257     runs = rnr.run(ec,
258             min_runs = 10,
259             max_runs = 100, 
260             compute_metric_callback = avg_interest_rtt,
261             evaluate_convergence_callback = normal_law,
262             wait_guids = wait_guids(ec))
263    
264     ### post processing
265     post_process(ec, runs)
266
267