]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/address.py
addons: address: if hwaddress changed delete old fdb entry
[mirror_ifupdown2.git] / ifupdown2 / addons / address.py
CommitLineData
15ef32ea
RP
1#!/usr/bin/python
2#
d486dd0d 3# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
15ef32ea
RP
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6
007cae35
JF
7import socket
8
d486dd0d 9from ipaddr import IPNetwork, IPv4Network, IPv6Network, _BaseV6
9087e727 10
15ef32ea 11try:
d486dd0d
JF
12 from ifupdown2.ifupdown.iface import *
13 from ifupdown2.ifupdown.utils import utils
14 from ifupdown2.ifupdown.netlink import netlink
15
16 from ifupdown2.ifupdownaddons.dhclient import dhclient
17 from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
18 from ifupdown2.ifupdownaddons.modulebase import moduleBase
19
20 import ifupdown2.ifupdown.statemanager as statemanager
21 import ifupdown2.ifupdown.policymanager as policymanager
22 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
23 import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
24except ImportError:
15ef32ea 25 from ifupdown.iface import *
82908a2d 26 from ifupdown.utils import utils
d486dd0d
JF
27 from ifupdown.netlink import netlink
28
15ef32ea 29 from ifupdownaddons.dhclient import dhclient
d486dd0d
JF
30 from ifupdownaddons.LinkUtils import LinkUtils
31 from ifupdownaddons.modulebase import moduleBase
32
33 import ifupdown.statemanager as statemanager
84f33af6 34 import ifupdown.policymanager as policymanager
fc5e1735 35 import ifupdown.ifupdownflags as ifupdownflags
d486dd0d
JF
36 import ifupdown.ifupdownconfig as ifupdownconfig
37
15ef32ea
RP
38
39class address(moduleBase):
40 """ ifupdown2 addon module to configure address, mtu, hwaddress, alias
41 (description) on an interface """
42
43 _modinfo = {'mhelp' : 'address configuration module for interfaces',
44 'attrs': {
45 'address' :
46 {'help' : 'ipv4 or ipv6 addresses',
482b2fab 47 'validvals' : ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
c6370b56 48 'multiline' : True,
15ef32ea
RP
49 'example' : ['address 10.0.12.3/24',
50 'address 2000:1000:1000:1000:3::5/128']},
51 'netmask' :
52 {'help': 'netmask',
53 'example' : ['netmask 255.255.255.0'],
54 'compat' : True},
55 'broadcast' :
56 {'help': 'broadcast address',
482b2fab 57 'validvals' : ['<ipv4>', ],
15ef32ea
RP
58 'example' : ['broadcast 10.0.1.255']},
59 'scope' :
60 {'help': 'scope',
c6370b56 61 'validvals' : ['universe', 'site', 'link', 'host', 'nowhere'],
15ef32ea
RP
62 'example' : ['scope host']},
63 'preferred-lifetime' :
64 {'help': 'preferred lifetime',
c6370b56 65 'validrange' : ['0', '65535'],
15ef32ea
RP
66 'example' : ['preferred-lifetime forever',
67 'preferred-lifetime 10']},
68 'gateway' :
69 {'help': 'default gateway',
482b2fab 70 'validvals' : ['<ipv4>', '<ipv6>'],
2ed2adeb 71 'multiline' : True,
15ef32ea
RP
72 'example' : ['gateway 255.255.255.0']},
73 'mtu' :
74 { 'help': 'interface mtu',
c6370b56 75 'validrange' : ['552', '9216'],
15ef32ea
RP
76 'example' : ['mtu 1600'],
77 'default' : '1500'},
78 'hwaddress' :
79 {'help' : 'hw address',
c6370b56 80 'validvals' : ['<mac>',],
15ef32ea
RP
81 'example': ['hwaddress 44:38:39:00:27:b8']},
82 'alias' :
83 { 'help': 'description/alias',
394e68b5
RP
84 'example' : ['alias testnetwork']},
85 'address-purge' :
86 { 'help': 'purge existing addresses. By default ' +
87 'any existing ip addresses on an interface are ' +
88 'purged to match persistant addresses in the ' +
89 'interfaces file. Set this attribute to \'no\'' +
90 'if you want to preserve existing addresses',
c6370b56 91 'validvals' : ['yes', 'no'],
394e68b5 92 'default' : 'yes',
a794fb31
BR
93 'example' : ['address-purge yes/no']},
94 'clagd-vxlan-anycast-ip' :
95 { 'help' : 'Anycast local IP address for ' +
96 'dual connected VxLANs',
482b2fab 97 'validvals' : ['<ipv4>', ],
d486dd0d
JF
98 'example' : ['clagd-vxlan-anycast-ip 36.0.0.11']},
99 'ip-forward' :
100 { 'help': 'ip forwarding flag',
7b444c7c 101 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
d486dd0d
JF
102 'default' : 'off',
103 'example' : ['ip-forward off']},
104 'ip6-forward' :
105 { 'help': 'ipv6 forwarding flag',
7b444c7c 106 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
d486dd0d
JF
107 'default' : 'off',
108 'example' : ['ip6-forward off']},
109 'mpls-enable' :
110 { 'help': 'mpls enable flag',
111 'validvals': ['yes', 'no'],
112 'default' : 'no',
113 'example' : ['mpls-enable yes']},
3fc54eef
JF
114 'ipv6-addrgen': {
115 'help': 'enable disable ipv6 link addrgenmode',
116 'validvals': ['on', 'off'],
117 'default': 'on',
118 'example': [
119 'ipv6-addrgen on',
120 'ipv6-addrgen off'
121 ]
122 }
d486dd0d 123 }}
15ef32ea
RP
124
125 def __init__(self, *args, **kargs):
126 moduleBase.__init__(self, *args, **kargs)
127 self.ipcmd = None
8e113d63 128 self._bridge_fdb_query_cache = {}
84f33af6 129 self.default_mtu = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='mtu')
9f30b2cc 130 self.max_mtu = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='max_mtu')
d486dd0d
JF
131 self.ipforward = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='ip-forward')
132 self.ip6forward = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='ip6-forward')
133 self.ifaces_defaults = policymanager.policymanager_api.get_iface_defaults(module_name=self.__class__.__name__)
134 self.enable_l3_iface_forwarding_checks = utils.get_boolean_from_string(
135 policymanager.policymanager_api.get_module_globals(
136 self.__class__.__name__,
137 'enable_l3_iface_forwarding_checks'
138 )
139 )
9f30b2cc
RP
140
141 if not self.default_mtu:
142 self.default_mtu = '1500'
143
144 self.logger.info('address: using default mtu %s' %self.default_mtu)
145
146 if self.max_mtu:
147 self.logger.info('address: using max mtu %s' %self.max_mtu)
15ef32ea 148
d486dd0d
JF
149 self.lower_iface_mtu_checked_list = list()
150
8b57a467
JF
151 self.l3_intf_arp_accept = utils.get_boolean_from_string(
152 policymanager.policymanager_api.get_module_globals(
153 module_name=self.__class__.__name__,
154 attr='l3_intf_arp_accept'
155 ),
156 default=False
157 )
158
9d505185
JF
159 self.l3_intf_default_gateway_set_onlink = utils.get_boolean_from_string(
160 policymanager.policymanager_api.get_module_globals(
161 module_name=self.__class__.__name__,
162 attr='l3_intf_default_gateway_set_onlink'
163 ),
164 default=True
165 )
166
09096420 167 def syntax_check(self, ifaceobj, ifaceobj_getfunc=None):
22b49c28 168 return (self.syntax_check_multiple_gateway(ifaceobj)
09096420 169 and self.syntax_check_addr_allowed_on(ifaceobj, True)
d486dd0d
JF
170 and self.syntax_check_mtu(ifaceobj, ifaceobj_getfunc)
171 and self.syntax_check_sysctls(ifaceobj)
172 and self.syntax_check_enable_l3_iface_forwardings(ifaceobj, ifaceobj_getfunc, syntax_check=True))
173
174 def syntax_check_enable_l3_iface_forwardings(self, ifaceobj, ifaceobj_getfunc, syntax_check=False):
175 if (self.enable_l3_iface_forwarding_checks
176 and (ifaceobj.link_kind & ifaceLinkKind.VLAN
177 or ifaceobj.link_kind & ifaceLinkKind.BRIDGE)
178 and not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
179
180 ifname = ifaceobj.name
181 vlan_addr = None
182 vlan_ipforward_off = None
183
184 for obj in ifaceobj_getfunc(ifname) or [ifaceobj]:
185 if not vlan_addr:
186 vlan_addr = obj.get_attr_value('address')
187
188 if not vlan_ipforward_off:
189 ip_forward_value = obj.get_attr_value_first('ip-forward')
190
191 if ip_forward_value and not utils.get_boolean_from_string(ip_forward_value):
192 vlan_ipforward_off = True
193
194 if vlan_addr and vlan_ipforward_off:
195 if syntax_check:
196 raise Exception(
197 'configuring ip-forward off and ip address(es) (%s) is not compatible'
198 % (', '.join(vlan_addr))
199 )
200 else:
201 raise Exception(
202 '%s: configuring ip-forward off and ip address(es) (%s) is not compatible'
203 % (ifname, ', '.join(vlan_addr))
204 )
205
206 return True
207
208 def syntax_check_sysctls(self, ifaceobj):
209 result = True
210 bridge_port = (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT)
211 ipforward = ifaceobj.get_attr_value_first('ip-forward')
212 if bridge_port and ipforward:
213 result = False
214 self.log_error('%s: \'ip-forward\' is not supported for '
215 'bridge port' %ifaceobj.name)
216 ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
217 if bridge_port and ip6forward:
218 result = False
219 self.log_error('%s: \'ip6-forward\' is not supported for '
220 'bridge port' %ifaceobj.name)
221 return result
09096420
RP
222
223 def syntax_check_mtu(self, ifaceobj, ifaceobj_getfunc):
224 mtu = ifaceobj.get_attr_value_first('mtu')
225 if mtu:
226 return self._check_mtu_config(ifaceobj, mtu, ifaceobj_getfunc,
227 syntaxcheck=True)
228 return True
22b49c28
JF
229
230 def syntax_check_addr_allowed_on(self, ifaceobj, syntax_check=False):
231 if ifaceobj.get_attr_value('address'):
232 return utils.is_addr_ip_allowed_on(ifaceobj, syntax_check=syntax_check)
233 return True
234
38365d4a
JF
235 def _syntax_check_multiple_gateway(self, family, found, addr, type_obj):
236 if type(IPNetwork(addr)) == type_obj:
237 if found:
238 raise Exception('%s: multiple gateways for %s family'
239 % (addr, family))
240 return True
241 return False
242
22b49c28 243 def syntax_check_multiple_gateway(self, ifaceobj):
38365d4a
JF
244 result = True
245 inet = False
246 inet6 = False
247 gateways = ifaceobj.get_attr_value('gateway')
248 for addr in gateways if gateways else []:
249 try:
250 if self._syntax_check_multiple_gateway('inet', inet, addr,
251 IPv4Network):
252 inet = True
253 if self._syntax_check_multiple_gateway('inet6', inet6, addr,
254 IPv6Network):
255 inet6 = True
256 except Exception as e:
257 self.logger.warning('%s: address: %s' % (ifaceobj.name, str(e)))
258 result = False
259 return result
260
75afe2a7
RP
261 def _address_valid(self, addrs):
262 if not addrs:
263 return False
264 if any(map(lambda a: True if a[:7] != '0.0.0.0'
265 else False, addrs)):
266 return True
267 return False
268
428206bf 269 def _get_hwaddress(self, ifaceobj):
d486dd0d 270 return utils.strip_hwaddress(ifaceobj.get_attr_value_first('hwaddress'))
428206bf
JF
271
272 def _process_bridge(self, ifaceobj, up):
273 hwaddress = self._get_hwaddress(ifaceobj)
75afe2a7
RP
274 addrs = ifaceobj.get_attr_value_first('address')
275 is_vlan_dev_on_vlan_aware_bridge = False
276 is_bridge = self.ipcmd.is_bridge(ifaceobj.name)
277 if not is_bridge:
d486dd0d
JF
278 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
279 bridgename = ifaceobj.lowerifaces[0]
280 vlan = self._get_vlan_id(ifaceobj)
75afe2a7 281 is_vlan_dev_on_vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridgename)
8c2c9f26
RP
282 if ((is_bridge and not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name))
283 or is_vlan_dev_on_vlan_aware_bridge):
8b57a467
JF
284 if self._address_valid(addrs):
285 if self.l3_intf_arp_accept:
286 if up:
287 self.write_file('/proc/sys/net/ipv4/conf/%s' % ifaceobj.name +
288 '/arp_accept', '1')
289 else:
290 self.write_file('/proc/sys/net/ipv4/conf/%s' % ifaceobj.name +
291 '/arp_accept', '0')
292 else:
293 self.write_file('/proc/sys/net/ipv4/conf/%s/arp_accept' % ifaceobj.name, '0')
75afe2a7 294 if hwaddress and is_vlan_dev_on_vlan_aware_bridge:
15897163
JF
295 if up:
296 # check statemanager to delete the old entry if necessary
297 try:
298 for old_obj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
299 old_hwaddress = old_obj.get_attr_value_first("hwaddress")
300 if old_hwaddress and self.ipcmd.mac_str_to_int(old_hwaddress) != self.ipcmd.mac_str_to_int(hwaddress):
301 self.ipcmd.bridge_fdb_del(bridgename, old_hwaddress, vlan)
302 break
303 except:
304 pass
305 self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan)
306 else:
307 self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan)
cb46a208 308
0582f185
RP
309 def _get_anycast_addr(self, ifaceobjlist):
310 for ifaceobj in ifaceobjlist:
311 anycast_addr = ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip')
312 if anycast_addr:
313 anycast_addr = anycast_addr+'/32'
314 return anycast_addr
315 return None
316
317 def _inet_address_convert_to_cidr(self, ifaceobjlist):
15ef32ea 318 newaddrs = []
0582f185
RP
319 newaddr_attrs = {}
320
321 for ifaceobj in ifaceobjlist:
322 addrs = ifaceobj.get_attr_value('address')
323 if not addrs:
324 continue
325
22b49c28
JF
326 if not self.syntax_check_addr_allowed_on(ifaceobj,
327 syntax_check=False):
0582f185 328 return (False, newaddrs, newaddr_attrs)
15ef32ea
RP
329 # If user address is not in CIDR notation, convert them to CIDR
330 for addr_index in range(0, len(addrs)):
331 addr = addrs[addr_index]
8de397ef 332 newaddr = addr
15ef32ea
RP
333 if '/' in addr:
334 newaddrs.append(addr)
42ae7838 335 else:
8de397ef
MW
336 netmask = ifaceobj.get_attr_value_n('netmask', addr_index)
337 if netmask:
338 prefixlen = IPNetwork('%s' %addr +
339 '/%s' %netmask).prefixlen
340 newaddr = addr + '/%s' %prefixlen
341 else:
342 # we are here because there is no slash (/xx) and no netmask
343 # just let IPNetwork handle the ipv4 or ipv6 address mask
344 prefixlen = IPNetwork(addr).prefixlen
345 newaddr = addr + '/%s' %prefixlen
346 newaddrs.append(newaddr)
15ef32ea 347
0582f185
RP
348 attrs = {}
349 for a in ['broadcast', 'pointopoint', 'scope',
350 'preferred-lifetime']:
351 aval = ifaceobj.get_attr_value_n(a, addr_index)
352 if aval:
72c964c2 353 attrs[a] = aval
0582f185
RP
354
355 if attrs:
356 newaddr_attrs[newaddr]= attrs
357 return (True, newaddrs, newaddr_attrs)
358
77021aa1
RP
359 def _inet_address_list_config(self, ifaceobj, newaddrs, newaddr_attrs):
360 for addr_index in range(0, len(newaddrs)):
361 try:
362 if newaddr_attrs:
363 self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index],
364 newaddr_attrs.get(newaddrs[addr_index],
365 {}).get('broadcast'),
366 newaddr_attrs.get(newaddrs[addr_index],
367 {}).get('pointopoint'),
368 newaddr_attrs.get(newaddrs[addr_index],
369 {}).get('scope'),
370 newaddr_attrs.get(newaddrs[addr_index],
371 {}).get('preferred-lifetime'))
372 else:
373 self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index])
374 except Exception, e:
bf3eda91 375 self.log_error(str(e), ifaceobj)
77021aa1
RP
376
377 def _inet_address_config(self, ifaceobj, ifaceobj_getfunc=None,
378 force_reapply=False):
0582f185 379 squash_addr_config = (True if \
d486dd0d
JF
380 ifupdownconfig.config.get('addr_config_squash', \
381 '0') == '1' else False)
0582f185
RP
382
383 if (squash_addr_config and
384 not (ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING)):
385 return
386
387 purge_addresses = ifaceobj.get_attr_value_first('address-purge')
388 if not purge_addresses:
389 purge_addresses = 'yes'
390
391 if squash_addr_config and ifaceobj.flags & iface.HAS_SIBLINGS:
392 ifaceobjlist = ifaceobj_getfunc(ifaceobj.name)
393 else:
394 ifaceobjlist = [ifaceobj]
395
d486dd0d
JF
396 module_name = self.__class__.__name__
397 ifname = ifaceobj.name
398
0582f185 399 (addr_supported, newaddrs, newaddr_attrs) = self._inet_address_convert_to_cidr(ifaceobjlist)
d486dd0d
JF
400 newaddrs = utils.get_ip_objs(module_name, ifname, newaddrs)
401
0582f185
RP
402 if not addr_supported:
403 return
404 if (not squash_addr_config and (ifaceobj.flags & iface.HAS_SIBLINGS)):
405 # if youngest sibling and squash addr is not set
406 # print a warning that addresses will not be purged
407 if (ifaceobj.flags & iface.YOUNGEST_SIBLING):
408 self.logger.warn('%s: interface has multiple ' %ifaceobj.name +
409 'iface stanzas, skip purging existing addresses')
410 purge_addresses = 'no'
411
fc5e1735 412 if not ifupdownflags.flags.PERFMODE and purge_addresses == 'yes':
0582f185
RP
413 # if perfmode is not set and purge addresses is not set to 'no'
414 # lets purge addresses not in the config
d486dd0d 415 runningaddrs = self.ipcmd.get_running_addrs(ifaceobj, details=False)
0582f185 416
a794fb31
BR
417 # if anycast address is configured on 'lo' and is in running config
418 # add it to newaddrs so that ifreload doesn't wipe it out
82908a2d 419 anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, self._get_anycast_addr(ifaceobjlist))
0582f185 420
a794fb31
BR
421 if runningaddrs and anycast_addr and anycast_addr in runningaddrs:
422 newaddrs.append(anycast_addr)
d486dd0d
JF
423
424 user_ip4, user_ip6, newaddrs = self.order_user_configured_addrs(newaddrs)
425
426 if newaddrs == runningaddrs or self.compare_running_ips_and_user_config(user_ip4, user_ip6, runningaddrs):
77021aa1
RP
427 if force_reapply:
428 self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
15ef32ea
RP
429 return
430 try:
431 # if primary address is not same, there is no need to keep any.
432 # reset all addresses
d486dd0d
JF
433 if newaddrs and runningaddrs and newaddrs[0] != runningaddrs[0]:
434 skip_addrs = []
15ef32ea 435 else:
d486dd0d
JF
436 skip_addrs = newaddrs or []
437 for addr in runningaddrs or []:
438 if addr in skip_addrs:
439 continue
440 self.ipcmd.addr_del(ifaceobj.name, addr)
15ef32ea
RP
441 except Exception, e:
442 self.log_warn(str(e))
443 if not newaddrs:
444 return
77021aa1 445 self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
15ef32ea 446
d486dd0d
JF
447 def compare_running_ips_and_user_config(self, user_ip4, user_ip6, running_addrs):
448 """
449 We need to compare the user config ips and the running ips.
450 ip4 ordering matters (primary etc) but ip6 order doesn't matter
451
452 this function replaces the strict comparison previously in place
453 if newaddrs == running_addrs ?
454
455 We will compare if the ip4 ordering is correct, then check if all
456 ip6 are present in the list (without checking the ordering)
457 """
458 if (user_ip4 or user_ip6) and not running_addrs:
459 return False
460 elif running_addrs and not user_ip4 and not user_ip6:
461 return False
462 elif not running_addrs and not user_ip4 and not user_ip6:
463 return True
464
465 len_ip4 = len(user_ip4)
466 len_running_addrs = len(running_addrs)
467
468 if len_ip4 > len_running_addrs:
469 return False
470
471 i = 0
472 while i < len_ip4:
473 if user_ip4[i] != running_addrs[i]:
474 return False
475 i += 1
476
477 if len_ip4 > 0:
478 running_ip6 = running_addrs[len_ip4:]
479 else:
480 running_ip6 = running_addrs
481
482 i = 0
483 len_ip6 = len(user_ip6)
484
485 for ip6 in running_ip6:
486 if ip6 not in user_ip6:
487 return False
488 i += 1
489
490 return i == len_ip6
491
492 def order_user_configured_addrs(self, user_config_addrs):
493 ip4 = []
494 ip6 = []
495
496 for a in user_config_addrs:
497 if isinstance(a, _BaseV6):
498 ip6.append(str(a))
499 else:
500 ip4.append(str(a))
501
502 return ip4, ip6, ip4 + ip6
503
504 def _delete_gateway(self, ifaceobj, gateways, vrf, metric):
505 for del_gw in gateways:
0232d1bb
N
506 try:
507 self.ipcmd.route_del_gateway(ifaceobj.name, del_gw, vrf, metric)
5b666749
JF
508 except Exception as e:
509 self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
d486dd0d
JF
510
511 def _add_delete_gateway(self, ifaceobj, gateways=[], prev_gw=[]):
512 vrf = ifaceobj.get_attr_value_first('vrf')
513 metric = ifaceobj.get_attr_value_first('metric')
514 self._delete_gateway(ifaceobj, list(set(prev_gw) - set(gateways)),
515 vrf, metric)
4b875c17 516 for add_gw in gateways:
0232d1bb 517 try:
9d505185 518 self.ipcmd.route_add_gateway(ifaceobj.name, add_gw, vrf, metric, onlink=self.l3_intf_default_gateway_set_onlink)
5b666749
JF
519 except Exception as e:
520 self.log_error('%s: %s' % (ifaceobj.name, str(e)))
0232d1bb
N
521
522 def _get_prev_gateway(self, ifaceobj, gateways):
523 ipv = []
524 saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name)
525 if not saved_ifaceobjs:
526 return ipv
527 prev_gateways = saved_ifaceobjs[0].get_attr_value('gateway')
528 if not prev_gateways:
529 return ipv
530 return prev_gateways
531
8d1e346f
RP
532 def _check_mtu_config(self, ifaceobj, mtu, ifaceobj_getfunc, syntaxcheck=False):
533 retval = True
534 if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
535 if syntaxcheck:
536 self.logger.warn('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj.name)
537 retval = False
538 else:
9f30b2cc 539 self.logger.info('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj.name)
8d1e346f
RP
540 elif ifaceobj_getfunc:
541 if ((ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and
542 ifaceobj.upperifaces):
9f30b2cc
RP
543 masterobj = ifaceobj_getfunc(ifaceobj.upperifaces[0])
544 if masterobj:
545 master_mtu = masterobj[0].get_attr_value_first('mtu')
546 if master_mtu and master_mtu != mtu:
8d1e346f
RP
547 if syntaxcheck:
548 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))
549 retval = False
550 else:
551 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))
552 elif ((ifaceobj.link_kind & ifaceLinkKind.VLAN) and
553 ifaceobj.lowerifaces):
554 lowerobj = ifaceobj_getfunc(ifaceobj.lowerifaces[0])
555 if lowerobj:
556 if syntaxcheck:
557 lowerdev_mtu = lowerobj[0].get_attr_value_first('mtu')
558 else:
d486dd0d 559 lowerdev_mtu = self.ipcmd.link_get_mtu_sysfs(lowerobj[0].name)
8d1e346f
RP
560 if lowerdev_mtu and int(mtu) > int(lowerdev_mtu):
561 self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
562 %(ifaceobj.name, mtu, lowerobj[0].name, lowerdev_mtu))
563 retval = False
564 elif (not lowerobj[0].link_kind and
565 not (lowerobj[0].link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
d486dd0d
JF
566 not lowerdev_mtu and self.default_mtu and
567 (int(mtu) > int(self.default_mtu))):
8d1e346f
RP
568 # only check default mtu on lower device which is a physical interface
569 self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
570 %(ifaceobj.name, mtu, lowerobj[0].name, self.default_mtu))
571 retval = False
9f30b2cc
RP
572 if self.max_mtu and mtu > self.max_mtu:
573 self.logger.warn('%s: specified mtu %s is greater than max mtu %s'
574 %(ifaceobj.name, mtu, self.max_mtu))
8d1e346f
RP
575 retval = False
576 return retval
577
578 def _propagate_mtu_to_upper_devs(self, ifaceobj, mtu, ifaceobj_getfunc):
579 if (not ifaceobj.upperifaces or
580 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) or
581 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) or
582 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT)):
583 return
584 for u in ifaceobj.upperifaces:
585 upperobjs = ifaceobj_getfunc(u)
586 if (not upperobjs or
587 not (upperobjs[0].link_kind & ifaceLinkKind.VLAN)):
588 continue
589 # only adjust mtu for vlan devices on ifaceobj
590 umtu = upperobjs[0].get_attr_value_first('mtu')
591 if not umtu:
592 running_mtu = self.ipcmd.link_get_mtu(upperobjs[0].name)
593 if not running_mtu or (running_mtu != mtu):
594 self.ipcmd.link_set(u, 'mtu', mtu)
595
d486dd0d 596 def _process_mtu_config(self, ifaceobj, ifaceobj_getfunc, mtu):
8d1e346f
RP
597 if mtu:
598 if not self._check_mtu_config(ifaceobj, mtu, ifaceobj_getfunc):
599 return
d486dd0d
JF
600 cached_running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
601 running_mtu = self.ipcmd.link_get_mtu_sysfs(ifaceobj.name)
8d1e346f 602 if not running_mtu or (running_mtu and running_mtu != mtu):
d486dd0d
JF
603 force = cached_running_mtu != running_mtu
604 self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu, force=force)
8d1e346f
RP
605 if (not ifupdownflags.flags.ALL and
606 not ifaceobj.link_kind and
d486dd0d 607 ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'):
8d1e346f
RP
608 # This is additional cost to us, so do it only when
609 # ifupdown2 is called on a particular interface and
610 # it is a physical interface
611 self._propagate_mtu_to_upper_devs(ifaceobj, mtu, ifaceobj_getfunc)
9f30b2cc
RP
612 return
613
614 if ifaceobj.link_kind:
19ee2b11 615 # bonds, vxlan and custom devices (like dummy) need an explicit set of mtu.
9f30b2cc
RP
616 # bridges don't need mtu set
617 if (ifaceobj.link_kind & ifaceLinkKind.BOND or
19ee2b11
JF
618 ifaceobj.link_kind & ifaceLinkKind.VXLAN or
619 ifaceobj.link_kind & ifaceLinkKind.OTHER
620 ):
9f30b2cc
RP
621 running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
622 if (self.default_mtu and running_mtu != self.default_mtu):
623 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
624 return
d486dd0d 625 if (ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'
9f30b2cc
RP
626 and ifaceobj.lowerifaces):
627 # set vlan interface mtu to lower device mtu
628 if (ifaceobj.link_kind & ifaceLinkKind.VLAN):
d486dd0d
JF
629 lower_iface = ifaceobj.lowerifaces[0]
630 if lower_iface not in self.lower_iface_mtu_checked_list:
631 lower_iface_mtu = self.ipcmd.link_get_mtu_sysfs(lower_iface)
632 self.ipcmd.cache_update([lower_iface, 'mtu'], lower_iface_mtu)
633 self.lower_iface_mtu_checked_list.append(lower_iface)
634 else:
635 lower_iface_mtu = self.ipcmd.link_get_mtu(lower_iface)
636
637 if lower_iface_mtu != self.ipcmd.link_get_mtu_sysfs(ifaceobj.name):
9f30b2cc
RP
638 self.ipcmd.link_set_mtu(ifaceobj.name, lower_iface_mtu)
639
640 elif (not (ifaceobj.name == 'lo') and not ifaceobj.link_kind and
641 not (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and
642 self.default_mtu):
643 # logical devices like bridges and vlan devices rely on mtu
644 # from their lower devices. ie mtu travels from
645 # lower devices to upper devices. For bonds mtu travels from
646 # upper to lower devices. running mtu depends on upper and
647 # lower device mtu. With all this implicit mtu
648 # config by the kernel in play, we try to be cautious here
649 # on which devices we want to reset mtu to default.
650 # essentially only physical interfaces which are not bond slaves
651 running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
652 if running_mtu != self.default_mtu:
653 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
654
d486dd0d
JF
655 def _set_bridge_forwarding(self, ifaceobj):
656 """ set ip forwarding to 0 if bridge interface does not have a
657 ip nor svi """
2185a108 658 ifname = ifaceobj.name
d486dd0d 659 if not ifaceobj.upperifaces and not ifaceobj.get_attr_value('address'):
2185a108
JF
660 if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv4") == '1':
661 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv4", 0)
662 if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv6") == '1':
663 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv6", 0)
d486dd0d 664 else:
2185a108
JF
665 if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv4") == '0':
666 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv4", 1)
667 if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv6") == '0':
668 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv6", 1)
669
670 def sysctl_get_forwarding_value_from_proc(self, ifname, family):
671 return self.read_file_oneline("/proc/sys/net/%s/conf/%s/forwarding" % (family, ifname))
672
673 def sysctl_write_forwarding_value_to_proc(self, ifname, family, value):
674 self.write_file("/proc/sys/net/%s/conf/%s/forwarding" % (family, ifname), "%s\n" % value)
d486dd0d
JF
675
676 def _sysctl_config(self, ifaceobj):
677 setting_default_value = False
678 mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
679 if not mpls_enable:
680 setting_default_value = True
681 mpls_enable = self.get_mod_subattr('mpls-enable', 'default')
682 mpls_enable = utils.boolean_support_binary(mpls_enable)
683 # File read has been used for better performance
684 # instead of using sysctl command
685 if ifupdownflags.flags.PERFMODE:
686 running_mpls_enable = '0'
687 else:
688 running_mpls_enable = self.read_file_oneline(
689 '/proc/sys/net/mpls/conf/%s/input'
690 % ifaceobj.name
691 )
692
693 if mpls_enable != running_mpls_enable:
694 try:
695 self.sysctl_set('net.mpls.conf.%s.input'
696 %('/'.join(ifaceobj.name.split("."))),
697 mpls_enable)
698 except Exception as e:
699 if not setting_default_value:
700 ifaceobj.status = ifaceStatus.ERROR
701 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
702
703 if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
704 self._set_bridge_forwarding(ifaceobj)
705 return
706 if not self.syntax_check_sysctls(ifaceobj):
707 return
708 ipforward = ifaceobj.get_attr_value_first('ip-forward')
709 ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
710 if ifupdownflags.flags.PERFMODE:
711 if ipforward:
712 self.sysctl_set('net.ipv4.conf.%s.forwarding'
713 %('/'.join(ifaceobj.name.split("."))),
714 utils.boolean_support_binary(ipforward))
715 if ip6forward:
716 self.sysctl_set('net.ipv6.conf.%s.forwarding'
717 %('/'.join(ifaceobj.name.split("."))),
718 utils.boolean_support_binary(ip6forward))
719 return
720 bridge_port = ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
721 if bridge_port:
722 if ipforward:
723 self.log_error('%s: \'ip-forward\' is not supported for '
724 'bridge port' %ifaceobj.name)
725 if ip6forward:
726 self.log_error('%s: \'ip6-forward\' is not supported for '
727 'bridge port' %ifaceobj.name)
728 return
42ef1cce 729
52712b1a
AD
730 setting_default_value = False
731 if not ipforward:
732 setting_default_value = True
733 ipforward = self.ipforward
734
42ef1cce
AD
735 if ipforward:
736 ipforward = utils.boolean_support_binary(ipforward)
737 # File read has been used for better performance
738 # instead of using sysctl command
739 running_ipforward = self.read_file_oneline(
740 '/proc/sys/net/ipv4/conf/%s/forwarding'
741 %ifaceobj.name)
742
743 if ipforward != running_ipforward:
744 try:
745
746 self.sysctl_set('net.ipv4.conf.%s.forwarding'
747 %('/'.join(ifaceobj.name.split("."))),
748 ipforward)
749 except Exception as e:
52712b1a
AD
750 if not setting_default_value:
751 ifaceobj.status = ifaceStatus.ERROR
752 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
753
754
755 setting_default_value = False
756 if not ip6forward:
757 setting_default_value = True
758 ip6forward = self.ip6forward
d486dd0d 759
42ef1cce
AD
760 if ip6forward:
761 ip6forward = utils.boolean_support_binary(ip6forward)
762 # File read has been used for better performance
763 # instead of using sysctl command
764 running_ip6forward = self.read_file_oneline(
765 '/proc/sys/net/ipv6/conf/%s/forwarding'
766 %ifaceobj.name)
767 if ip6forward != running_ip6forward:
768 try:
769 self.sysctl_set('net.ipv6.conf.%s.forwarding'
770 %('/'.join(ifaceobj.name.split("."))),
771 ip6forward)
772 except Exception as e:
773 # There is chance of ipv6 being removed because of,
774 # for example, setting mtu < 1280
775 # In such cases, log error only if user has configured
776 # ip6-forward
52712b1a
AD
777 if not setting_default_value:
778 ifaceobj.status = ifaceStatus.ERROR
779 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
d486dd0d
JF
780
781 def process_mtu(self, ifaceobj, ifaceobj_getfunc):
782 mtu = ifaceobj.get_attr_value_first('mtu')
783
784 if not mtu:
785 default_iface_mtu = self.ifaces_defaults.get(ifaceobj.name, {}).get('mtu')
786
787 if default_iface_mtu:
788 try:
789 mtu = default_iface_mtu
790 int(default_iface_mtu)
791 except Exception as e:
792 self.logger.warning('%s: MTU value from policy file: %s' % (ifaceobj.name, str(e)))
793 return
794
795 self._process_mtu_config(ifaceobj, ifaceobj_getfunc, mtu)
796
3fc54eef 797 def up_ipv6_addrgen(self, ifaceobj):
007cae35
JF
798 user_configured_ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
799
b306a8b6
JF
800 if not user_configured_ipv6_addrgen and ifupdownflags.flags.PERFMODE:
801 # no need to go further during perfmode (boot)
802 return
803
cd890b06
JF
804 if not user_configured_ipv6_addrgen and ifaceobj.addr_method == 'dhcp':
805 return
806
007cae35 807 if not user_configured_ipv6_addrgen:
17da0561
JF
808 # if user didn't configure ipv6-addrgen, should we reset to default?
809 user_configured_ipv6_addrgen = self.get_attr_default_value('ipv6-addrgen')
007cae35
JF
810
811 ipv6_addrgen_nl = {
812 'on': 0,
813 'yes': 0,
814 '0': 0,
815 'off': 1,
816 'no': 1,
817 '1': 1
818 }.get(user_configured_ipv6_addrgen.lower(), None)
819
820 if ipv6_addrgen_nl is not None:
821 self.ipcmd.ipv6_addrgen(ifaceobj.name, ipv6_addrgen_nl, link_created=True)
822 # link_create=False will flush the addr cache of that intf
823 else:
824 self.logger.warning('%s: invalid value "%s" for attribute ipv6-addrgen' % (ifaceobj.name, user_configured_ipv6_addrgen))
3fc54eef 825
0582f185 826 def _up(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea
RP
827 if not self.ipcmd.link_exists(ifaceobj.name):
828 return
2ff98bb9 829
d486dd0d
JF
830 if not self.syntax_check_enable_l3_iface_forwardings(ifaceobj, ifaceobj_getfunc):
831 return
832
2ff98bb9
JF
833 alias = ifaceobj.get_attr_value_first('alias')
834 current_alias = self.ipcmd.link_get_alias(ifaceobj.name)
835 if alias and alias != current_alias:
836 self.ipcmd.link_set_alias(ifaceobj.name, alias)
837 elif not alias and current_alias:
838 self.ipcmd.link_set_alias(ifaceobj.name, '')
839
d486dd0d
JF
840 self._sysctl_config(ifaceobj)
841
68d9fee0 842 addr_method = ifaceobj.addr_method
77021aa1 843 force_reapply = False
15ef32ea
RP
844 try:
845 # release any stale dhcp addresses if present
77054f7f 846 if (addr_method not in ["dhcp", "ppp"] and not ifupdownflags.flags.PERFMODE and
15ef32ea
RP
847 not (ifaceobj.flags & iface.HAS_SIBLINGS)):
848 # if not running in perf mode and ifaceobj does not have
849 # any sibling iface objects, kill any stale dhclient
850 # processes
75afe2a7 851 dhclientcmd = dhclient()
7c1135ea 852 if dhclientcmd.is_running(ifaceobj.name):
15ef32ea
RP
853 # release any dhcp leases
854 dhclientcmd.release(ifaceobj.name)
77021aa1 855 force_reapply = True
7c1135ea 856 elif dhclientcmd.is_running6(ifaceobj.name):
15ef32ea 857 dhclientcmd.release6(ifaceobj.name)
77021aa1 858 force_reapply = True
15ef32ea
RP
859 except:
860 pass
8e113d63 861
15ef32ea 862 self.ipcmd.batch_start()
3fc54eef
JF
863 self.up_ipv6_addrgen(ifaceobj)
864
77054f7f 865 if addr_method not in ["dhcp", "ppp"]:
77021aa1
RP
866 self._inet_address_config(ifaceobj, ifaceobj_getfunc,
867 force_reapply)
2e2dcdaf
JF
868 else:
869 # remove old addresses added by ifupdown2
870 # (if intf was moved from static config to dhcp)
871 for old_ifaceobj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
872 for addr in old_ifaceobj.get_attr_value("address") or []:
873 self.ipcmd.addr_del(ifaceobj.name, addr)
d486dd0d
JF
874
875 self.process_mtu(ifaceobj, ifaceobj_getfunc)
13e22530 876
093ffa00
JF
877 try:
878 self.ipcmd.batch_commit()
879 except Exception as e:
03092649 880 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj, raise_error=False)
264dcaa0 881
d1477c4b
JF
882 self.up_hwaddress(ifaceobj)
883
884 gateways = ifaceobj.get_attr_value('gateway')
885 if not gateways:
886 gateways = []
887 prev_gw = self._get_prev_gateway(ifaceobj, gateways)
888 self._add_delete_gateway(ifaceobj, gateways, prev_gw)
889
890 def up_hwaddress(self, ifaceobj):
68d9fee0 891 try:
707aeb73 892 hwaddress = self._get_hwaddress(ifaceobj)
d1477c4b 893
707aeb73 894 if hwaddress:
d1477c4b 895 if not ifupdownflags.flags.PERFMODE: # system is clean
707aeb73 896 running_hwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
d1477c4b
JF
897 else:
898 running_hwaddress = None
899
900 if self.ipcmd.mac_str_to_int(running_hwaddress) != self.ipcmd.mac_str_to_int(hwaddress):
707aeb73
JF
901 slave_down = False
902 netlink.link_set_updown(ifaceobj.name, "down")
903 if ifaceobj.link_kind & ifaceLinkKind.BOND:
904 # if bond, down all the slaves
905 if ifaceobj.lowerifaces:
906 for l in ifaceobj.lowerifaces:
907 netlink.link_set_updown(l, "down")
908 slave_down = True
909 try:
d1477c4b 910 self.ipcmd.link_set_hwaddress(ifaceobj.name, hwaddress, force=True)
707aeb73
JF
911 finally:
912 netlink.link_set_updown(ifaceobj.name, "up")
913 if slave_down:
914 for l in ifaceobj.lowerifaces:
915 netlink.link_set_updown(l, "up")
916
68d9fee0
RP
917 # Handle special things on a bridge
918 self._process_bridge(ifaceobj, True)
919 except Exception, e:
d1477c4b 920 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
15ef32ea 921
0582f185 922 def _down(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea
RP
923 try:
924 if not self.ipcmd.link_exists(ifaceobj.name):
925 return
68d9fee0 926 addr_method = ifaceobj.addr_method
77054f7f 927 if addr_method not in ["dhcp", "ppp"]:
aa052170
N
928 if ifaceobj.get_attr_value_first('address-purge')=='no':
929 addrlist = ifaceobj.get_attr_value('address')
930 for addr in addrlist:
931 self.ipcmd.addr_del(ifaceobj.name, addr)
932 #self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0])
d486dd0d
JF
933 elif not ifaceobj.link_kind:
934 # for logical interfaces we don't need to remove the ip addresses
935 # kernel will do it for us on 'ip link del'
aa052170 936 self.ipcmd.del_addr_all(ifaceobj.name)
d486dd0d
JF
937 gateways = ifaceobj.get_attr_value('gateway')
938 if gateways:
939 self._delete_gateway(ifaceobj, gateways,
940 ifaceobj.get_attr_value_first('vrf'),
941 ifaceobj.get_attr_value_first('metric'))
84f33af6 942 mtu = ifaceobj.get_attr_value_first('mtu')
00c12960
RP
943 if (not ifaceobj.link_kind and mtu and
944 self.default_mtu and (mtu != self.default_mtu)):
84f33af6 945 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
15ef32ea
RP
946 alias = ifaceobj.get_attr_value_first('alias')
947 if alias:
d486dd0d 948 self.write_file('/sys/class/net/%s/ifalias' % ifaceobj.name, '\n')
75afe2a7
RP
949 # XXX hwaddress reset cannot happen because we dont know last
950 # address.
951
952 # Handle special things on a bridge
953 self._process_bridge(ifaceobj, False)
15ef32ea 954 except Exception, e:
bcf11b14
RP
955 self.logger.debug('%s : %s' %(ifaceobj.name, str(e)))
956 pass
15ef32ea
RP
957
958 def _get_iface_addresses(self, ifaceobj):
959 addrlist = ifaceobj.get_attr_value('address')
960 outaddrlist = []
961
962 if not addrlist: return None
963 for addrindex in range(0, len(addrlist)):
964 addr = addrlist[addrindex]
965 netmask = ifaceobj.get_attr_value_n('netmask', addrindex)
966 if netmask:
967 prefixlen = IPNetwork('%s' %addr +
968 '/%s' %netmask).prefixlen
969 addr = addr + '/%s' %prefixlen
970 outaddrlist.append(addr)
971 return outaddrlist
972
8e113d63
RP
973 def _get_bridge_fdbs(self, bridgename, vlan):
974 fdbs = self._bridge_fdb_query_cache.get(bridgename)
975 if not fdbs:
976 fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
977 if not fdbs:
978 return
979 self._bridge_fdb_query_cache[bridgename] = fdbs
980 return fdbs.get(vlan)
981
982 def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
983 """ If the device is a bridge, make sure the addresses
984 are in the bridge """
d486dd0d
JF
985 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
986 bridgename = ifaceobj.lowerifaces[0]
987 vlan = self._get_vlan_id(ifaceobj)
8e113d63 988 if self.ipcmd.bridge_is_vlan_aware(bridgename):
d1477c4b
JF
989 fdb_addrs = [self.ipcmd.mac_str_to_int(fdb_addr) for fdb_addr in self._get_bridge_fdbs(bridgename, str(vlan))]
990 if not fdb_addrs:
991 return False
992 hwaddress_int = self.ipcmd.mac_str_to_int(hwaddress)
993 if hwaddress_int not in fdb_addrs:
994 return False
8e113d63
RP
995 return True
996
d486dd0d
JF
997 def _query_sysctl(self, ifaceobj, ifaceobjcurr):
998 bridge_port = ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
999 ipforward = ifaceobj.get_attr_value_first('ip-forward')
1000 if ipforward:
1001 if bridge_port:
1002 ifaceobjcurr.status = ifaceStatus.ERROR
1003 ifaceobjcurr.status_str = ('\'ip-forward\' not supported ' +
1004 'for bridge port')
1005 ifaceobjcurr.update_config_with_status('ip-forward', 1, None)
1006 else:
1007 running_ipforward = self.read_file_oneline(
1008 '/proc/sys/net/ipv4/conf/%s/forwarding'
1009 %ifaceobj.name)
307e814c
JF
1010 running_ipforward = utils.get_boolean_from_string(running_ipforward)
1011 config_ipforward = utils.get_boolean_from_string(ipforward)
1012 ifaceobjcurr.update_config_with_status(
1013 'ip-forward',
1014 'on' if running_ipforward else 'off',
1015 running_ipforward != config_ipforward
1016 )
d486dd0d
JF
1017
1018 ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
1019 if ip6forward:
1020 if bridge_port:
1021 ifaceobjcurr.status = ifaceStatus.ERROR
1022 ifaceobjcurr.status_str = ('\'ip6-forward\' not supported ' +
1023 'for bridge port')
1024 ifaceobjcurr.update_config_with_status('ip6-forward', 1, None)
1025 else:
1026 running_ip6forward = self.read_file_oneline(
1027 '/proc/sys/net/ipv6/conf/%s/forwarding'
1028 %ifaceobj.name)
307e814c
JF
1029 running_ip6forward = utils.get_boolean_from_string(running_ip6forward)
1030 config_ip6forward = utils.get_boolean_from_string(ip6forward)
1031 ifaceobjcurr.update_config_with_status(
1032 'ip6-forward',
1033 'on' if running_ip6forward else 'off',
1034 running_ip6forward != config_ip6forward
1035 )
d486dd0d
JF
1036 mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
1037 if mpls_enable:
1038 running_mpls_enable = self.read_file_oneline(
1039 '/proc/sys/net/mpls/conf/%s/input'
1040 %ifaceobj.name)
1041 running_mpls_enable = utils.get_yesno_from_onezero(
1042 running_mpls_enable)
1043 ifaceobjcurr.update_config_with_status('mpls-enable',
1044 running_mpls_enable,
1045 mpls_enable != running_mpls_enable)
1046 return
1047
007cae35
JF
1048 def query_check_ipv6_addrgen(self, ifaceobj, ifaceobjcurr):
1049 ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
1050
1051 if not ipv6_addrgen:
1052 return
1053
1054 if ipv6_addrgen in utils._string_values:
1055 ifaceobjcurr.update_config_with_status(
1056 'ipv6-addrgen',
1057 ipv6_addrgen,
1058 utils.get_boolean_from_string(ipv6_addrgen) == self.ipcmd.get_ipv6_addrgen_mode(ifaceobj.name)
1059 )
1060 else:
1061 ifaceobjcurr.update_config_with_status('ipv6-addrgen', ipv6_addrgen, 1)
1062
0582f185 1063 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
15ef32ea
RP
1064 runningaddrsdict = None
1065 if not self.ipcmd.link_exists(ifaceobj.name):
1066 self.logger.debug('iface %s not found' %ifaceobj.name)
1067 return
007cae35
JF
1068
1069 self.query_check_ipv6_addrgen(ifaceobj, ifaceobjcurr)
1070
16d854b4 1071 addr_method = ifaceobj.addr_method
15ef32ea
RP
1072 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
1073 'mtu', self.ipcmd.link_get_mtu)
428206bf 1074 hwaddress = self._get_hwaddress(ifaceobj)
8e113d63 1075 if hwaddress:
2876ca35 1076 rhwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
d1477c4b 1077 if not rhwaddress or self.ipcmd.mac_str_to_int(rhwaddress) != self.ipcmd.mac_str_to_int(hwaddress):
8e113d63
RP
1078 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1079 1)
1080 elif not self._check_addresses_in_bridge(ifaceobj, hwaddress):
1081 # XXX: hw address is not in bridge
1082 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1083 1)
1084 ifaceobjcurr.status_str = 'bridge fdb error'
1085 else:
1086 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1087 0)
15ef32ea
RP
1088 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
1089 'alias', self.ipcmd.link_get_alias)
d486dd0d 1090 self._query_sysctl(ifaceobj, ifaceobjcurr)
15ef32ea 1091 # compare addresses
77054f7f 1092 if addr_method in ["dhcp", "ppp"]:
16d854b4 1093 return
82908a2d
JF
1094 addrs = utils.get_normalized_ip_addr(ifaceobj.name,
1095 self._get_iface_addresses(ifaceobj))
d486dd0d 1096 runningaddrsdict = self.ipcmd.get_running_addrs(ifaceobj)
a794fb31
BR
1097 # if anycast address is configured on 'lo' and is in running config
1098 # add it to addrs so that query_check doesn't fail
82908a2d 1099 anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip'))
a794fb31
BR
1100 if anycast_addr:
1101 anycast_addr = anycast_addr+'/32'
1102 if runningaddrsdict and anycast_addr and runningaddrsdict.get(anycast_addr):
1103 addrs.append(anycast_addr)
15ef32ea
RP
1104
1105 # Set ifaceobjcurr method and family
1106 ifaceobjcurr.addr_method = ifaceobj.addr_method
1107 ifaceobjcurr.addr_family = ifaceobj.addr_family
1108 if not runningaddrsdict and not addrs:
1109 return
1110 runningaddrs = runningaddrsdict.keys() if runningaddrsdict else []
8de397ef
MW
1111 # Add /32 netmask to configured address without netmask.
1112 # This may happen on interfaces where pointopoint is used.
1113 runningaddrs = [ addr if '/' in addr else addr + '/32' for addr in runningaddrs]
15ef32ea
RP
1114 if runningaddrs != addrs:
1115 runningaddrsset = set(runningaddrs) if runningaddrs else set([])
1116 addrsset = set(addrs) if addrs else set([])
1117 if (ifaceobj.flags & iface.HAS_SIBLINGS):
1118 if not addrsset:
1119 return
1120 # only check for addresses present in running config
1121 addrsdiff = addrsset.difference(runningaddrsset)
1122 for addr in addrs:
1123 if addr in addrsdiff:
1124 ifaceobjcurr.update_config_with_status('address',
1125 addr, 1)
1126 else:
1127 ifaceobjcurr.update_config_with_status('address',
1128 addr, 0)
1129 else:
1130 addrsdiff = addrsset.symmetric_difference(runningaddrsset)
1131 for addr in addrsset.union(runningaddrsset):
1132 if addr in addrsdiff:
1133 ifaceobjcurr.update_config_with_status('address',
1134 addr, 1)
1135 else:
1136 ifaceobjcurr.update_config_with_status('address',
1137 addr, 0)
1138 elif addrs:
1139 [ifaceobjcurr.update_config_with_status('address',
1140 addr, 0) for addr in addrs]
1141 #XXXX Check broadcast address, scope, etc
1142 return
1143
007cae35
JF
1144 def query_running_ipv6_addrgen(self, ifaceobjrunning):
1145 ipv6_addrgen = self.ipcmd.get_ipv6_addrgen_mode(ifaceobjrunning.name)
1146
1147 if ipv6_addrgen:
1148 ifaceobjrunning.update_config('ipv6-addrgen', 'off')
1149
0582f185 1150 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
15ef32ea
RP
1151 if not self.ipcmd.link_exists(ifaceobjrunning.name):
1152 self.logger.debug('iface %s not found' %ifaceobjrunning.name)
15ef32ea 1153 return
007cae35
JF
1154
1155 self.query_running_ipv6_addrgen(ifaceobjrunning)
1156
15ef32ea
RP
1157 dhclientcmd = dhclient()
1158 if (dhclientcmd.is_running(ifaceobjrunning.name) or
1159 dhclientcmd.is_running6(ifaceobjrunning.name)):
1160 # If dhcp is configured on the interface, we skip it
84f33af6 1161 return
15ef32ea
RP
1162 isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name)
1163 if isloopback:
1164 default_addrs = ['127.0.0.1/8', '::1/128']
004d1e65 1165 ifaceobjrunning.addr_family.append('inet')
15ef32ea
RP
1166 ifaceobjrunning.addr_method = 'loopback'
1167 else:
1168 default_addrs = []
d486dd0d 1169 runningaddrsdict = self.ipcmd.get_running_addrs(ifaceobjrunning)
15ef32ea
RP
1170 if runningaddrsdict:
1171 [ifaceobjrunning.update_config('address', addr)
1172 for addr, addrattrs in runningaddrsdict.items()
1173 if addr not in default_addrs]
1174 mtu = self.ipcmd.link_get_mtu(ifaceobjrunning.name)
1175 if (mtu and
1176 (ifaceobjrunning.name == 'lo' and mtu != '16436') or
1177 (ifaceobjrunning.name != 'lo' and
1178 mtu != self.get_mod_subattr('mtu', 'default'))):
1179 ifaceobjrunning.update_config('mtu', mtu)
1180 alias = self.ipcmd.link_get_alias(ifaceobjrunning.name)
84f33af6 1181 if alias:
15ef32ea
RP
1182 ifaceobjrunning.update_config('alias', alias)
1183
d486dd0d
JF
1184 ipforward = self.read_file_oneline(
1185 '/proc/sys/net/ipv4/conf/%s/forwarding'
1186 %ifaceobjrunning.name)
1187
8d1e346f 1188
15ef32ea
RP
1189 _run_ops = {'up' : _up,
1190 'down' : _down,
1191 'query-checkcurr' : _query_check,
1192 'query-running' : _query_running }
1193
1194 def get_ops(self):
1195 """ returns list of ops supported by this module """
1196 return self._run_ops.keys()
1197
1198 def _init_command_handlers(self):
1199 if not self.ipcmd:
d486dd0d 1200 self.ipcmd = LinkUtils()
15ef32ea 1201
6e16e5ae 1202 def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
15ef32ea
RP
1203 """ run address configuration on the interface object passed as argument
1204
1205 Args:
1206 **ifaceobj** (object): iface object
1207
1208 **operation** (str): any of 'up', 'down', 'query-checkcurr',
1209 'query-running'
1210 Kwargs:
1211 query_ifaceobj (object): query check ifaceobject. This is only
1212 valid when op is 'query-checkcurr'. It is an object same as
1213 ifaceobj, but contains running attribute values and its config
1214 status. The modules can use it to return queried running state
1215 of interfaces. status is success if the running state is same
1216 as user required state in ifaceobj. error otherwise.
1217 """
8e113d63
RP
1218 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
1219 return
15ef32ea
RP
1220 op_handler = self._run_ops.get(operation)
1221 if not op_handler:
1222 return
15ef32ea
RP
1223 self._init_command_handlers()
1224 if operation == 'query-checkcurr':
0582f185
RP
1225 op_handler(self, ifaceobj, query_ifaceobj,
1226 ifaceobj_getfunc=ifaceobj_getfunc)
15ef32ea 1227 else:
0582f185
RP
1228 op_handler(self, ifaceobj,
1229 ifaceobj_getfunc=ifaceobj_getfunc)