1 # -*- python-indent: 4 -*-
4 Description: IPv6 Support and Management to Slices
5 ipv6 nodemanager plugin
7 Author: Guilherme Sperb Machado <gsm@machados.org>
18 from sliver_libvirt import Sliver_Libvirt
19 from xml.dom.minidom import parseString
23 radvdConfFile = '/etc/radvd.conf'
26 logger.log("ipv6: plugin starting up...")
28 def buildLibvirtDefaultNetConfig(dom):
30 # create the <network> element
31 networkElem = dom.createElement("network")
32 # create <name> element
33 nameElem = dom.createElement("name")
34 textName = dom.createTextNode("default")
35 nameElem.appendChild(textName)
36 # create <uuid> element
37 uuidElem = dom.createElement("uuid")
38 textUUID = dom.createTextNode(str(uuid.uuid1()))
39 uuidElem.appendChild(textUUID)
40 # create <forward> element
41 forwardElem = dom.createElement("forward")
42 forwardElem.setAttribute("mode", "nat")
43 # create <nat> element
44 natElem = dom.createElement("nat")
45 # create <port> element
46 portElem = dom.createElement("port")
47 portElem.setAttribute("end", "65535")
48 portElem.setAttribute("start", "1024")
49 # create the ipv4 <ip> element
50 ipElem0 = dom.createElement("ip")
51 ipElem0.setAttribute("address", "192.168.122.1")
52 ipElem0.setAttribute("netmask", "255.255.255.0")
53 # create the <dhcp> element
54 dhcpElem = dom.createElement("dhcp")
55 # create the <range> element
56 rangeElem = dom.createElement("range")
57 rangeElem.setAttribute("end", "192.168.122.254")
58 rangeElem.setAttribute("start", "192.168.122.2")
59 # create the <bridge> element
60 bridgeElem = dom.createElement("bridge")
61 bridgeElem.setAttribute("delay", "0")
62 bridgeElem.setAttribute("name", "virbr0")
63 bridgeElem.setAttribute("stp", "on")
65 # build the whole thing
66 natElem.appendChild(portElem)
67 forwardElem.appendChild(natElem)
69 dhcpElem.appendChild(rangeElem)
70 ipElem0.appendChild(dhcpElem)
71 networkElem.appendChild(nameElem)
72 networkElem.appendChild(uuidElem)
73 networkElem.appendChild(forwardElem)
74 networkElem.appendChild(bridgeElem)
75 networkElem.appendChild(ipElem0)
78 def checkForIPv6(defaultNetworkConfig):
79 netnodes = defaultNetworkConfig.getElementsByTagName('network')
81 for netnode in netnodes:
82 ips = netnode.getElementsByTagName('ip')
84 if ip.getAttribute('family')=='ipv6':
85 logger.log("ipv6: IPv6 address/prefix already set for slivers! %s/%s" % \
86 (ip.getAttribute('address'), ip.getAttribute('prefix')) )
91 def addIPv6(defaultNetworkConfig, ipv6addr, prefix):
93 netnodes = defaultNetworkConfig.getElementsByTagName('network')
94 for netnode in netnodes:
95 # create the ipv6 <ip> element 1
96 ipElem1 = defaultNetworkConfig.createElement("ip")
97 ipElem1.setAttribute("family", "ipv6")
98 ipElem1.setAttribute("address", ipv6addr)
99 ipElem1.setAttribute("prefix", prefix)
100 # create the ipv6 <ip> element 2
101 # it's ugly, I know, but we need a link-local address on the interface!
102 ipElem2 = defaultNetworkConfig.createElement("ip")
103 ipElem2.setAttribute("family", "ipv6")
104 ipElem2.setAttribute("address", "fe80:1234::1")
105 ipElem2.setAttribute("prefix", "64")
106 # adding to the 'defaultNetworkConfig'
107 netnode.appendChild(ipElem1)
108 netnode.appendChild(ipElem2)
109 return defaultNetworkConfig
111 def changeIPv6(dom, ipv6addr, prefix):
112 ips = dom.getElementsByTagName('ip')
114 if ip.getAttribute("family")=='ipv6' and not(re.match(r'fe80(.*)', ip.getAttribute("address"), re.I)):
115 ip.setAttribute("address", ipv6addr)
116 ip.setAttribute("prefix", prefix)
121 networks = dom.getElementsByTagName('network')
122 for network in networks:
123 ips = network.getElementsByTagName('ip')
125 if ip.getAttribute("family")=='ipv6':
126 network.removeChild(ip)
130 def checkIfIPv6IsDifferent(dom, ipv6addr, prefix):
131 netnodes = dom.getElementsByTagName('network')
132 for netnode in netnodes:
133 ips = netnode.getElementsByTagName('ip')
135 if ip.getAttribute('family')=='ipv6' and \
136 not ( re.match(r'fe80(.*)', ip.getAttribute("address"), re.I) ) and \
137 (ip.getAttribute('address')!=ipv6addr or ip.getAttribute('prefix')!=prefix) :
138 logger.log("ipv6: the IPv6 address or prefix are different. Change detected!")
143 def setAutostart(network):
145 network.setAutostart(1)
147 logger.log("ipv6: network could not set to autostart")
150 def setUp(networkLibvirt, connLibvirt, networkElem, ipv6addr, prefix):
151 newXml = networkElem.toxml()
152 #logger.log(networkElem.toxml())
155 # logger.log(repr(method))
156 networkLibvirt.undefine()
157 networkLibvirt.destroy()
158 connLibvirt.networkCreateXML(newXml)
159 networkDefault = connLibvirt.networkDefineXML(newXml)
160 setAutostart(networkDefault)
161 commandForwarding = ['sysctl', '-w', 'net.ipv6.conf.all.forwarding=1']
162 logger.log_call(commandForwarding, timeout=15*60)
167 MinRtrAdvInterval 30;
168 MaxRtrAdvInterval 100;
169 prefix %(ipv6addr)s/%(prefix)s
178 with open(radvdConfFile,'w') as f:
182 logger.log("ipv6: set up process finalized. Enabled IPv6 address to the slivers!")
184 def cleanUp(networkLibvirt, connLibvirt, networkElem):
185 dom = removeIPv6(networkElem)
187 networkLibvirt.undefine()
188 networkLibvirt.destroy()
189 # TODO: set autostart for the network
190 connLibvirt.networkCreateXML(newXml)
191 networkDefault = connLibvirt.networkDefineXML(newXml)
192 setAutostart(networkDefault)
194 logger.log("ipv6: cleanup process finalized. The IPv6 support on the slivers was removed.")
197 commandKillRadvd = ['killall', 'radvd']
198 logger.log_call(commandKillRadvd, timeout=15*60)
201 commandRadvd = ['radvd']
202 logger.log_call(commandRadvd, timeout=15*60)
204 def GetSlivers(data, config, plc):
208 interfaces = data['interfaces']
209 logger.log(repr(interfaces))
210 for interface in interfaces:
211 logger.log('ipv6: get interface 1: %r'%(interface))
212 if 'interface_tag_ids' in interface:
213 interface_tag_ids = "interface_tag_ids"
214 interface_tag_id = "interface_tag_id"
215 settings = plc.GetInterfaceTags({interface_tag_id:interface[interface_tag_ids]})
216 isSliversIPv6PrefixSet = False
217 for setting in settings:
218 #logger.log(repr(setting))
219 # TODO: create a static variable to describe the "sliversipv6prefix" tag
220 if setting['tagname']=='sliversipv6prefix':
221 ipv6addrprefix = setting['value'].split('/', 1)
222 ipv6addr = ipv6addrprefix[0]
223 prefix = ipv6addrprefix[1]
224 logger.log("ipv6: %s" % (ipv6addr) )
225 validIPv6 = tools.isValidIPv6(ipv6addr)
227 logger.log("ipv6: the 'sliversipv6prefix' tag presented a non-valid IPv6 address!")
229 # connecting to the libvirtd
230 connLibvirt = Sliver_Libvirt.getConnection(type)
231 list = connLibvirt.listAllNetworks()
232 for networkLibvirt in list:
233 xmldesc = networkLibvirt.XMLDesc()
234 dom = parseString(xmldesc)
235 hasIPv6 = checkForIPv6(dom)
237 # let's first check if the IPv6 is different or is it the same...
238 isDifferent = checkIfIPv6IsDifferent(dom, ipv6addr, prefix)
240 logger.log("ipv6: tag 'sliversipv6prefix' was modified! " +
241 "Updating configuration with the new one...")
242 networkElem = changeIPv6(dom, ipv6addr, prefix)
243 setUp(networkLibvirt, connLibvirt, networkElem, ipv6addr, prefix)
244 logger.log("ipv6: trying to reboot the slivers...")
245 tools.reboot_sliver('blah')
247 logger.log("ipv6: starting to redefine the virtual network...")
248 #networkElem = buildLibvirtDefaultNetConfig(dom,ipv6addr,prefix)
249 networkElem = addIPv6(dom, ipv6addr, prefix)
250 setUp(networkLibvirt, connLibvirt, networkElem, ipv6addr, prefix)
251 logger.log("ipv6: trying to reboot the slivers...")
252 tools.reboot_sliver('blah')
253 isSliversIPv6PrefixSet = True
254 if not(isSliversIPv6PrefixSet):
255 # connecting to the libvirtd
256 connLibvirt = Sliver_Libvirt.getConnection(type)
257 list = connLibvirt.listAllNetworks()
258 for networkLibvirt in list:
259 xmldesc = networkLibvirt.XMLDesc()
260 dom = parseString(xmldesc)
261 if checkForIPv6(dom):
262 cleanUp(networkLibvirt, connLibvirt, dom)
263 logger.log("ipv6: trying to reboot the slivers...")
264 tools.reboot_sliver('blah')
266 logger.log("ipv6: all done!")