]> git.proxmox.com Git - mirror_ifupdown2.git/blame - addons/address.py
addons: bridge: don't warn several times for duplicate bridge-ports in stanza
[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
9087e727
JF
7import os
8
15ef32ea 9try:
c6370b56 10 from ipaddr import IPNetwork, IPv4Network, IPv6Network, IPv4Address, IPv6Address
15ef32ea
RP
11 from sets import Set
12 from ifupdown.iface import *
82908a2d 13 from ifupdown.utils import utils
15ef32ea
RP
14 from ifupdownaddons.modulebase import moduleBase
15 from ifupdownaddons.iproute2 import iproute2
16 from ifupdownaddons.dhclient import dhclient
84f33af6 17 import ifupdown.policymanager as policymanager
2864d6f3 18 from ifupdown.netlink import netlink
0582f185 19 import ifupdown.ifupdownconfig as ifupdownConfig
fc5e1735 20 import ifupdown.ifupdownflags as ifupdownflags
0232d1bb 21 import ifupdown.statemanager as statemanager
15ef32ea
RP
22except ImportError, e:
23 raise ImportError (str(e) + "- required module not found")
24
25class address(moduleBase):
26 """ ifupdown2 addon module to configure address, mtu, hwaddress, alias
27 (description) on an interface """
28
29 _modinfo = {'mhelp' : 'address configuration module for interfaces',
30 'attrs': {
31 'address' :
32 {'help' : 'ipv4 or ipv6 addresses',
482b2fab 33 'validvals' : ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
c6370b56 34 'multiline' : True,
15ef32ea
RP
35 'example' : ['address 10.0.12.3/24',
36 'address 2000:1000:1000:1000:3::5/128']},
37 'netmask' :
38 {'help': 'netmask',
39 'example' : ['netmask 255.255.255.0'],
40 'compat' : True},
41 'broadcast' :
42 {'help': 'broadcast address',
482b2fab 43 'validvals' : ['<ipv4>', ],
15ef32ea
RP
44 'example' : ['broadcast 10.0.1.255']},
45 'scope' :
46 {'help': 'scope',
c6370b56 47 'validvals' : ['universe', 'site', 'link', 'host', 'nowhere'],
15ef32ea
RP
48 'example' : ['scope host']},
49 'preferred-lifetime' :
50 {'help': 'preferred lifetime',
c6370b56 51 'validrange' : ['0', '65535'],
15ef32ea
RP
52 'example' : ['preferred-lifetime forever',
53 'preferred-lifetime 10']},
54 'gateway' :
55 {'help': 'default gateway',
482b2fab 56 'validvals' : ['<ipv4>', '<ipv6>'],
2ed2adeb 57 'multiline' : True,
15ef32ea
RP
58 'example' : ['gateway 255.255.255.0']},
59 'mtu' :
60 { 'help': 'interface mtu',
c6370b56 61 'validrange' : ['552', '9216'],
15ef32ea
RP
62 'example' : ['mtu 1600'],
63 'default' : '1500'},
64 'hwaddress' :
65 {'help' : 'hw address',
c6370b56 66 'validvals' : ['<mac>',],
15ef32ea
RP
67 'example': ['hwaddress 44:38:39:00:27:b8']},
68 'alias' :
69 { 'help': 'description/alias',
394e68b5
RP
70 'example' : ['alias testnetwork']},
71 'address-purge' :
72 { 'help': 'purge existing addresses. By default ' +
73 'any existing ip addresses on an interface are ' +
74 'purged to match persistant addresses in the ' +
75 'interfaces file. Set this attribute to \'no\'' +
76 'if you want to preserve existing addresses',
c6370b56 77 'validvals' : ['yes', 'no'],
394e68b5 78 'default' : 'yes',
a794fb31
BR
79 'example' : ['address-purge yes/no']},
80 'clagd-vxlan-anycast-ip' :
81 { 'help' : 'Anycast local IP address for ' +
82 'dual connected VxLANs',
482b2fab 83 'validvals' : ['<ipv4>', ],
a794fb31 84 'example' : ['clagd-vxlan-anycast-ip 36.0.0.11']}}}
15ef32ea
RP
85
86 def __init__(self, *args, **kargs):
87 moduleBase.__init__(self, *args, **kargs)
88 self.ipcmd = None
8e113d63 89 self._bridge_fdb_query_cache = {}
84f33af6 90 self.default_mtu = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='mtu')
9f30b2cc
RP
91 self.max_mtu = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='max_mtu')
92
93 if not self.default_mtu:
94 self.default_mtu = '1500'
95
96 self.logger.info('address: using default mtu %s' %self.default_mtu)
97
98 if self.max_mtu:
99 self.logger.info('address: using max mtu %s' %self.max_mtu)
15ef32ea 100
22b49c28
JF
101 def syntax_check(self, ifaceobj, ifaceobj_func=None):
102 return (self.syntax_check_multiple_gateway(ifaceobj)
103 and self.syntax_check_addr_allowed_on(ifaceobj, True))
104
105 def syntax_check_addr_allowed_on(self, ifaceobj, syntax_check=False):
106 if ifaceobj.get_attr_value('address'):
107 return utils.is_addr_ip_allowed_on(ifaceobj, syntax_check=syntax_check)
108 return True
109
38365d4a
JF
110 def _syntax_check_multiple_gateway(self, family, found, addr, type_obj):
111 if type(IPNetwork(addr)) == type_obj:
112 if found:
113 raise Exception('%s: multiple gateways for %s family'
114 % (addr, family))
115 return True
116 return False
117
22b49c28 118 def syntax_check_multiple_gateway(self, ifaceobj):
38365d4a
JF
119 result = True
120 inet = False
121 inet6 = False
122 gateways = ifaceobj.get_attr_value('gateway')
123 for addr in gateways if gateways else []:
124 try:
125 if self._syntax_check_multiple_gateway('inet', inet, addr,
126 IPv4Network):
127 inet = True
128 if self._syntax_check_multiple_gateway('inet6', inet6, addr,
129 IPv6Network):
130 inet6 = True
131 except Exception as e:
132 self.logger.warning('%s: address: %s' % (ifaceobj.name, str(e)))
133 result = False
134 return result
135
75afe2a7
RP
136 def _address_valid(self, addrs):
137 if not addrs:
138 return False
139 if any(map(lambda a: True if a[:7] != '0.0.0.0'
140 else False, addrs)):
141 return True
142 return False
143
428206bf 144 def _get_hwaddress(self, ifaceobj):
2876ca35 145 hwaddress = ifaceobj.get_attr_value_first('hwaddress')
428206bf
JF
146 if hwaddress and hwaddress.startswith("ether"):
147 hwaddress = hwaddress[5:].strip()
148 return hwaddress
149
150 def _process_bridge(self, ifaceobj, up):
151 hwaddress = self._get_hwaddress(ifaceobj)
75afe2a7
RP
152 addrs = ifaceobj.get_attr_value_first('address')
153 is_vlan_dev_on_vlan_aware_bridge = False
154 is_bridge = self.ipcmd.is_bridge(ifaceobj.name)
155 if not is_bridge:
156 if '.' in ifaceobj.name:
157 (bridgename, vlan) = ifaceobj.name.split('.')
158 is_vlan_dev_on_vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridgename)
8c2c9f26
RP
159 if ((is_bridge and not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name))
160 or is_vlan_dev_on_vlan_aware_bridge):
75afe2a7
RP
161 if self._address_valid(addrs):
162 if up:
163 self.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj.name +
164 '/arp_accept', '1')
165 else:
166 self.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj.name +
167 '/arp_accept', '0')
168 if hwaddress and is_vlan_dev_on_vlan_aware_bridge:
169 if up:
170 self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan)
171 else:
172 self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan)
cb46a208 173
0582f185
RP
174 def _get_anycast_addr(self, ifaceobjlist):
175 for ifaceobj in ifaceobjlist:
176 anycast_addr = ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip')
177 if anycast_addr:
178 anycast_addr = anycast_addr+'/32'
179 return anycast_addr
180 return None
181
182 def _inet_address_convert_to_cidr(self, ifaceobjlist):
15ef32ea 183 newaddrs = []
0582f185
RP
184 newaddr_attrs = {}
185
186 for ifaceobj in ifaceobjlist:
187 addrs = ifaceobj.get_attr_value('address')
188 if not addrs:
189 continue
190
22b49c28
JF
191 if not self.syntax_check_addr_allowed_on(ifaceobj,
192 syntax_check=False):
0582f185 193 return (False, newaddrs, newaddr_attrs)
15ef32ea
RP
194 # If user address is not in CIDR notation, convert them to CIDR
195 for addr_index in range(0, len(addrs)):
196 addr = addrs[addr_index]
197 if '/' in addr:
198 newaddrs.append(addr)
199 continue
494d31d2 200 newaddr = addr
15ef32ea
RP
201 netmask = ifaceobj.get_attr_value_n('netmask', addr_index)
202 if netmask:
203 prefixlen = IPNetwork('%s' %addr +
204 '/%s' %netmask).prefixlen
0582f185 205 newaddr = addr + '/%s' %prefixlen
42ae7838
ST
206 else:
207 # we are here because there is no slash (/xx) and no netmask
208 # just let IPNetwork handle the ipv4 or ipv6 address mask
209 prefixlen = IPNetwork(addr).prefixlen
210 newaddr = addr + '/%s' %prefixlen
0582f185 211 newaddrs.append(newaddr)
15ef32ea 212
0582f185
RP
213 attrs = {}
214 for a in ['broadcast', 'pointopoint', 'scope',
215 'preferred-lifetime']:
216 aval = ifaceobj.get_attr_value_n(a, addr_index)
217 if aval:
72c964c2 218 attrs[a] = aval
0582f185
RP
219
220 if attrs:
221 newaddr_attrs[newaddr]= attrs
222 return (True, newaddrs, newaddr_attrs)
223
77021aa1
RP
224 def _inet_address_list_config(self, ifaceobj, newaddrs, newaddr_attrs):
225 for addr_index in range(0, len(newaddrs)):
226 try:
227 if newaddr_attrs:
228 self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index],
229 newaddr_attrs.get(newaddrs[addr_index],
230 {}).get('broadcast'),
231 newaddr_attrs.get(newaddrs[addr_index],
232 {}).get('pointopoint'),
233 newaddr_attrs.get(newaddrs[addr_index],
234 {}).get('scope'),
235 newaddr_attrs.get(newaddrs[addr_index],
236 {}).get('preferred-lifetime'))
237 else:
238 self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index])
239 except Exception, e:
bf3eda91 240 self.log_error(str(e), ifaceobj)
77021aa1
RP
241
242 def _inet_address_config(self, ifaceobj, ifaceobj_getfunc=None,
243 force_reapply=False):
0582f185
RP
244 squash_addr_config = (True if \
245 ifupdownConfig.config.get('addr_config_squash', \
246 '0') == '1' else False)
247
248 if (squash_addr_config and
249 not (ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING)):
250 return
251
252 purge_addresses = ifaceobj.get_attr_value_first('address-purge')
253 if not purge_addresses:
254 purge_addresses = 'yes'
255
256 if squash_addr_config and ifaceobj.flags & iface.HAS_SIBLINGS:
257 ifaceobjlist = ifaceobj_getfunc(ifaceobj.name)
258 else:
259 ifaceobjlist = [ifaceobj]
260
261 (addr_supported, newaddrs, newaddr_attrs) = self._inet_address_convert_to_cidr(ifaceobjlist)
82908a2d 262 newaddrs = utils.get_normalized_ip_addr(ifaceobj.name, newaddrs)
0582f185
RP
263 if not addr_supported:
264 return
265 if (not squash_addr_config and (ifaceobj.flags & iface.HAS_SIBLINGS)):
266 # if youngest sibling and squash addr is not set
267 # print a warning that addresses will not be purged
268 if (ifaceobj.flags & iface.YOUNGEST_SIBLING):
269 self.logger.warn('%s: interface has multiple ' %ifaceobj.name +
270 'iface stanzas, skip purging existing addresses')
271 purge_addresses = 'no'
272
fc5e1735 273 if not ifupdownflags.flags.PERFMODE and purge_addresses == 'yes':
0582f185
RP
274 # if perfmode is not set and purge addresses is not set to 'no'
275 # lets purge addresses not in the config
82908a2d 276 runningaddrs = utils.get_normalized_ip_addr(ifaceobj.name, self.ipcmd.addr_get(ifaceobj.name, details=False))
0582f185 277
a794fb31
BR
278 # if anycast address is configured on 'lo' and is in running config
279 # add it to newaddrs so that ifreload doesn't wipe it out
82908a2d 280 anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, self._get_anycast_addr(ifaceobjlist))
0582f185 281
a794fb31
BR
282 if runningaddrs and anycast_addr and anycast_addr in runningaddrs:
283 newaddrs.append(anycast_addr)
15ef32ea 284 if newaddrs == runningaddrs:
77021aa1
RP
285 if force_reapply:
286 self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
15ef32ea
RP
287 return
288 try:
289 # if primary address is not same, there is no need to keep any.
290 # reset all addresses
291 if (newaddrs and runningaddrs and
292 (newaddrs[0] != runningaddrs[0])):
293 self.ipcmd.del_addr_all(ifaceobj.name)
294 else:
295 self.ipcmd.del_addr_all(ifaceobj.name, newaddrs)
296 except Exception, e:
297 self.log_warn(str(e))
298 if not newaddrs:
299 return
77021aa1 300 self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
15ef32ea 301
0232d1bb
N
302 def _add_delete_gateway(self, ifaceobj, gateways=[], prev_gw=[]):
303 vrf = ifaceobj.get_attr_value_first('vrf')
304 metric = ifaceobj.get_attr_value_first('metric')
305 for del_gw in list(set(prev_gw) - set(gateways)):
306 try:
307 self.ipcmd.route_del_gateway(ifaceobj.name, del_gw, vrf, metric)
308 except:
309 pass
310 for add_gw in list(set(gateways) - set(prev_gw)):
311 try:
312 self.ipcmd.route_add_gateway(ifaceobj.name, add_gw, vrf)
313 except:
314 pass
315
316 def _get_prev_gateway(self, ifaceobj, gateways):
317 ipv = []
318 saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name)
319 if not saved_ifaceobjs:
320 return ipv
321 prev_gateways = saved_ifaceobjs[0].get_attr_value('gateway')
322 if not prev_gateways:
323 return ipv
324 return prev_gateways
325
8d1e346f
RP
326 def _check_mtu_config(self, ifaceobj, mtu, ifaceobj_getfunc, syntaxcheck=False):
327 retval = True
328 if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
329 if syntaxcheck:
330 self.logger.warn('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj.name)
331 retval = False
332 else:
9f30b2cc 333 self.logger.info('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj.name)
8d1e346f
RP
334 elif ifaceobj_getfunc:
335 if ((ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and
336 ifaceobj.upperifaces):
9f30b2cc
RP
337 masterobj = ifaceobj_getfunc(ifaceobj.upperifaces[0])
338 if masterobj:
339 master_mtu = masterobj[0].get_attr_value_first('mtu')
340 if master_mtu and master_mtu != mtu:
8d1e346f
RP
341 if syntaxcheck:
342 self.logger.warn('%s: bond slave mtu %s is different from bond master %s mtu %s. There is no need to configure mtu on a bond slave.' %(ifaceobj.name, mtu, masterobj[0].name, master_mtu))
343 retval = False
344 else:
345 self.logger.info('%s: bond slave mtu %s is different from bond master %s mtu %s. There is no need to configure mtu on a bond slave.' %(ifaceobj.name, mtu, masterobj[0].name, master_mtu))
346 elif ((ifaceobj.link_kind & ifaceLinkKind.VLAN) and
347 ifaceobj.lowerifaces):
348 lowerobj = ifaceobj_getfunc(ifaceobj.lowerifaces[0])
349 if lowerobj:
350 if syntaxcheck:
351 lowerdev_mtu = lowerobj[0].get_attr_value_first('mtu')
352 else:
353 lowerdev_mtu = self.ipcmd.link_get_mtu(lowerobj[0].name)
354 if lowerdev_mtu and int(mtu) > int(lowerdev_mtu):
355 self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
356 %(ifaceobj.name, mtu, lowerobj[0].name, lowerdev_mtu))
357 retval = False
358 elif (not lowerobj[0].link_kind and
359 not (lowerobj[0].link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
360 self.default_mtu and (int(mtu) > int(self.default_mtu))):
361 # only check default mtu on lower device which is a physical interface
362 self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
363 %(ifaceobj.name, mtu, lowerobj[0].name, self.default_mtu))
364 retval = False
9f30b2cc
RP
365 if self.max_mtu and mtu > self.max_mtu:
366 self.logger.warn('%s: specified mtu %s is greater than max mtu %s'
367 %(ifaceobj.name, mtu, self.max_mtu))
8d1e346f
RP
368 retval = False
369 return retval
370
371 def _propagate_mtu_to_upper_devs(self, ifaceobj, mtu, ifaceobj_getfunc):
372 if (not ifaceobj.upperifaces or
373 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) or
374 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) or
375 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT)):
376 return
377 for u in ifaceobj.upperifaces:
378 upperobjs = ifaceobj_getfunc(u)
379 if (not upperobjs or
380 not (upperobjs[0].link_kind & ifaceLinkKind.VLAN)):
381 continue
382 # only adjust mtu for vlan devices on ifaceobj
383 umtu = upperobjs[0].get_attr_value_first('mtu')
384 if not umtu:
385 running_mtu = self.ipcmd.link_get_mtu(upperobjs[0].name)
386 if not running_mtu or (running_mtu != mtu):
387 self.ipcmd.link_set(u, 'mtu', mtu)
388
389 def _process_mtu_config(self, ifaceobj, ifaceobj_getfunc):
390 mtu = ifaceobj.get_attr_value_first('mtu')
391 if mtu:
392 if not self._check_mtu_config(ifaceobj, mtu, ifaceobj_getfunc):
393 return
394 running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
395 if not running_mtu or (running_mtu and running_mtu != mtu):
396 self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu)
397 if (not ifupdownflags.flags.ALL and
398 not ifaceobj.link_kind and
399 ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0'):
400 # This is additional cost to us, so do it only when
401 # ifupdown2 is called on a particular interface and
402 # it is a physical interface
403 self._propagate_mtu_to_upper_devs(ifaceobj, mtu, ifaceobj_getfunc)
9f30b2cc
RP
404 return
405
406 if ifaceobj.link_kind:
407 # bonds and vxlan devices need an explicit set of mtu.
408 # bridges don't need mtu set
409 if (ifaceobj.link_kind & ifaceLinkKind.BOND or
410 ifaceobj.link_kind & ifaceLinkKind.VXLAN):
411 running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
412 if (self.default_mtu and running_mtu != self.default_mtu):
413 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
414 return
415 if (ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0'
416 and ifaceobj.lowerifaces):
417 # set vlan interface mtu to lower device mtu
418 if (ifaceobj.link_kind & ifaceLinkKind.VLAN):
419 lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.lowerifaces[0], refresh=True)
420 if not lower_iface_mtu == self.ipcmd.link_get_mtu(ifaceobj.name):
421 self.ipcmd.link_set_mtu(ifaceobj.name, lower_iface_mtu)
422
423 elif (not (ifaceobj.name == 'lo') and not ifaceobj.link_kind and
424 not (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and
425 self.default_mtu):
426 # logical devices like bridges and vlan devices rely on mtu
427 # from their lower devices. ie mtu travels from
428 # lower devices to upper devices. For bonds mtu travels from
429 # upper to lower devices. running mtu depends on upper and
430 # lower device mtu. With all this implicit mtu
431 # config by the kernel in play, we try to be cautious here
432 # on which devices we want to reset mtu to default.
433 # essentially only physical interfaces which are not bond slaves
434 running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
435 if running_mtu != self.default_mtu:
436 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
437
0582f185 438 def _up(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea
RP
439 if not self.ipcmd.link_exists(ifaceobj.name):
440 return
68d9fee0 441 addr_method = ifaceobj.addr_method
77021aa1 442 force_reapply = False
15ef32ea
RP
443 try:
444 # release any stale dhcp addresses if present
fc5e1735 445 if (addr_method != "dhcp" and not ifupdownflags.flags.PERFMODE and
15ef32ea
RP
446 not (ifaceobj.flags & iface.HAS_SIBLINGS)):
447 # if not running in perf mode and ifaceobj does not have
448 # any sibling iface objects, kill any stale dhclient
449 # processes
75afe2a7 450 dhclientcmd = dhclient()
7c1135ea 451 if dhclientcmd.is_running(ifaceobj.name):
15ef32ea
RP
452 # release any dhcp leases
453 dhclientcmd.release(ifaceobj.name)
77021aa1 454 force_reapply = True
7c1135ea 455 elif dhclientcmd.is_running6(ifaceobj.name):
15ef32ea 456 dhclientcmd.release6(ifaceobj.name)
77021aa1 457 force_reapply = True
15ef32ea
RP
458 except:
459 pass
8e113d63 460
15ef32ea 461 self.ipcmd.batch_start()
68d9fee0 462 if addr_method != "dhcp":
77021aa1
RP
463 self._inet_address_config(ifaceobj, ifaceobj_getfunc,
464 force_reapply)
9f30b2cc 465 self._process_mtu_config(ifaceobj, ifaceobj_getfunc)
13e22530 466
15ef32ea
RP
467 alias = ifaceobj.get_attr_value_first('alias')
468 if alias:
8e113d63 469 self.ipcmd.link_set_alias(ifaceobj.name, alias)
093ffa00
JF
470 try:
471 self.ipcmd.batch_commit()
472 except Exception as e:
03092649 473 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj, raise_error=False)
264dcaa0 474
68d9fee0 475 try:
707aeb73
JF
476 hwaddress = self._get_hwaddress(ifaceobj)
477 if hwaddress:
478 running_hwaddress = None
479 if not ifupdownflags.flags.PERFMODE: # system is clean
480 running_hwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
481 if hwaddress != running_hwaddress:
482 slave_down = False
483 netlink.link_set_updown(ifaceobj.name, "down")
484 if ifaceobj.link_kind & ifaceLinkKind.BOND:
485 # if bond, down all the slaves
486 if ifaceobj.lowerifaces:
487 for l in ifaceobj.lowerifaces:
488 netlink.link_set_updown(l, "down")
489 slave_down = True
490 try:
491 self.ipcmd.link_set(ifaceobj.name, 'address', hwaddress)
492 finally:
493 netlink.link_set_updown(ifaceobj.name, "up")
494 if slave_down:
495 for l in ifaceobj.lowerifaces:
496 netlink.link_set_updown(l, "up")
497
68d9fee0
RP
498 # Handle special things on a bridge
499 self._process_bridge(ifaceobj, True)
500 except Exception, e:
bf3eda91 501 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
cb46a208 502
68d9fee0 503 if addr_method != "dhcp":
0232d1bb
N
504 gateways = ifaceobj.get_attr_value('gateway')
505 if not gateways:
506 gateways = []
507 prev_gw = self._get_prev_gateway(ifaceobj, gateways)
508 self._add_delete_gateway(ifaceobj, gateways, prev_gw)
509 return
15ef32ea 510
0582f185 511 def _down(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea
RP
512 try:
513 if not self.ipcmd.link_exists(ifaceobj.name):
514 return
68d9fee0
RP
515 addr_method = ifaceobj.addr_method
516 if addr_method != "dhcp":
aa052170
N
517 if ifaceobj.get_attr_value_first('address-purge')=='no':
518 addrlist = ifaceobj.get_attr_value('address')
519 for addr in addrlist:
520 self.ipcmd.addr_del(ifaceobj.name, addr)
521 #self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0])
522 else:
523 self.ipcmd.del_addr_all(ifaceobj.name)
84f33af6 524 mtu = ifaceobj.get_attr_value_first('mtu')
00c12960
RP
525 if (not ifaceobj.link_kind and mtu and
526 self.default_mtu and (mtu != self.default_mtu)):
84f33af6 527 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
15ef32ea
RP
528 alias = ifaceobj.get_attr_value_first('alias')
529 if alias:
9087e727 530 filename = '/sys/class/net/%s/ifalias' %ifaceobj.name
a4a53f4b 531 self.logger.info('executing echo "" > %s' %filename)
9087e727 532 os.system('echo "" > %s' %filename)
75afe2a7
RP
533 # XXX hwaddress reset cannot happen because we dont know last
534 # address.
535
536 # Handle special things on a bridge
537 self._process_bridge(ifaceobj, False)
15ef32ea 538 except Exception, e:
bcf11b14
RP
539 self.logger.debug('%s : %s' %(ifaceobj.name, str(e)))
540 pass
15ef32ea
RP
541
542 def _get_iface_addresses(self, ifaceobj):
543 addrlist = ifaceobj.get_attr_value('address')
544 outaddrlist = []
545
546 if not addrlist: return None
547 for addrindex in range(0, len(addrlist)):
548 addr = addrlist[addrindex]
549 netmask = ifaceobj.get_attr_value_n('netmask', addrindex)
550 if netmask:
551 prefixlen = IPNetwork('%s' %addr +
552 '/%s' %netmask).prefixlen
553 addr = addr + '/%s' %prefixlen
554 outaddrlist.append(addr)
555 return outaddrlist
556
8e113d63
RP
557 def _get_bridge_fdbs(self, bridgename, vlan):
558 fdbs = self._bridge_fdb_query_cache.get(bridgename)
559 if not fdbs:
560 fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
561 if not fdbs:
562 return
563 self._bridge_fdb_query_cache[bridgename] = fdbs
564 return fdbs.get(vlan)
565
566 def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
567 """ If the device is a bridge, make sure the addresses
568 are in the bridge """
569 if '.' in ifaceobj.name:
570 (bridgename, vlan) = ifaceobj.name.split('.')
571 if self.ipcmd.bridge_is_vlan_aware(bridgename):
572 fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
573 if not fdb_addrs or hwaddress not in fdb_addrs:
574 return False
575 return True
576
0582f185 577 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
15ef32ea
RP
578 runningaddrsdict = None
579 if not self.ipcmd.link_exists(ifaceobj.name):
580 self.logger.debug('iface %s not found' %ifaceobj.name)
581 return
16d854b4 582 addr_method = ifaceobj.addr_method
15ef32ea
RP
583 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
584 'mtu', self.ipcmd.link_get_mtu)
428206bf 585 hwaddress = self._get_hwaddress(ifaceobj)
8e113d63 586 if hwaddress:
2876ca35 587 rhwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
8e113d63
RP
588 if not rhwaddress or rhwaddress != hwaddress:
589 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
590 1)
591 elif not self._check_addresses_in_bridge(ifaceobj, hwaddress):
592 # XXX: hw address is not in bridge
593 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
594 1)
595 ifaceobjcurr.status_str = 'bridge fdb error'
596 else:
597 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
598 0)
15ef32ea
RP
599 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
600 'alias', self.ipcmd.link_get_alias)
601 # compare addresses
16d854b4
RP
602 if addr_method == 'dhcp':
603 return
82908a2d
JF
604 addrs = utils.get_normalized_ip_addr(ifaceobj.name,
605 self._get_iface_addresses(ifaceobj))
15ef32ea 606 runningaddrsdict = self.ipcmd.addr_get(ifaceobj.name)
a794fb31
BR
607 # if anycast address is configured on 'lo' and is in running config
608 # add it to addrs so that query_check doesn't fail
82908a2d 609 anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip'))
a794fb31
BR
610 if anycast_addr:
611 anycast_addr = anycast_addr+'/32'
612 if runningaddrsdict and anycast_addr and runningaddrsdict.get(anycast_addr):
613 addrs.append(anycast_addr)
15ef32ea
RP
614
615 # Set ifaceobjcurr method and family
616 ifaceobjcurr.addr_method = ifaceobj.addr_method
617 ifaceobjcurr.addr_family = ifaceobj.addr_family
618 if not runningaddrsdict and not addrs:
619 return
620 runningaddrs = runningaddrsdict.keys() if runningaddrsdict else []
621 if runningaddrs != addrs:
622 runningaddrsset = set(runningaddrs) if runningaddrs else set([])
623 addrsset = set(addrs) if addrs else set([])
624 if (ifaceobj.flags & iface.HAS_SIBLINGS):
625 if not addrsset:
626 return
627 # only check for addresses present in running config
628 addrsdiff = addrsset.difference(runningaddrsset)
629 for addr in addrs:
630 if addr in addrsdiff:
631 ifaceobjcurr.update_config_with_status('address',
632 addr, 1)
633 else:
634 ifaceobjcurr.update_config_with_status('address',
635 addr, 0)
636 else:
637 addrsdiff = addrsset.symmetric_difference(runningaddrsset)
638 for addr in addrsset.union(runningaddrsset):
639 if addr in addrsdiff:
640 ifaceobjcurr.update_config_with_status('address',
641 addr, 1)
642 else:
643 ifaceobjcurr.update_config_with_status('address',
644 addr, 0)
645 elif addrs:
646 [ifaceobjcurr.update_config_with_status('address',
647 addr, 0) for addr in addrs]
648 #XXXX Check broadcast address, scope, etc
649 return
650
0582f185 651 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
15ef32ea
RP
652 if not self.ipcmd.link_exists(ifaceobjrunning.name):
653 self.logger.debug('iface %s not found' %ifaceobjrunning.name)
15ef32ea
RP
654 return
655 dhclientcmd = dhclient()
656 if (dhclientcmd.is_running(ifaceobjrunning.name) or
657 dhclientcmd.is_running6(ifaceobjrunning.name)):
658 # If dhcp is configured on the interface, we skip it
84f33af6 659 return
15ef32ea
RP
660 isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name)
661 if isloopback:
662 default_addrs = ['127.0.0.1/8', '::1/128']
004d1e65 663 ifaceobjrunning.addr_family.append('inet')
15ef32ea
RP
664 ifaceobjrunning.addr_method = 'loopback'
665 else:
666 default_addrs = []
667 runningaddrsdict = self.ipcmd.addr_get(ifaceobjrunning.name)
668 if runningaddrsdict:
669 [ifaceobjrunning.update_config('address', addr)
670 for addr, addrattrs in runningaddrsdict.items()
671 if addr not in default_addrs]
672 mtu = self.ipcmd.link_get_mtu(ifaceobjrunning.name)
673 if (mtu and
674 (ifaceobjrunning.name == 'lo' and mtu != '16436') or
675 (ifaceobjrunning.name != 'lo' and
676 mtu != self.get_mod_subattr('mtu', 'default'))):
677 ifaceobjrunning.update_config('mtu', mtu)
678 alias = self.ipcmd.link_get_alias(ifaceobjrunning.name)
84f33af6 679 if alias:
15ef32ea
RP
680 ifaceobjrunning.update_config('alias', alias)
681
8d1e346f
RP
682 def syntax_check(self, ifaceobj, ifaceobj_getfunc):
683 mtu = ifaceobj.get_attr_value_first('mtu')
684 if mtu:
685 return self._check_mtu_config(ifaceobj, mtu, ifaceobj_getfunc,
686 syntaxcheck=True)
687 return True
688
15ef32ea
RP
689 _run_ops = {'up' : _up,
690 'down' : _down,
691 'query-checkcurr' : _query_check,
692 'query-running' : _query_running }
693
694 def get_ops(self):
695 """ returns list of ops supported by this module """
696 return self._run_ops.keys()
697
698 def _init_command_handlers(self):
699 if not self.ipcmd:
fc5e1735 700 self.ipcmd = iproute2()
15ef32ea 701
6e16e5ae 702 def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
15ef32ea
RP
703 """ run address configuration on the interface object passed as argument
704
705 Args:
706 **ifaceobj** (object): iface object
707
708 **operation** (str): any of 'up', 'down', 'query-checkcurr',
709 'query-running'
710 Kwargs:
711 query_ifaceobj (object): query check ifaceobject. This is only
712 valid when op is 'query-checkcurr'. It is an object same as
713 ifaceobj, but contains running attribute values and its config
714 status. The modules can use it to return queried running state
715 of interfaces. status is success if the running state is same
716 as user required state in ifaceobj. error otherwise.
717 """
8e113d63
RP
718 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
719 return
15ef32ea
RP
720 op_handler = self._run_ops.get(operation)
721 if not op_handler:
722 return
15ef32ea
RP
723 self._init_command_handlers()
724 if operation == 'query-checkcurr':
0582f185
RP
725 op_handler(self, ifaceobj, query_ifaceobj,
726 ifaceobj_getfunc=ifaceobj_getfunc)
15ef32ea 727 else:
0582f185
RP
728 op_handler(self, ifaceobj,
729 ifaceobj_getfunc=ifaceobj_getfunc)