e6869bb5ad25c16f61a3c6aba15d903326cbc3d1
[nepi.git] / src / nepi / testbeds / planetlab / multicast.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from constants import TESTBED_ID
5
6 import os
7 import os.path
8 import sys
9 import functools
10
11 import nepi.util.server as server
12 import nepi.util.ipaddr2 as ipaddr2
13
14 import logging
15
16 import application
17
18 class MulticastForwarder(application.Application):
19     """
20     This application installs a userspace packet forwarder
21     that, when connected to a node, filters all packets
22     flowing through multicast-capable virtual interfaces
23     and applies custom-specified routing policies
24     """
25     def __init__(self, *p, **kw):
26         super(MulticastForwarder, self).__init__(*p, **kw)
27         
28         self.sources = ' '.join([
29             os.path.join( os.path.dirname(__file__),
30                 "scripts", "mcastfwd.py" ),
31             ipaddr2.__file__.replace('.pyc','.py').replace('.pyo','.py'),
32         ])
33         
34         self.sudo = True
35         
36         self.depends = "python"
37         
38         # Initialized when connected
39         self.ifaces = []
40         self.router = None
41     
42     def _command_get(self):
43         cmd = "python mcastfwd.py "
44         if not self.router:
45             cmd += "-R "
46         cmd += ' '.join([iface.address for iface in self.ifaces])
47         return cmd
48     def _command_set(self, value):
49         # ignore
50         return
51     command = property(_command_get, _command_set)
52     
53         
54 class MulticastAnnouncer(application.Application):
55     """
56     This application installs a userspace daemon that
57     monitors multicast membership and announces it on all
58     multicast-capable interfaces.
59     This does not usually happen automatically on PlanetLab slivers.
60     """
61     def __init__(self, *p, **kw):
62         super(MulticastAnnouncer, self).__init__(*p, **kw)
63         
64         self.sources = ' '.join([
65             os.path.join( os.path.dirname(__file__),
66                 "scripts", "mcastfwd.py" ),
67             ipaddr2.__file__.replace('.pyc','.py').replace('.pyo','.py'),
68         ])
69         
70         self.sudo = True
71         
72         self.depends = "python"
73         
74         self.ifaces = []
75         self.router = None
76     
77     def _command_get(self):
78         return (
79             "python mcastfwd.py -A %s"
80         ) % ( ' '.join([iface.address for iface in self.ifaces]), )
81     def _command_set(self, value):
82         # ignore
83         return
84     command = property(_command_get, _command_set)
85
86 class MulticastRouter(application.Application):
87     """
88     This application installs a userspace daemon that
89     monitors multicast membership and announces it on all
90     multicast-capable interfaces.
91     This does not usually happen automatically on PlanetLab slivers.
92     """
93     ALGORITHM_MAP = {
94         'dvmrp' : {
95             'sources' :
96                 ' '.join([
97                     os.path.join( os.path.dirname(__file__),
98                         "scripts", "mrouted-3.9.5-pl.patch" ),
99                 ]) ,
100             'depends' : "",
101             'buildDepends' : "byacc gcc make patch",
102             'build' : 
103                 "mkdir -p mrouted && "
104                 "echo '3a1c1e72c4f6f7334d72df4c50b510d7  mrouted-3.9.5.tar.bz2' > archive_sums.txt && "
105                 "wget -q -c -O mrouted-3.9.5.tar.bz2 ftp://ftp.vmlinux.org/pub/People/jocke/mrouted/mrouted-3.9.5.tar.bz2 && "
106                 "md5sum -c archive_sums.txt && "
107                 "tar xvjf mrouted-3.9.5.tar.bz2 -C mrouted --strip-components=1 && "
108                 "cd mrouted && patch -p1 < ${SOURCES}/mrouted-3.9.5-pl.patch && make"
109                 ,
110             'install' : "cp mrouted/mrouted ${SOURCES}",
111             'command' : 
112                 "while test \\! -e /var/run/mcastrt ; do sleep 1 ; done ; "
113                 "echo 'phyint eth0 disable' > ./mrouted.conf ; "
114                 "for iface in %(nonifaces)s ; do echo \"phyint $iface disable\" >> ./mrouted.conf ; done ; "
115                 "./mrouted -f %(debugbit)s -c ./mrouted.conf"
116                 ,
117             'debugbit' : "-dpacket,igmp,routing,interface,pruning,membership,cache",
118         }
119     }
120     
121     def __init__(self, *p, **kw):
122         super(MulticastRouter, self).__init__(*p, **kw)
123         
124         self.algorithm = 'dvmrp'
125         self.sudo = True
126         self.nonifaces = []
127     
128     def _non_set(self, value):
129         # ignore
130         return
131     
132     def _gen_get(attribute, self):
133         return self.ALGORITHM_MAP[self.algorithm][attribute]
134     
135     def _command_get(self):
136         command = self.ALGORITHM_MAP[self.algorithm]['command']
137         debugbit = self.ALGORITHM_MAP[self.algorithm]['debugbit']
138         
139         # download rpms and pack into a tar archive
140         return command % {
141             'nonifaces' : ' '.join([iface.if_name for iface in self.nonifaces if iface.if_name]),
142             'debugbit' : (debugbit if self.stderr else ""),
143         }
144     command = property(_command_get, _non_set)
145
146     build = property(functools.partial(_gen_get, "build"), _non_set)
147     install = property(functools.partial(_gen_get, "install"), _non_set)
148     sources = property(functools.partial(_gen_get, "sources"), _non_set)
149     depends = property(functools.partial(_gen_get, "depends"), _non_set)
150     buildDepends = property(functools.partial(_gen_get, "buildDepends"), _non_set)
151