4 ## Experiment topology:
6 ## ccncatchunks ccnsendchunks
8 ## .-> node1 -- .. -- nodei -- .. -- nodeN <-.
11 ## - Nodes are connected through Intenet
12 ## - On each node runs a CCNx daemon
13 ## - Static entries are added to the CCNx FIB on each node to communicate them in series.
14 ## (Nodes only have FIB entries to at most two nodes)
17 from nepi.core.design import ExperimentDescription, FactoriesProvider
18 from nepi.core.execute import ExperimentController
19 from nepi.util.constants import ApplicationStatus as AS
20 from optparse import OptionParser, SUPPRESS_HELP
28 # Trak SIGTERM, and set global termination flag instead of dying
30 def _finalize(sig,frame):
32 TERMINATE.append(None)
33 signal.signal(signal.SIGTERM, _finalize)
34 signal.signal(signal.SIGINT, _finalize)
36 def create_slice_desc(slicename, plc_host, pl_user, pl_pwd, pl_ssh_key,
37 port_base, root_dir, proxy, exp_desc):
38 pl_provider = FactoriesProvider("planetlab")
39 slice_desc = exp_desc.add_testbed_description(pl_provider)
40 slice_desc.set_attribute_value("homeDirectory", root_dir)
41 slice_desc.set_attribute_value("slice", slicename)
42 slice_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
43 slice_desc.set_attribute_value("authUser", pl_user)
44 slice_desc.set_attribute_value("authPass", pl_pwd)
45 slice_desc.set_attribute_value("plcHost", plc_host)
47 slice_desc.set_attribute_value("proxy", proxy)
48 slice_desc.set_attribute_value("tapPortBase", port_base)
49 slice_desc.set_attribute_value("p2pDeployment", True)
50 # Kills all running processes before starting the experiment
51 slice_desc.set_attribute_value("cleanProc", True)
52 # NOTICE: Setting 'cleanHome' to 'True' will erase all previous
53 # folders in the sliver Home directory, including result files!
54 #slice_desc.set_attribute_value("cleanHome", True)
55 slice_desc.set_attribute_value("plLogLevel", "DEBUG")
58 def create_node(hostname, pl_inet, slice_desc):
59 pl_node = slice_desc.create("Node")
60 pl_node.set_attribute_value("hostname", hostname)
61 pl_node.set_attribute_value("label", hostname)
62 pl_iface = slice_desc.create("NodeInterface")
63 pl_iface.set_attribute_value("label", "iface_%s" % hostname)
64 pl_iface.connector("inet").connect(pl_inet.connector("devs"))
65 pl_node.connector("devs").connect(pl_iface.connector("node"))
68 def create_ccnd(pl_node, port, routes, slice_desc):
69 pl_app = slice_desc.create("CCNxDaemon")
71 # We can specify a default ccnx version to be either 0.6.0 or 0.7.1
72 # We can also specify a custom local source and build and install directives
73 path_to_source = os.path.join(os.path.dirname(os.path.abspath(__file__)),
74 "ccnx-0.6.0rc3.tar.gz")
75 pl_app.set_attribute_value("sources", path_to_source)
76 pl_app.set_attribute_value("build",
77 "tar xzf ${SOURCES}/ccnx-0.6.0rc3.tar.gz && "
78 "cd ./ccnx-0.6.0rc3 && "
79 "./configure && make ")
80 pl_app.set_attribute_value("install", "cp -r ./ccnx-0.6.0rc3/bin ${SOURCES}")
82 # We use a wildcard to replace the public IP address of the node during runtime,
83 # once this IP is known
84 routes = "|".join(map(lambda route: "udp {#[iface_%s].addr[0].[Address]#}" % route, routes))
86 # Add unicast ccn routes
87 pl_app.set_attribute_value("ccnRoutes", routes)
89 # Use a specific port to bind the CCNx daemon
91 pl_app.set_attribute_value("ccnLocalPort", port)
93 pl_app.enable_trace("stdout")
94 pl_app.enable_trace("stderr")
95 pl_app.connector("node").connect(pl_node.connector("apps"))
97 def create_ccnsendchunks(pl_node, port, slice_desc):
98 pl_app = slice_desc.create("Application")
99 path_to_video = os.path.join(os.path.dirname(os.path.abspath(__file__)),
100 "../big_buck_bunny_240p_mpeg4_lq.ts")
101 pl_app.set_attribute_value("stdin", path_to_video)
103 command = "ccnsendchunks ccnx:/VIDEO"
105 command = "CCN_LOCAL_PORT=%d %s " % (port, command)
106 pl_app.set_attribute_value("command", command)
108 pl_app.enable_trace("stdout")
109 pl_app.enable_trace("stderr")
110 pl_app.connector("node").connect(pl_node.connector("apps"))
113 def exec_ccncatchunks(slicename, port, hostname):
114 print "Getting video chunks from %s ..." % hostname
116 command = 'PATH=$PATH:$(ls | egrep nepi-ccnd- | head -1)/bin;'
118 command += "CCN_LOCAL_PORT=%d " % port
119 command += ' ccncatchunks2 ccnx:/VIDEO'
121 login = "%s@%s" % (slicename, hostname)
122 proc1 = subprocess.Popen(['ssh',
123 '-o', 'StrictHostKeyChecking=no',
126 stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell = False)
128 proc2 = subprocess.Popen(['vlc',
129 '--ffmpeg-threads=1',
130 '--sub-filter', 'marq',
132 '(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org',
134 '--no-video-title-show', '-'],
135 stdin=proc1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
138 def create_ed(hostnames, vsys_vnet, slicename, plc_host, pl_user, pl_pwd, pl_ssh_key,
139 port_base, root_dir, delay, port, proxy):
141 # Create the experiment description object
142 exp_desc = ExperimentDescription()
144 # Create the slice description object
145 slice_desc = create_slice_desc(slicename, plc_host, pl_user, pl_pwd, pl_ssh_key,
146 port_base, root_dir, proxy, exp_desc)
148 # Create the Internet box object
149 pl_inet = slice_desc.create("Internet")
151 # Create the Node boxes
155 for hostname in hostnames:
156 pl_node = create_node(hostname, pl_inet, slice_desc)
157 pl_nodes[hostname] = pl_node
159 ccn_routes[hostname] = list()
161 ccn_routes[hostname].append(prev_hostname)
162 ccn_routes[prev_hostname].append(hostname)
163 prev_hostname = hostname
165 for hostname in hostnames:
166 pl_node = pl_nodes[hostname]
167 routes = ccn_routes[hostname]
168 create_ccnd(pl_node, port, routes, slice_desc)
170 # Create a ccnsendchunks application box in the first node
171 hostname = hostnames[0]
172 pl_node = pl_nodes[hostname]
173 pl_app = create_ccnsendchunks(pl_node, port, slice_desc)
175 return exp_desc, pl_nodes, hostname, pl_app
177 def run(hostnames, vsys_vnet, slicename, plc_host, pl_user, pl_pwd, pl_ssh_key,
178 port_base, root_dir, delay, port, proxy):
180 exp_desc, pl_nodes, hostname, pl_app = create_ed(hostnames, vsys_vnet,
181 slicename, plc_host, pl_user, pl_pwd, pl_ssh_key, port_base,
182 root_dir, delay, port, proxy)
184 xml = exp_desc.to_xml()
185 controller = ExperimentController(xml, root_dir)
188 while not TERMINATE and controller.status(pl_app.guid) == AS.STATUS_NOT_STARTED:
193 hostname = hostnames[-1]
194 proc1 = exec_ccncatchunks(slicename, port, hostname)
196 if not TERMINATE and proc1:
201 hostname = hostnames[-2]
202 proc2 = exec_ccncatchunks(slicename, port, hostname)
204 while not TERMINATE and proc1 and proc2 and proc2.poll() is None:
209 err = proc1.stderr.read()
210 print "Stream 1 ERROR ", err
212 out = proc1.stdout.read()
213 print "Stream 1 OUTPUT ", out
217 err = proc2.stderr.read()
218 print "Stream 2 ERROR ", err
220 out = proc2.stdout.read()
221 print "Stream 2 OUTPUT ", out
224 controller.shutdown()
226 if __name__ == '__main__':
227 root_dir = tempfile.mkdtemp()
228 slicename = os.environ.get("PL_SLICE")
229 pl_host = os.environ.get("PL_HOST", "www.planet-lab.eu")
230 port_base = 2000 + (os.getpid() % 1000) * 13
231 pl_ssh_key = os.environ.get(
233 "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
234 pl_user = os.environ.get('PL_USER')
235 pl_pwd = os.environ.get('PL_PASS')
236 pl_vsys_vnet = os.environ.get('PL_VSYS_NET')
237 pl_hostnames = os.environ.get('PL_HOSTNAMES')
238 default_hostnames = ['openlab02.pl.sophia.inria.fr',
240 'planetlab2.di.unito.it',
241 'merkur.planetlab.haw-hamburg.de',
242 'planetlab1.cs.uit.no',
243 'planetlab3.cs.st-andrews.ac.uk',
244 'planetlab2.cs.uoi.gr',
245 'planetlab3.xeno.cl.cam.ac.uk',
246 'planet2.inf.tu-dresden.de',
247 'planetlab2.csg.uzh.ch',
249 'planetlab-um00.di.uminho.pt',
250 'planetlabpc2.upf.edu',
252 'planetlab2.esprit-tn.com' ]
254 ccn_local_port = os.environ.get('CCN_LOCAL_PORT')
256 usage = "usage: %prog -s <pl_slice> -H <pl_host> -k <ssh_key> -u <pl_user> -p <pl_password> -v <vsys_vnet> -N <host_names> -c <node_count> -d <delay> -P <ccn-local-port> -x <proxy>"
258 parser = OptionParser(usage=usage)
259 parser.add_option("-s", "--slicename", dest="slicename",
260 help="PlanetLab slicename", default=slicename, type="str")
261 parser.add_option("-H", "--pl-host", dest="pl_host",
262 help="PlanetLab site (e.g. www.planet-lab.eu)",
263 default=pl_host, type="str")
264 parser.add_option("-k", "--ssh-key", dest="pl_ssh_key",
265 help="Path to private ssh key used for PlanetLab authentication",
266 default=pl_ssh_key, type="str")
267 parser.add_option("-u", "--pl-user", dest="pl_user",
268 help="PlanetLab account user (i.e. Registration email address)",
269 default=pl_user, type="str")
270 parser.add_option("-p", "--pl-pwd", dest="pl_pwd",
271 help="PlanetLab account password", default=pl_pwd, type="str")
272 parser.add_option("-v", "--vsys-vnet", dest="vsys_vnet",
273 help="Value of the vsys_vnet tag addigned to your slice. (e.g. 192.168.3.0/16)",
274 default=pl_vsys_vnet, type="str")
275 parser.add_option("-N", "--host-names", dest="hostnames",
276 help="Comma separated list of PlanetLab hostnames to use",
277 default=pl_hostnames, type="str")
278 parser.add_option("-c", "--node-count", dest="node_count",
279 help="Number of nodes to use",
280 default=9, type="int")
281 parser.add_option("-d", "--delay", dest="delay",
282 help="Time to wait before retrieveing the second video stream in seconds",
283 default=40, type="int")
284 parser.add_option("-P", "--ccn-local-port", dest="port",
285 help="Port to bind the CCNx daemon",
286 default=ccn_local_port, type="int")
287 parser.add_option("-x", "--proxy", dest="proxy",
288 help="Https proxy between here and PlanetLab machines",
289 default=None, type="str")
290 (options, args) = parser.parse_args()
292 hostnames = map(string.strip, options.hostnames.split(",")) if options.hostnames else default_hostnames
293 if options.node_count > 0 and options.node_count < len(hostnames):
294 hostnames = hostnames[0:options.node_count]
296 vsys_vnet = options.vsys_vnet
297 slicename = options.slicename
298 pl_host = options.pl_host
299 pl_user= options.pl_user
300 pl_pwd = options.pl_pwd
301 pl_ssh_key = options.pl_ssh_key
302 delay = options.delay
304 proxy = options.proxy
306 run(hostnames, vsys_vnet, slicename, pl_host, pl_user, pl_pwd, pl_ssh_key,
307 port_base, root_dir, delay, port, proxy)