]> git.proxmox.com Git - mirror_ifupdown2.git/blame - addons/address.py
some more ifquery support (for vxlan devices etc)
[mirror_ifupdown2.git] / addons / address.py
CommitLineData
15ef32ea
RP
1#!/usr/bin/python
2#
3# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6
7try:
8 from ipaddr import IPNetwork
9 from sets import Set
10 from ifupdown.iface import *
11 from ifupdownaddons.modulebase import moduleBase
12 from ifupdownaddons.iproute2 import iproute2
13 from ifupdownaddons.dhclient import dhclient
14except ImportError, e:
15 raise ImportError (str(e) + "- required module not found")
16
17class address(moduleBase):
18 """ ifupdown2 addon module to configure address, mtu, hwaddress, alias
19 (description) on an interface """
20
21 _modinfo = {'mhelp' : 'address configuration module for interfaces',
22 'attrs': {
23 'address' :
24 {'help' : 'ipv4 or ipv6 addresses',
25 'example' : ['address 10.0.12.3/24',
26 'address 2000:1000:1000:1000:3::5/128']},
27 'netmask' :
28 {'help': 'netmask',
29 'example' : ['netmask 255.255.255.0'],
30 'compat' : True},
31 'broadcast' :
32 {'help': 'broadcast address',
33 'example' : ['broadcast 10.0.1.255']},
34 'scope' :
35 {'help': 'scope',
36 'example' : ['scope host']},
37 'preferred-lifetime' :
38 {'help': 'preferred lifetime',
39 'example' : ['preferred-lifetime forever',
40 'preferred-lifetime 10']},
41 'gateway' :
42 {'help': 'default gateway',
43 'example' : ['gateway 255.255.255.0']},
44 'mtu' :
45 { 'help': 'interface mtu',
46 'example' : ['mtu 1600'],
47 'default' : '1500'},
48 'hwaddress' :
49 {'help' : 'hw address',
50 'example': ['hwaddress 44:38:39:00:27:b8']},
51 'alias' :
52 { 'help': 'description/alias',
53 'example' : ['alias testnetwork']}}}
54
55 def __init__(self, *args, **kargs):
56 moduleBase.__init__(self, *args, **kargs)
57 self.ipcmd = None
58
cb46a208
RP
59 def _add_address_to_bridge(self, ifaceobj, hwaddress):
60 if '.' in ifaceobj.name:
61 (bridgename, vlan) = ifaceobj.name.split('.')
62 if self.ipcmd.bridge_is_vlan_aware(bridgename):
63 self.ipcmd.bridge_fdb_add(bridgename, hwaddress,
64 vlan)
65
66 def _remove_address_from_bridge(self, ifaceobj, hwaddress):
67 if '.' in ifaceobj.name:
68 (bridgename, vlan) = ifaceobj.name.split('.')
69 if self.ipcmd.bridge_is_vlan_aware(bridgename):
70 self.ipcmd.bridge_fdb_del(bridgename, hwaddress,
71 vlan)
72
15ef32ea
RP
73 def _inet_address_config(self, ifaceobj):
74 newaddrs = []
75 addrs = ifaceobj.get_attr_value('address')
76 if addrs:
77 # If user address is not in CIDR notation, convert them to CIDR
78 for addr_index in range(0, len(addrs)):
79 addr = addrs[addr_index]
80 if '/' in addr:
81 newaddrs.append(addr)
82 continue
83 netmask = ifaceobj.get_attr_value_n('netmask', addr_index)
84 if netmask:
85 prefixlen = IPNetwork('%s' %addr +
86 '/%s' %netmask).prefixlen
87 newaddrs.append(addr + '/%s' %prefixlen)
88 else:
89 newaddrs.append(addr)
90
91 if not self.PERFMODE and not (ifaceobj.flags & iface.HAS_SIBLINGS):
92 # if perfmode is not set and also if iface has no sibling
93 # objects, purge addresses that are not present in the new
94 # config
95 runningaddrs = self.ipcmd.addr_get(ifaceobj.name, details=False)
96 if newaddrs == runningaddrs:
97 return
98 try:
99 # if primary address is not same, there is no need to keep any.
100 # reset all addresses
101 if (newaddrs and runningaddrs and
102 (newaddrs[0] != runningaddrs[0])):
103 self.ipcmd.del_addr_all(ifaceobj.name)
104 else:
105 self.ipcmd.del_addr_all(ifaceobj.name, newaddrs)
106 except Exception, e:
107 self.log_warn(str(e))
108 if not newaddrs:
109 return
110 for addr_index in range(0, len(newaddrs)):
111 try:
112 self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index],
113 ifaceobj.get_attr_value_n('broadcast', addr_index),
114 ifaceobj.get_attr_value_n('pointopoint',addr_index),
115 ifaceobj.get_attr_value_n('scope', addr_index),
116 ifaceobj.get_attr_value_n('preferred-lifetime', addr_index))
117 except Exception, e:
118 self.log_error(str(e))
119
120 def _up(self, ifaceobj):
121 if not self.ipcmd.link_exists(ifaceobj.name):
122 return
123 try:
124 # release any stale dhcp addresses if present
125 if (not self.PERFMODE and
126 not (ifaceobj.flags & iface.HAS_SIBLINGS)):
127 # if not running in perf mode and ifaceobj does not have
128 # any sibling iface objects, kill any stale dhclient
129 # processes
130 dhclientcmd = self.dhclient()
131 if dhclient.is_running(ifaceobj.name):
132 # release any dhcp leases
133 dhclientcmd.release(ifaceobj.name)
134 elif dhclient.is_running6(ifaceobj.name):
135 dhclientcmd.release6(ifaceobj.name)
136 except:
137 pass
138 self.ipcmd.batch_start()
139 self._inet_address_config(ifaceobj)
140 mtu = ifaceobj.get_attr_value_first('mtu')
141 if mtu:
142 self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu)
15ef32ea
RP
143 alias = ifaceobj.get_attr_value_first('alias')
144 if alias:
145 self.ipcmd.link_set_alias(ifaceobj.name, alias)
cb46a208
RP
146 hwaddress = ifaceobj.get_attr_value_first('hwaddress')
147 if hwaddress:
148 self.ipcmd.link_set(ifaceobj.name, 'address', hwaddress)
15ef32ea 149 self.ipcmd.batch_commit()
cb46a208
RP
150
151 # After all adds are successful, also add the hw address
152 # to the bridge if required
153 if hwaddress:
154 self._add_address_to_bridge(ifaceobj, hwaddress)
155
15ef32ea
RP
156 self.ipcmd.route_add_gateway(ifaceobj.name,
157 ifaceobj.get_attr_value_first('gateway'))
158
159 def _down(self, ifaceobj):
160 try:
161 if not self.ipcmd.link_exists(ifaceobj.name):
162 return
163 self.ipcmd.route_del_gateway(ifaceobj.name,
164 ifaceobj.get_attr_value_first('gateway'),
165 ifaceobj.get_attr_value_first('metric'))
166 self.ipcmd.del_addr_all(ifaceobj.name)
167 mtu = ifaceobj.get_attr_value_first('mtu')
168 if mtu:
169 self.ipcmd.link_set(ifaceobj.name, 'mtu',
170 self.get_mod_subattr('mtu', 'default'))
171 alias = ifaceobj.get_attr_value_first('alias')
172 if alias:
173 self.ipcmd.link_set(ifaceobj.name, 'alias', "\'\'")
cb46a208
RP
174 hwaddress = ifaceobj.get_attr_value_first('hwaddress')
175 if hwaddress:
176 # XXX Dont know what to reset the address to
177 self._remove_address_from_bridge(ifaceobj, hwaddress)
15ef32ea
RP
178 except Exception, e:
179 self.log_warn(str(e))
180
181 def _get_iface_addresses(self, ifaceobj):
182 addrlist = ifaceobj.get_attr_value('address')
183 outaddrlist = []
184
185 if not addrlist: return None
186 for addrindex in range(0, len(addrlist)):
187 addr = addrlist[addrindex]
188 netmask = ifaceobj.get_attr_value_n('netmask', addrindex)
189 if netmask:
190 prefixlen = IPNetwork('%s' %addr +
191 '/%s' %netmask).prefixlen
192 addr = addr + '/%s' %prefixlen
193 outaddrlist.append(addr)
194 return outaddrlist
195
196 def _query_check(self, ifaceobj, ifaceobjcurr):
197 runningaddrsdict = None
198 if not self.ipcmd.link_exists(ifaceobj.name):
199 self.logger.debug('iface %s not found' %ifaceobj.name)
200 return
201 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
202 'mtu', self.ipcmd.link_get_mtu)
203 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
204 'hwaddress', self.ipcmd.link_get_hwaddress)
205 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
206 'alias', self.ipcmd.link_get_alias)
207 # compare addresses
208 addrs = self._get_iface_addresses(ifaceobj)
209 runningaddrsdict = self.ipcmd.addr_get(ifaceobj.name)
210
211 # Set ifaceobjcurr method and family
212 ifaceobjcurr.addr_method = ifaceobj.addr_method
213 ifaceobjcurr.addr_family = ifaceobj.addr_family
214 if not runningaddrsdict and not addrs:
215 return
216 runningaddrs = runningaddrsdict.keys() if runningaddrsdict else []
217 if runningaddrs != addrs:
218 runningaddrsset = set(runningaddrs) if runningaddrs else set([])
219 addrsset = set(addrs) if addrs else set([])
220 if (ifaceobj.flags & iface.HAS_SIBLINGS):
221 if not addrsset:
222 return
223 # only check for addresses present in running config
224 addrsdiff = addrsset.difference(runningaddrsset)
225 for addr in addrs:
226 if addr in addrsdiff:
227 ifaceobjcurr.update_config_with_status('address',
228 addr, 1)
229 else:
230 ifaceobjcurr.update_config_with_status('address',
231 addr, 0)
232 else:
233 addrsdiff = addrsset.symmetric_difference(runningaddrsset)
234 for addr in addrsset.union(runningaddrsset):
235 if addr in addrsdiff:
236 ifaceobjcurr.update_config_with_status('address',
237 addr, 1)
238 else:
239 ifaceobjcurr.update_config_with_status('address',
240 addr, 0)
241 elif addrs:
242 [ifaceobjcurr.update_config_with_status('address',
243 addr, 0) for addr in addrs]
244 #XXXX Check broadcast address, scope, etc
245 return
246
247 def _query_running(self, ifaceobjrunning):
248 if not self.ipcmd.link_exists(ifaceobjrunning.name):
249 self.logger.debug('iface %s not found' %ifaceobjrunning.name)
250 ifaceobjrunning.status = ifaceStatus.NOTFOUND
251 return
252 dhclientcmd = dhclient()
253 if (dhclientcmd.is_running(ifaceobjrunning.name) or
254 dhclientcmd.is_running6(ifaceobjrunning.name)):
255 # If dhcp is configured on the interface, we skip it
256 return
257 isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name)
258 if isloopback:
259 default_addrs = ['127.0.0.1/8', '::1/128']
260 ifaceobjrunning.addr_family = 'inet'
261 ifaceobjrunning.addr_method = 'loopback'
262 else:
263 default_addrs = []
264 runningaddrsdict = self.ipcmd.addr_get(ifaceobjrunning.name)
265 if runningaddrsdict:
266 [ifaceobjrunning.update_config('address', addr)
267 for addr, addrattrs in runningaddrsdict.items()
268 if addr not in default_addrs]
269 mtu = self.ipcmd.link_get_mtu(ifaceobjrunning.name)
270 if (mtu and
271 (ifaceobjrunning.name == 'lo' and mtu != '16436') or
272 (ifaceobjrunning.name != 'lo' and
273 mtu != self.get_mod_subattr('mtu', 'default'))):
274 ifaceobjrunning.update_config('mtu', mtu)
275 alias = self.ipcmd.link_get_alias(ifaceobjrunning.name)
276 if alias:
277 ifaceobjrunning.update_config('alias', alias)
278
279 _run_ops = {'up' : _up,
280 'down' : _down,
281 'query-checkcurr' : _query_check,
282 'query-running' : _query_running }
283
284 def get_ops(self):
285 """ returns list of ops supported by this module """
286 return self._run_ops.keys()
287
288 def _init_command_handlers(self):
289 if not self.ipcmd:
290 self.ipcmd = iproute2(**self.get_flags())
291
84ca006f 292 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
15ef32ea
RP
293 """ run address configuration on the interface object passed as argument
294
295 Args:
296 **ifaceobj** (object): iface object
297
298 **operation** (str): any of 'up', 'down', 'query-checkcurr',
299 'query-running'
300 Kwargs:
301 query_ifaceobj (object): query check ifaceobject. This is only
302 valid when op is 'query-checkcurr'. It is an object same as
303 ifaceobj, but contains running attribute values and its config
304 status. The modules can use it to return queried running state
305 of interfaces. status is success if the running state is same
306 as user required state in ifaceobj. error otherwise.
307 """
308
309 op_handler = self._run_ops.get(operation)
310 if not op_handler:
311 return
312 if (operation != 'query-running' and ifaceobj.addr_family and
313 ifaceobj.addr_family != 'inet' and
314 ifaceobj.addr_family != 'inet6'):
315 return
316 if (operation != 'query-running' and ifaceobj.addr_method and
317 ifaceobj.addr_method != 'static' and
318 ifaceobj.addr_method != 'loopback'):
319 return
320 self._init_command_handlers()
321 if operation == 'query-checkcurr':
322 op_handler(self, ifaceobj, query_ifaceobj)
323 else:
324 op_handler(self, ifaceobj)