1 # -*- python-indent: 4 -*-
4 Description: IPv6 Support and Management to Slices
5 ipv6 nodemanager plugin
7 Author: Guilherme Sperb Machado <gsm@machados.org>
10 * The 'sliversipv6prefix' tag must have this format:
11 ipv6_address/prefix -- e.g., 2002:1000::1/64
12 * The prefix specified on 'sliversipv6prefix' tag must be at least 64
13 It should vary between 1 and 64, since it is the minimum amount of bits to
14 have native IPv6 auto-configuration.
15 * The ipv6_address in 'sliversipv6prefix' tag value can be any valid IPv6 address.
16 E.g., 2002:1000:: or 2002:1000::1
17 * It is the node manager/admin responsibility to properly set the IPv6 routing,
18 since slivers should receive/send any kind of traffic.
28 from xml.dom.minidom import parseString
30 # TODO: is there anything better to do if the "libvirt", "sliver_libvirt",
31 # and are not in place in the VS distro?
34 from sliver_libvirt import Sliver_Libvirt
36 logger.log("Could not import 'sliver_lxc' or 'libvirt'.")
40 radvd_conf_file = '/etc/radvd.conf'
41 sliversipv6prefixtag = 'sliversipv6prefix'
44 logger.log("ipv6: plugin starting up...")
46 def build_libvirt_default_net_config(dom):
48 # create the <network> element
49 networkElem = dom.createElement("network")
50 # create <name> element
51 nameElem = dom.createElement("name")
52 textName = dom.createTextNode("default")
53 nameElem.appendChild(textName)
54 # create <uuid> element
55 uuidElem = dom.createElement("uuid")
56 textUUID = dom.createTextNode(str(uuid.uuid1()))
57 uuidElem.appendChild(textUUID)
58 # create <forward> element
59 forwardElem = dom.createElement("forward")
60 forwardElem.setAttribute("mode", "nat")
61 # create <nat> element
62 natElem = dom.createElement("nat")
63 # create <port> element
64 portElem = dom.createElement("port")
65 portElem.setAttribute("end", "65535")
66 portElem.setAttribute("start", "1024")
67 # create the ipv4 <ip> element
68 ipElem0 = dom.createElement("ip")
69 ipElem0.setAttribute("address", "192.168.122.1")
70 ipElem0.setAttribute("netmask", "255.255.255.0")
71 # create the <dhcp> element
72 dhcpElem = dom.createElement("dhcp")
73 # create the <range> element
74 rangeElem = dom.createElement("range")
75 rangeElem.setAttribute("end", "192.168.122.254")
76 rangeElem.setAttribute("start", "192.168.122.2")
77 # create the <bridge> element
78 bridgeElem = dom.createElement("bridge")
79 bridgeElem.setAttribute("delay", "0")
80 bridgeElem.setAttribute("name", "virbr0")
81 bridgeElem.setAttribute("stp", "on")
83 # build the whole thing
84 natElem.appendChild(portElem)
85 forwardElem.appendChild(natElem)
87 dhcpElem.appendChild(rangeElem)
88 ipElem0.appendChild(dhcpElem)
89 networkElem.appendChild(nameElem)
90 networkElem.appendChild(uuidElem)
91 networkElem.appendChild(forwardElem)
92 networkElem.appendChild(bridgeElem)
93 networkElem.appendChild(ipElem0)
96 def check_for_ipv6(defaultNetworkConfig):
97 netnodes = defaultNetworkConfig.getElementsByTagName('network')
99 for netnode in netnodes:
100 ips = netnode.getElementsByTagName('ip')
102 if ip.getAttribute('family')=='ipv6':
103 logger.log("ipv6: IPv6 address/prefix already set for slivers! %s/%s" % \
104 (ip.getAttribute('address'), ip.getAttribute('prefix')) )
109 def add_ipv6(defaultNetworkConfig, ipv6addr, prefix):
111 netnodes = defaultNetworkConfig.getElementsByTagName('network')
112 for netnode in netnodes:
113 # create the ipv6 <ip> element 1
114 ipElem1 = defaultNetworkConfig.createElement("ip")
115 ipElem1.setAttribute("family", "ipv6")
116 ipElem1.setAttribute("address", ipv6addr)
117 ipElem1.setAttribute("prefix", prefix)
118 # create the ipv6 <ip> element 2
119 # it's ugly, I know, but we need a link-local address on the interface!
120 ipElem2 = defaultNetworkConfig.createElement("ip")
121 ipElem2.setAttribute("family", "ipv6")
122 ipElem2.setAttribute("address", "fe80:1234::1")
123 ipElem2.setAttribute("prefix", "64")
124 # adding to the 'defaultNetworkConfig'
125 netnode.appendChild(ipElem1)
126 netnode.appendChild(ipElem2)
127 return defaultNetworkConfig
129 def change_ipv6(dom, ipv6addr, prefix):
130 ips = dom.getElementsByTagName('ip')
132 if ip.getAttribute("family")=='ipv6' and not(re.match(r'fe80(.*)', ip.getAttribute("address"), re.I)):
133 ip.setAttribute("address", ipv6addr)
134 ip.setAttribute("prefix", prefix)
138 def remove_ipv6(dom):
139 networks = dom.getElementsByTagName('network')
140 for network in networks:
141 ips = network.getElementsByTagName('ip')
143 if ip.getAttribute("family")=='ipv6':
144 network.removeChild(ip)
148 def check_if_ipv6_is_different(dom, ipv6addr, prefix):
149 netnodes = dom.getElementsByTagName('network')
150 for netnode in netnodes:
151 ips = netnode.getElementsByTagName('ip')
153 if ip.getAttribute('family')=='ipv6' and \
154 not ( re.match(r'fe80(.*)', ip.getAttribute("address"), re.I) ) and \
155 (ip.getAttribute('address')!=ipv6addr or ip.getAttribute('prefix')!=prefix) :
156 logger.log("ipv6: IPv6 address or prefix are different. Change detected!")
161 def set_autostart(network):
163 network.setAutostart(1)
165 logger.log("ipv6: network could not set to autostart")
168 def set_up(networkLibvirt, connLibvirt, networkElem, ipv6addr, prefix):
169 newXml = networkElem.toxml()
170 #logger.log(networkElem.toxml())
173 # logger.log(repr(method))
174 networkLibvirt.undefine()
175 networkLibvirt.destroy()
176 connLibvirt.networkCreateXML(newXml)
177 networkDefault = connLibvirt.networkDefineXML(newXml)
178 set_autostart(networkDefault)
179 commandForwarding = ['sysctl', '-w', 'net.ipv6.conf.all.forwarding=1']
180 logger.log_call(commandForwarding, timeout=15*60)
185 MinRtrAdvInterval 30;
186 MaxRtrAdvInterval 100;
187 prefix %(ipv6addr)s/%(prefix)s
196 with open(radvd_conf_file, 'w') as f:
200 logger.log("ipv6: set up process finalized -- enabled IPv6 address to the slivers!")
202 def clean_up(networkLibvirt, connLibvirt, networkElem):
203 dom = remove_ipv6(networkElem)
205 networkLibvirt.undefine()
206 networkLibvirt.destroy()
207 # TODO: set autostart for the network
208 connLibvirt.networkCreateXML(newXml)
209 networkDefault = connLibvirt.networkDefineXML(newXml)
210 set_autostart(networkDefault)
212 logger.log("ipv6: cleanup process finalized. The IPv6 support on the slivers was removed.")
215 command_kill_radvd = ['killall', 'radvd']
216 logger.log_call(command_kill_radvd, timeout=15*60)
219 commandRadvd = ['radvd']
220 logger.log_call(commandRadvd, timeout=15*60)
222 def GetSlivers(data, config, plc):
225 virt=tools.get_node_virt()
229 interfaces = data['interfaces']
230 logger.log(repr(interfaces))
231 for interface in interfaces:
232 #logger.log('ipv6: get interface: %r'%(interface))
233 if 'interface_tag_ids' in interface:
234 interface_tag_ids = "interface_tag_ids"
235 interface_tag_id = "interface_tag_id"
236 settings = plc.GetInterfaceTags({interface_tag_id:interface[interface_tag_ids]})
237 is_slivers_ipv6_prefix_set = False
238 for setting in settings:
239 if setting['tagname']==sliversipv6prefixtag:
240 ipv6addrprefix = setting['value'].split('/', 1)
241 ipv6addr = ipv6addrprefix[0]
243 #logger.log("ipv6: len(ipv6addrprefix)=%s" % (len(ipv6addrprefix)) )
244 if len(ipv6addrprefix)>1:
245 prefix = ipv6addrprefix[1]
246 #logger.log("ipv6: prefix=%s" % (prefix) )
247 if int(prefix)>0 and int(prefix)<=64:
253 #logger.log("ipv6: '%s'=%s" % (sliversipv6prefixtag, ipv6addr) )
254 valid_ipv6 = tools.is_valid_ipv6(ipv6addr)
256 logger.log("ipv6: the 'sliversipv6prefix' tag presented a non-valid IPv6 address!")
257 elif not(valid_prefix):
258 logger.log("ipv6: the '%s' tag does not present a valid prefix (e.g., '/64', '/58')!" % \
259 (sliversipv6prefixtag))
261 # connecting to the libvirtd
262 connLibvirt = Sliver_Libvirt.getConnection(type)
263 list = connLibvirt.listAllNetworks()
264 for networkLibvirt in list:
265 xmldesc = networkLibvirt.XMLDesc()
266 dom = parseString(xmldesc)
267 has_ipv6 = check_for_ipv6(dom)
269 # let's first check if the IPv6 is different or is it the same...
270 is_different = check_if_ipv6_is_different(dom, ipv6addr, prefix)
272 logger.log("ipv6: tag 'sliversipv6prefix' was modified! " +
273 "Updating configuration with the new one...")
274 network_elem = change_ipv6(dom, ipv6addr, prefix)
275 set_up(networkLibvirt, connLibvirt, network_elem, ipv6addr, prefix)
276 logger.log("ipv6: trying to reboot the slivers...")
277 tools.reboot_slivers()
279 logger.log("ipv6: starting to redefine the virtual network...")
280 #network_elem = buildLibvirtDefaultNetConfig(dom, ipv6addr, prefix)
281 network_elem = add_ipv6(dom, ipv6addr, prefix)
282 set_up(networkLibvirt, connLibvirt, network_elem, ipv6addr, prefix)
283 logger.log("ipv6: trying to reboot the slivers...")
284 tools.reboot_slivers()
285 is_slivers_ipv6_prefix_set = True
286 if not(is_slivers_ipv6_prefix_set):
287 # connecting to the libvirtd
288 connLibvirt = Sliver_Libvirt.getConnection(type)
289 list = connLibvirt.listAllNetworks()
290 for networkLibvirt in list:
291 xmldesc = networkLibvirt.XMLDesc()
292 dom = parseString(xmldesc)
293 if check_for_ipv6(dom):
294 clean_up(networkLibvirt, connLibvirt, dom)
295 logger.log("ipv6: trying to reboot the slivers...")
296 tools.reboot_slivers()
298 logger.log("ipv6: all done!")