]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/address.py
debian: changelog: update 1.2.6-1 entry before release
[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
RP
294 if hwaddress and is_vlan_dev_on_vlan_aware_bridge:
295 if up:
296 self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan)
297 else:
298 self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan)
cb46a208 299
0582f185
RP
300 def _get_anycast_addr(self, ifaceobjlist):
301 for ifaceobj in ifaceobjlist:
302 anycast_addr = ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip')
303 if anycast_addr:
304 anycast_addr = anycast_addr+'/32'
305 return anycast_addr
306 return None
307
308 def _inet_address_convert_to_cidr(self, ifaceobjlist):
15ef32ea 309 newaddrs = []
0582f185
RP
310 newaddr_attrs = {}
311
312 for ifaceobj in ifaceobjlist:
313 addrs = ifaceobj.get_attr_value('address')
314 if not addrs:
315 continue
316
22b49c28
JF
317 if not self.syntax_check_addr_allowed_on(ifaceobj,
318 syntax_check=False):
0582f185 319 return (False, newaddrs, newaddr_attrs)
15ef32ea
RP
320 # If user address is not in CIDR notation, convert them to CIDR
321 for addr_index in range(0, len(addrs)):
322 addr = addrs[addr_index]
8de397ef 323 newaddr = addr
15ef32ea
RP
324 if '/' in addr:
325 newaddrs.append(addr)
42ae7838 326 else:
8de397ef
MW
327 netmask = ifaceobj.get_attr_value_n('netmask', addr_index)
328 if netmask:
329 prefixlen = IPNetwork('%s' %addr +
330 '/%s' %netmask).prefixlen
331 newaddr = addr + '/%s' %prefixlen
332 else:
333 # we are here because there is no slash (/xx) and no netmask
334 # just let IPNetwork handle the ipv4 or ipv6 address mask
335 prefixlen = IPNetwork(addr).prefixlen
336 newaddr = addr + '/%s' %prefixlen
337 newaddrs.append(newaddr)
15ef32ea 338
0582f185
RP
339 attrs = {}
340 for a in ['broadcast', 'pointopoint', 'scope',
341 'preferred-lifetime']:
342 aval = ifaceobj.get_attr_value_n(a, addr_index)
343 if aval:
72c964c2 344 attrs[a] = aval
0582f185
RP
345
346 if attrs:
347 newaddr_attrs[newaddr]= attrs
348 return (True, newaddrs, newaddr_attrs)
349
77021aa1
RP
350 def _inet_address_list_config(self, ifaceobj, newaddrs, newaddr_attrs):
351 for addr_index in range(0, len(newaddrs)):
352 try:
353 if newaddr_attrs:
354 self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index],
355 newaddr_attrs.get(newaddrs[addr_index],
356 {}).get('broadcast'),
357 newaddr_attrs.get(newaddrs[addr_index],
358 {}).get('pointopoint'),
359 newaddr_attrs.get(newaddrs[addr_index],
360 {}).get('scope'),
361 newaddr_attrs.get(newaddrs[addr_index],
362 {}).get('preferred-lifetime'))
363 else:
364 self.ipcmd.addr_add(ifaceobj.name, newaddrs[addr_index])
365 except Exception, e:
bf3eda91 366 self.log_error(str(e), ifaceobj)
77021aa1
RP
367
368 def _inet_address_config(self, ifaceobj, ifaceobj_getfunc=None,
369 force_reapply=False):
0582f185 370 squash_addr_config = (True if \
d486dd0d
JF
371 ifupdownconfig.config.get('addr_config_squash', \
372 '0') == '1' else False)
0582f185
RP
373
374 if (squash_addr_config and
375 not (ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING)):
376 return
377
378 purge_addresses = ifaceobj.get_attr_value_first('address-purge')
379 if not purge_addresses:
380 purge_addresses = 'yes'
381
382 if squash_addr_config and ifaceobj.flags & iface.HAS_SIBLINGS:
383 ifaceobjlist = ifaceobj_getfunc(ifaceobj.name)
384 else:
385 ifaceobjlist = [ifaceobj]
386
d486dd0d
JF
387 module_name = self.__class__.__name__
388 ifname = ifaceobj.name
389
0582f185 390 (addr_supported, newaddrs, newaddr_attrs) = self._inet_address_convert_to_cidr(ifaceobjlist)
d486dd0d
JF
391 newaddrs = utils.get_ip_objs(module_name, ifname, newaddrs)
392
0582f185
RP
393 if not addr_supported:
394 return
395 if (not squash_addr_config and (ifaceobj.flags & iface.HAS_SIBLINGS)):
396 # if youngest sibling and squash addr is not set
397 # print a warning that addresses will not be purged
398 if (ifaceobj.flags & iface.YOUNGEST_SIBLING):
399 self.logger.warn('%s: interface has multiple ' %ifaceobj.name +
400 'iface stanzas, skip purging existing addresses')
401 purge_addresses = 'no'
402
fc5e1735 403 if not ifupdownflags.flags.PERFMODE and purge_addresses == 'yes':
0582f185
RP
404 # if perfmode is not set and purge addresses is not set to 'no'
405 # lets purge addresses not in the config
d486dd0d 406 runningaddrs = self.ipcmd.get_running_addrs(ifaceobj, details=False)
0582f185 407
a794fb31
BR
408 # if anycast address is configured on 'lo' and is in running config
409 # add it to newaddrs so that ifreload doesn't wipe it out
82908a2d 410 anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, self._get_anycast_addr(ifaceobjlist))
0582f185 411
a794fb31
BR
412 if runningaddrs and anycast_addr and anycast_addr in runningaddrs:
413 newaddrs.append(anycast_addr)
d486dd0d
JF
414
415 user_ip4, user_ip6, newaddrs = self.order_user_configured_addrs(newaddrs)
416
417 if newaddrs == runningaddrs or self.compare_running_ips_and_user_config(user_ip4, user_ip6, runningaddrs):
77021aa1
RP
418 if force_reapply:
419 self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
15ef32ea
RP
420 return
421 try:
422 # if primary address is not same, there is no need to keep any.
423 # reset all addresses
d486dd0d
JF
424 if newaddrs and runningaddrs and newaddrs[0] != runningaddrs[0]:
425 skip_addrs = []
15ef32ea 426 else:
d486dd0d
JF
427 skip_addrs = newaddrs or []
428 for addr in runningaddrs or []:
429 if addr in skip_addrs:
430 continue
431 self.ipcmd.addr_del(ifaceobj.name, addr)
15ef32ea
RP
432 except Exception, e:
433 self.log_warn(str(e))
434 if not newaddrs:
435 return
77021aa1 436 self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
15ef32ea 437
d486dd0d
JF
438 def compare_running_ips_and_user_config(self, user_ip4, user_ip6, running_addrs):
439 """
440 We need to compare the user config ips and the running ips.
441 ip4 ordering matters (primary etc) but ip6 order doesn't matter
442
443 this function replaces the strict comparison previously in place
444 if newaddrs == running_addrs ?
445
446 We will compare if the ip4 ordering is correct, then check if all
447 ip6 are present in the list (without checking the ordering)
448 """
449 if (user_ip4 or user_ip6) and not running_addrs:
450 return False
451 elif running_addrs and not user_ip4 and not user_ip6:
452 return False
453 elif not running_addrs and not user_ip4 and not user_ip6:
454 return True
455
456 len_ip4 = len(user_ip4)
457 len_running_addrs = len(running_addrs)
458
459 if len_ip4 > len_running_addrs:
460 return False
461
462 i = 0
463 while i < len_ip4:
464 if user_ip4[i] != running_addrs[i]:
465 return False
466 i += 1
467
468 if len_ip4 > 0:
469 running_ip6 = running_addrs[len_ip4:]
470 else:
471 running_ip6 = running_addrs
472
473 i = 0
474 len_ip6 = len(user_ip6)
475
476 for ip6 in running_ip6:
477 if ip6 not in user_ip6:
478 return False
479 i += 1
480
481 return i == len_ip6
482
483 def order_user_configured_addrs(self, user_config_addrs):
484 ip4 = []
485 ip6 = []
486
487 for a in user_config_addrs:
488 if isinstance(a, _BaseV6):
489 ip6.append(str(a))
490 else:
491 ip4.append(str(a))
492
493 return ip4, ip6, ip4 + ip6
494
495 def _delete_gateway(self, ifaceobj, gateways, vrf, metric):
496 for del_gw in gateways:
0232d1bb
N
497 try:
498 self.ipcmd.route_del_gateway(ifaceobj.name, del_gw, vrf, metric)
5b666749
JF
499 except Exception as e:
500 self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
d486dd0d
JF
501
502 def _add_delete_gateway(self, ifaceobj, gateways=[], prev_gw=[]):
503 vrf = ifaceobj.get_attr_value_first('vrf')
504 metric = ifaceobj.get_attr_value_first('metric')
505 self._delete_gateway(ifaceobj, list(set(prev_gw) - set(gateways)),
506 vrf, metric)
4b875c17 507 for add_gw in gateways:
0232d1bb 508 try:
9d505185 509 self.ipcmd.route_add_gateway(ifaceobj.name, add_gw, vrf, metric, onlink=self.l3_intf_default_gateway_set_onlink)
5b666749
JF
510 except Exception as e:
511 self.log_error('%s: %s' % (ifaceobj.name, str(e)))
0232d1bb
N
512
513 def _get_prev_gateway(self, ifaceobj, gateways):
514 ipv = []
515 saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name)
516 if not saved_ifaceobjs:
517 return ipv
518 prev_gateways = saved_ifaceobjs[0].get_attr_value('gateway')
519 if not prev_gateways:
520 return ipv
521 return prev_gateways
522
8d1e346f
RP
523 def _check_mtu_config(self, ifaceobj, mtu, ifaceobj_getfunc, syntaxcheck=False):
524 retval = True
525 if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
526 if syntaxcheck:
527 self.logger.warn('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj.name)
528 retval = False
529 else:
9f30b2cc 530 self.logger.info('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj.name)
8d1e346f
RP
531 elif ifaceobj_getfunc:
532 if ((ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and
533 ifaceobj.upperifaces):
9f30b2cc
RP
534 masterobj = ifaceobj_getfunc(ifaceobj.upperifaces[0])
535 if masterobj:
536 master_mtu = masterobj[0].get_attr_value_first('mtu')
537 if master_mtu and master_mtu != mtu:
8d1e346f
RP
538 if syntaxcheck:
539 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))
540 retval = False
541 else:
542 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))
543 elif ((ifaceobj.link_kind & ifaceLinkKind.VLAN) and
544 ifaceobj.lowerifaces):
545 lowerobj = ifaceobj_getfunc(ifaceobj.lowerifaces[0])
546 if lowerobj:
547 if syntaxcheck:
548 lowerdev_mtu = lowerobj[0].get_attr_value_first('mtu')
549 else:
d486dd0d 550 lowerdev_mtu = self.ipcmd.link_get_mtu_sysfs(lowerobj[0].name)
8d1e346f
RP
551 if lowerdev_mtu and int(mtu) > int(lowerdev_mtu):
552 self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
553 %(ifaceobj.name, mtu, lowerobj[0].name, lowerdev_mtu))
554 retval = False
555 elif (not lowerobj[0].link_kind and
556 not (lowerobj[0].link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
d486dd0d
JF
557 not lowerdev_mtu and self.default_mtu and
558 (int(mtu) > int(self.default_mtu))):
8d1e346f
RP
559 # only check default mtu on lower device which is a physical interface
560 self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
561 %(ifaceobj.name, mtu, lowerobj[0].name, self.default_mtu))
562 retval = False
9f30b2cc
RP
563 if self.max_mtu and mtu > self.max_mtu:
564 self.logger.warn('%s: specified mtu %s is greater than max mtu %s'
565 %(ifaceobj.name, mtu, self.max_mtu))
8d1e346f
RP
566 retval = False
567 return retval
568
569 def _propagate_mtu_to_upper_devs(self, ifaceobj, mtu, ifaceobj_getfunc):
570 if (not ifaceobj.upperifaces or
571 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) or
572 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) or
573 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT)):
574 return
575 for u in ifaceobj.upperifaces:
576 upperobjs = ifaceobj_getfunc(u)
577 if (not upperobjs or
578 not (upperobjs[0].link_kind & ifaceLinkKind.VLAN)):
579 continue
580 # only adjust mtu for vlan devices on ifaceobj
581 umtu = upperobjs[0].get_attr_value_first('mtu')
582 if not umtu:
583 running_mtu = self.ipcmd.link_get_mtu(upperobjs[0].name)
584 if not running_mtu or (running_mtu != mtu):
585 self.ipcmd.link_set(u, 'mtu', mtu)
586
d486dd0d 587 def _process_mtu_config(self, ifaceobj, ifaceobj_getfunc, mtu):
8d1e346f
RP
588 if mtu:
589 if not self._check_mtu_config(ifaceobj, mtu, ifaceobj_getfunc):
590 return
d486dd0d
JF
591 cached_running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
592 running_mtu = self.ipcmd.link_get_mtu_sysfs(ifaceobj.name)
8d1e346f 593 if not running_mtu or (running_mtu and running_mtu != mtu):
d486dd0d
JF
594 force = cached_running_mtu != running_mtu
595 self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu, force=force)
8d1e346f
RP
596 if (not ifupdownflags.flags.ALL and
597 not ifaceobj.link_kind and
d486dd0d 598 ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'):
8d1e346f
RP
599 # This is additional cost to us, so do it only when
600 # ifupdown2 is called on a particular interface and
601 # it is a physical interface
602 self._propagate_mtu_to_upper_devs(ifaceobj, mtu, ifaceobj_getfunc)
9f30b2cc
RP
603 return
604
605 if ifaceobj.link_kind:
606 # bonds and vxlan devices need an explicit set of mtu.
607 # bridges don't need mtu set
608 if (ifaceobj.link_kind & ifaceLinkKind.BOND or
609 ifaceobj.link_kind & ifaceLinkKind.VXLAN):
610 running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
611 if (self.default_mtu and running_mtu != self.default_mtu):
612 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
613 return
d486dd0d 614 if (ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'
9f30b2cc
RP
615 and ifaceobj.lowerifaces):
616 # set vlan interface mtu to lower device mtu
617 if (ifaceobj.link_kind & ifaceLinkKind.VLAN):
d486dd0d
JF
618 lower_iface = ifaceobj.lowerifaces[0]
619 if lower_iface not in self.lower_iface_mtu_checked_list:
620 lower_iface_mtu = self.ipcmd.link_get_mtu_sysfs(lower_iface)
621 self.ipcmd.cache_update([lower_iface, 'mtu'], lower_iface_mtu)
622 self.lower_iface_mtu_checked_list.append(lower_iface)
623 else:
624 lower_iface_mtu = self.ipcmd.link_get_mtu(lower_iface)
625
626 if lower_iface_mtu != self.ipcmd.link_get_mtu_sysfs(ifaceobj.name):
9f30b2cc
RP
627 self.ipcmd.link_set_mtu(ifaceobj.name, lower_iface_mtu)
628
629 elif (not (ifaceobj.name == 'lo') and not ifaceobj.link_kind and
630 not (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and
631 self.default_mtu):
632 # logical devices like bridges and vlan devices rely on mtu
633 # from their lower devices. ie mtu travels from
634 # lower devices to upper devices. For bonds mtu travels from
635 # upper to lower devices. running mtu depends on upper and
636 # lower device mtu. With all this implicit mtu
637 # config by the kernel in play, we try to be cautious here
638 # on which devices we want to reset mtu to default.
639 # essentially only physical interfaces which are not bond slaves
640 running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
641 if running_mtu != self.default_mtu:
642 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
643
d486dd0d
JF
644 def _set_bridge_forwarding(self, ifaceobj):
645 """ set ip forwarding to 0 if bridge interface does not have a
646 ip nor svi """
2185a108 647 ifname = ifaceobj.name
d486dd0d 648 if not ifaceobj.upperifaces and not ifaceobj.get_attr_value('address'):
2185a108
JF
649 if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv4") == '1':
650 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv4", 0)
651 if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv6") == '1':
652 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv6", 0)
d486dd0d 653 else:
2185a108
JF
654 if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv4") == '0':
655 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv4", 1)
656 if self.sysctl_get_forwarding_value_from_proc(ifname, "ipv6") == '0':
657 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv6", 1)
658
659 def sysctl_get_forwarding_value_from_proc(self, ifname, family):
660 return self.read_file_oneline("/proc/sys/net/%s/conf/%s/forwarding" % (family, ifname))
661
662 def sysctl_write_forwarding_value_to_proc(self, ifname, family, value):
663 self.write_file("/proc/sys/net/%s/conf/%s/forwarding" % (family, ifname), "%s\n" % value)
d486dd0d
JF
664
665 def _sysctl_config(self, ifaceobj):
666 setting_default_value = False
667 mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
668 if not mpls_enable:
669 setting_default_value = True
670 mpls_enable = self.get_mod_subattr('mpls-enable', 'default')
671 mpls_enable = utils.boolean_support_binary(mpls_enable)
672 # File read has been used for better performance
673 # instead of using sysctl command
674 if ifupdownflags.flags.PERFMODE:
675 running_mpls_enable = '0'
676 else:
677 running_mpls_enable = self.read_file_oneline(
678 '/proc/sys/net/mpls/conf/%s/input'
679 % ifaceobj.name
680 )
681
682 if mpls_enable != running_mpls_enable:
683 try:
684 self.sysctl_set('net.mpls.conf.%s.input'
685 %('/'.join(ifaceobj.name.split("."))),
686 mpls_enable)
687 except Exception as e:
688 if not setting_default_value:
689 ifaceobj.status = ifaceStatus.ERROR
690 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
691
692 if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
693 self._set_bridge_forwarding(ifaceobj)
694 return
695 if not self.syntax_check_sysctls(ifaceobj):
696 return
697 ipforward = ifaceobj.get_attr_value_first('ip-forward')
698 ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
699 if ifupdownflags.flags.PERFMODE:
700 if ipforward:
701 self.sysctl_set('net.ipv4.conf.%s.forwarding'
702 %('/'.join(ifaceobj.name.split("."))),
703 utils.boolean_support_binary(ipforward))
704 if ip6forward:
705 self.sysctl_set('net.ipv6.conf.%s.forwarding'
706 %('/'.join(ifaceobj.name.split("."))),
707 utils.boolean_support_binary(ip6forward))
708 return
709 bridge_port = ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
710 if bridge_port:
711 if ipforward:
712 self.log_error('%s: \'ip-forward\' is not supported for '
713 'bridge port' %ifaceobj.name)
714 if ip6forward:
715 self.log_error('%s: \'ip6-forward\' is not supported for '
716 'bridge port' %ifaceobj.name)
717 return
718 setting_default_value = False
719 if not ipforward:
720 setting_default_value = True
721 ipforward = (self.ipforward or
722 self.get_mod_subattr('ip-forward', 'default'))
723 ipforward = utils.boolean_support_binary(ipforward)
724 # File read has been used for better performance
725 # instead of using sysctl command
726 running_ipforward = self.read_file_oneline(
727 '/proc/sys/net/ipv4/conf/%s/forwarding'
728 %ifaceobj.name)
729 if ipforward != running_ipforward:
730 try:
731 self.sysctl_set('net.ipv4.conf.%s.forwarding'
732 %('/'.join(ifaceobj.name.split("."))),
733 ipforward)
734 except Exception as e:
735 if not setting_default_value:
736 ifaceobj.status = ifaceStatus.ERROR
737 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
738
739 setting_default_value = False
740 if not ip6forward:
741 setting_default_value = True
742 ip6forward = (self.ip6forward or
743 self.get_mod_subattr('ip6-forward', 'default'))
744 ip6forward = utils.boolean_support_binary(ip6forward)
745 # File read has been used for better performance
746 # instead of using sysctl command
747 running_ip6forward = self.read_file_oneline(
748 '/proc/sys/net/ipv6/conf/%s/forwarding'
749 %ifaceobj.name)
750 if ip6forward != running_ip6forward:
751 try:
752 self.sysctl_set('net.ipv6.conf.%s.forwarding'
753 %('/'.join(ifaceobj.name.split("."))),
754 ip6forward)
755 except Exception as e:
756 # There is chance of ipv6 being removed because of,
757 # for example, setting mtu < 1280
758 # In such cases, log error only if user has configured
759 # ip6-forward
760 if not setting_default_value:
761 ifaceobj.status = ifaceStatus.ERROR
762 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
763
764 def process_mtu(self, ifaceobj, ifaceobj_getfunc):
765 mtu = ifaceobj.get_attr_value_first('mtu')
766
767 if not mtu:
768 default_iface_mtu = self.ifaces_defaults.get(ifaceobj.name, {}).get('mtu')
769
770 if default_iface_mtu:
771 try:
772 mtu = default_iface_mtu
773 int(default_iface_mtu)
774 except Exception as e:
775 self.logger.warning('%s: MTU value from policy file: %s' % (ifaceobj.name, str(e)))
776 return
777
778 self._process_mtu_config(ifaceobj, ifaceobj_getfunc, mtu)
779
3fc54eef 780 def up_ipv6_addrgen(self, ifaceobj):
007cae35
JF
781 user_configured_ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
782
b306a8b6
JF
783 if not user_configured_ipv6_addrgen and ifupdownflags.flags.PERFMODE:
784 # no need to go further during perfmode (boot)
785 return
786
cd890b06
JF
787 if not user_configured_ipv6_addrgen and ifaceobj.addr_method == 'dhcp':
788 return
789
007cae35 790 if not user_configured_ipv6_addrgen:
17da0561
JF
791 # if user didn't configure ipv6-addrgen, should we reset to default?
792 user_configured_ipv6_addrgen = self.get_attr_default_value('ipv6-addrgen')
007cae35
JF
793
794 ipv6_addrgen_nl = {
795 'on': 0,
796 'yes': 0,
797 '0': 0,
798 'off': 1,
799 'no': 1,
800 '1': 1
801 }.get(user_configured_ipv6_addrgen.lower(), None)
802
803 if ipv6_addrgen_nl is not None:
804 self.ipcmd.ipv6_addrgen(ifaceobj.name, ipv6_addrgen_nl, link_created=True)
805 # link_create=False will flush the addr cache of that intf
806 else:
807 self.logger.warning('%s: invalid value "%s" for attribute ipv6-addrgen' % (ifaceobj.name, user_configured_ipv6_addrgen))
3fc54eef 808
0582f185 809 def _up(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea
RP
810 if not self.ipcmd.link_exists(ifaceobj.name):
811 return
2ff98bb9 812
d486dd0d
JF
813 if not self.syntax_check_enable_l3_iface_forwardings(ifaceobj, ifaceobj_getfunc):
814 return
815
2ff98bb9
JF
816 alias = ifaceobj.get_attr_value_first('alias')
817 current_alias = self.ipcmd.link_get_alias(ifaceobj.name)
818 if alias and alias != current_alias:
819 self.ipcmd.link_set_alias(ifaceobj.name, alias)
820 elif not alias and current_alias:
821 self.ipcmd.link_set_alias(ifaceobj.name, '')
822
d486dd0d
JF
823 self._sysctl_config(ifaceobj)
824
68d9fee0 825 addr_method = ifaceobj.addr_method
77021aa1 826 force_reapply = False
15ef32ea
RP
827 try:
828 # release any stale dhcp addresses if present
77054f7f 829 if (addr_method not in ["dhcp", "ppp"] and not ifupdownflags.flags.PERFMODE and
15ef32ea
RP
830 not (ifaceobj.flags & iface.HAS_SIBLINGS)):
831 # if not running in perf mode and ifaceobj does not have
832 # any sibling iface objects, kill any stale dhclient
833 # processes
75afe2a7 834 dhclientcmd = dhclient()
7c1135ea 835 if dhclientcmd.is_running(ifaceobj.name):
15ef32ea
RP
836 # release any dhcp leases
837 dhclientcmd.release(ifaceobj.name)
77021aa1 838 force_reapply = True
7c1135ea 839 elif dhclientcmd.is_running6(ifaceobj.name):
15ef32ea 840 dhclientcmd.release6(ifaceobj.name)
77021aa1 841 force_reapply = True
15ef32ea
RP
842 except:
843 pass
8e113d63 844
15ef32ea 845 self.ipcmd.batch_start()
3fc54eef
JF
846 self.up_ipv6_addrgen(ifaceobj)
847
77054f7f 848 if addr_method not in ["dhcp", "ppp"]:
77021aa1
RP
849 self._inet_address_config(ifaceobj, ifaceobj_getfunc,
850 force_reapply)
d486dd0d
JF
851
852 self.process_mtu(ifaceobj, ifaceobj_getfunc)
13e22530 853
093ffa00
JF
854 try:
855 self.ipcmd.batch_commit()
856 except Exception as e:
03092649 857 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj, raise_error=False)
264dcaa0 858
68d9fee0 859 try:
707aeb73
JF
860 hwaddress = self._get_hwaddress(ifaceobj)
861 if hwaddress:
862 running_hwaddress = None
863 if not ifupdownflags.flags.PERFMODE: # system is clean
864 running_hwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
865 if hwaddress != running_hwaddress:
866 slave_down = False
867 netlink.link_set_updown(ifaceobj.name, "down")
868 if ifaceobj.link_kind & ifaceLinkKind.BOND:
869 # if bond, down all the slaves
870 if ifaceobj.lowerifaces:
871 for l in ifaceobj.lowerifaces:
872 netlink.link_set_updown(l, "down")
873 slave_down = True
874 try:
875 self.ipcmd.link_set(ifaceobj.name, 'address', hwaddress)
876 finally:
877 netlink.link_set_updown(ifaceobj.name, "up")
878 if slave_down:
879 for l in ifaceobj.lowerifaces:
880 netlink.link_set_updown(l, "up")
881
68d9fee0
RP
882 # Handle special things on a bridge
883 self._process_bridge(ifaceobj, True)
884 except Exception, e:
bf3eda91 885 self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
cb46a208 886
d486dd0d
JF
887 gateways = ifaceobj.get_attr_value('gateway')
888 if not gateways:
889 gateways = []
890 prev_gw = self._get_prev_gateway(ifaceobj, gateways)
891 self._add_delete_gateway(ifaceobj, gateways, prev_gw)
15ef32ea 892
0582f185 893 def _down(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea
RP
894 try:
895 if not self.ipcmd.link_exists(ifaceobj.name):
896 return
68d9fee0 897 addr_method = ifaceobj.addr_method
77054f7f 898 if addr_method not in ["dhcp", "ppp"]:
aa052170
N
899 if ifaceobj.get_attr_value_first('address-purge')=='no':
900 addrlist = ifaceobj.get_attr_value('address')
901 for addr in addrlist:
902 self.ipcmd.addr_del(ifaceobj.name, addr)
903 #self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0])
d486dd0d
JF
904 elif not ifaceobj.link_kind:
905 # for logical interfaces we don't need to remove the ip addresses
906 # kernel will do it for us on 'ip link del'
aa052170 907 self.ipcmd.del_addr_all(ifaceobj.name)
d486dd0d
JF
908 gateways = ifaceobj.get_attr_value('gateway')
909 if gateways:
910 self._delete_gateway(ifaceobj, gateways,
911 ifaceobj.get_attr_value_first('vrf'),
912 ifaceobj.get_attr_value_first('metric'))
84f33af6 913 mtu = ifaceobj.get_attr_value_first('mtu')
00c12960
RP
914 if (not ifaceobj.link_kind and mtu and
915 self.default_mtu and (mtu != self.default_mtu)):
84f33af6 916 self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
15ef32ea
RP
917 alias = ifaceobj.get_attr_value_first('alias')
918 if alias:
d486dd0d 919 self.write_file('/sys/class/net/%s/ifalias' % ifaceobj.name, '\n')
75afe2a7
RP
920 # XXX hwaddress reset cannot happen because we dont know last
921 # address.
922
923 # Handle special things on a bridge
924 self._process_bridge(ifaceobj, False)
15ef32ea 925 except Exception, e:
bcf11b14
RP
926 self.logger.debug('%s : %s' %(ifaceobj.name, str(e)))
927 pass
15ef32ea
RP
928
929 def _get_iface_addresses(self, ifaceobj):
930 addrlist = ifaceobj.get_attr_value('address')
931 outaddrlist = []
932
933 if not addrlist: return None
934 for addrindex in range(0, len(addrlist)):
935 addr = addrlist[addrindex]
936 netmask = ifaceobj.get_attr_value_n('netmask', addrindex)
937 if netmask:
938 prefixlen = IPNetwork('%s' %addr +
939 '/%s' %netmask).prefixlen
940 addr = addr + '/%s' %prefixlen
941 outaddrlist.append(addr)
942 return outaddrlist
943
8e113d63
RP
944 def _get_bridge_fdbs(self, bridgename, vlan):
945 fdbs = self._bridge_fdb_query_cache.get(bridgename)
946 if not fdbs:
947 fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
948 if not fdbs:
949 return
950 self._bridge_fdb_query_cache[bridgename] = fdbs
951 return fdbs.get(vlan)
952
953 def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
954 """ If the device is a bridge, make sure the addresses
955 are in the bridge """
d486dd0d
JF
956 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
957 bridgename = ifaceobj.lowerifaces[0]
958 vlan = self._get_vlan_id(ifaceobj)
8e113d63 959 if self.ipcmd.bridge_is_vlan_aware(bridgename):
d486dd0d 960 fdb_addrs = self._get_bridge_fdbs(bridgename, str(vlan))
8e113d63
RP
961 if not fdb_addrs or hwaddress not in fdb_addrs:
962 return False
963 return True
964
d486dd0d
JF
965 def _query_sysctl(self, ifaceobj, ifaceobjcurr):
966 bridge_port = ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
967 ipforward = ifaceobj.get_attr_value_first('ip-forward')
968 if ipforward:
969 if bridge_port:
970 ifaceobjcurr.status = ifaceStatus.ERROR
971 ifaceobjcurr.status_str = ('\'ip-forward\' not supported ' +
972 'for bridge port')
973 ifaceobjcurr.update_config_with_status('ip-forward', 1, None)
974 else:
975 running_ipforward = self.read_file_oneline(
976 '/proc/sys/net/ipv4/conf/%s/forwarding'
977 %ifaceobj.name)
307e814c
JF
978 running_ipforward = utils.get_boolean_from_string(running_ipforward)
979 config_ipforward = utils.get_boolean_from_string(ipforward)
980 ifaceobjcurr.update_config_with_status(
981 'ip-forward',
982 'on' if running_ipforward else 'off',
983 running_ipforward != config_ipforward
984 )
d486dd0d
JF
985
986 ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
987 if ip6forward:
988 if bridge_port:
989 ifaceobjcurr.status = ifaceStatus.ERROR
990 ifaceobjcurr.status_str = ('\'ip6-forward\' not supported ' +
991 'for bridge port')
992 ifaceobjcurr.update_config_with_status('ip6-forward', 1, None)
993 else:
994 running_ip6forward = self.read_file_oneline(
995 '/proc/sys/net/ipv6/conf/%s/forwarding'
996 %ifaceobj.name)
307e814c
JF
997 running_ip6forward = utils.get_boolean_from_string(running_ip6forward)
998 config_ip6forward = utils.get_boolean_from_string(ip6forward)
999 ifaceobjcurr.update_config_with_status(
1000 'ip6-forward',
1001 'on' if running_ip6forward else 'off',
1002 running_ip6forward != config_ip6forward
1003 )
d486dd0d
JF
1004 mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
1005 if mpls_enable:
1006 running_mpls_enable = self.read_file_oneline(
1007 '/proc/sys/net/mpls/conf/%s/input'
1008 %ifaceobj.name)
1009 running_mpls_enable = utils.get_yesno_from_onezero(
1010 running_mpls_enable)
1011 ifaceobjcurr.update_config_with_status('mpls-enable',
1012 running_mpls_enable,
1013 mpls_enable != running_mpls_enable)
1014 return
1015
007cae35
JF
1016 def query_check_ipv6_addrgen(self, ifaceobj, ifaceobjcurr):
1017 ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
1018
1019 if not ipv6_addrgen:
1020 return
1021
1022 if ipv6_addrgen in utils._string_values:
1023 ifaceobjcurr.update_config_with_status(
1024 'ipv6-addrgen',
1025 ipv6_addrgen,
1026 utils.get_boolean_from_string(ipv6_addrgen) == self.ipcmd.get_ipv6_addrgen_mode(ifaceobj.name)
1027 )
1028 else:
1029 ifaceobjcurr.update_config_with_status('ipv6-addrgen', ipv6_addrgen, 1)
1030
0582f185 1031 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
15ef32ea
RP
1032 runningaddrsdict = None
1033 if not self.ipcmd.link_exists(ifaceobj.name):
1034 self.logger.debug('iface %s not found' %ifaceobj.name)
1035 return
007cae35
JF
1036
1037 self.query_check_ipv6_addrgen(ifaceobj, ifaceobjcurr)
1038
16d854b4 1039 addr_method = ifaceobj.addr_method
15ef32ea
RP
1040 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
1041 'mtu', self.ipcmd.link_get_mtu)
428206bf 1042 hwaddress = self._get_hwaddress(ifaceobj)
8e113d63 1043 if hwaddress:
2876ca35 1044 rhwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
8e113d63
RP
1045 if not rhwaddress or rhwaddress != hwaddress:
1046 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1047 1)
1048 elif not self._check_addresses_in_bridge(ifaceobj, hwaddress):
1049 # XXX: hw address is not in bridge
1050 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1051 1)
1052 ifaceobjcurr.status_str = 'bridge fdb error'
1053 else:
1054 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1055 0)
15ef32ea
RP
1056 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
1057 'alias', self.ipcmd.link_get_alias)
d486dd0d 1058 self._query_sysctl(ifaceobj, ifaceobjcurr)
15ef32ea 1059 # compare addresses
77054f7f 1060 if addr_method in ["dhcp", "ppp"]:
16d854b4 1061 return
82908a2d
JF
1062 addrs = utils.get_normalized_ip_addr(ifaceobj.name,
1063 self._get_iface_addresses(ifaceobj))
d486dd0d 1064 runningaddrsdict = self.ipcmd.get_running_addrs(ifaceobj)
a794fb31
BR
1065 # if anycast address is configured on 'lo' and is in running config
1066 # add it to addrs so that query_check doesn't fail
82908a2d 1067 anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip'))
a794fb31
BR
1068 if anycast_addr:
1069 anycast_addr = anycast_addr+'/32'
1070 if runningaddrsdict and anycast_addr and runningaddrsdict.get(anycast_addr):
1071 addrs.append(anycast_addr)
15ef32ea
RP
1072
1073 # Set ifaceobjcurr method and family
1074 ifaceobjcurr.addr_method = ifaceobj.addr_method
1075 ifaceobjcurr.addr_family = ifaceobj.addr_family
1076 if not runningaddrsdict and not addrs:
1077 return
1078 runningaddrs = runningaddrsdict.keys() if runningaddrsdict else []
8de397ef
MW
1079 # Add /32 netmask to configured address without netmask.
1080 # This may happen on interfaces where pointopoint is used.
1081 runningaddrs = [ addr if '/' in addr else addr + '/32' for addr in runningaddrs]
15ef32ea
RP
1082 if runningaddrs != addrs:
1083 runningaddrsset = set(runningaddrs) if runningaddrs else set([])
1084 addrsset = set(addrs) if addrs else set([])
1085 if (ifaceobj.flags & iface.HAS_SIBLINGS):
1086 if not addrsset:
1087 return
1088 # only check for addresses present in running config
1089 addrsdiff = addrsset.difference(runningaddrsset)
1090 for addr in addrs:
1091 if addr in addrsdiff:
1092 ifaceobjcurr.update_config_with_status('address',
1093 addr, 1)
1094 else:
1095 ifaceobjcurr.update_config_with_status('address',
1096 addr, 0)
1097 else:
1098 addrsdiff = addrsset.symmetric_difference(runningaddrsset)
1099 for addr in addrsset.union(runningaddrsset):
1100 if addr in addrsdiff:
1101 ifaceobjcurr.update_config_with_status('address',
1102 addr, 1)
1103 else:
1104 ifaceobjcurr.update_config_with_status('address',
1105 addr, 0)
1106 elif addrs:
1107 [ifaceobjcurr.update_config_with_status('address',
1108 addr, 0) for addr in addrs]
1109 #XXXX Check broadcast address, scope, etc
1110 return
1111
007cae35
JF
1112 def query_running_ipv6_addrgen(self, ifaceobjrunning):
1113 ipv6_addrgen = self.ipcmd.get_ipv6_addrgen_mode(ifaceobjrunning.name)
1114
1115 if ipv6_addrgen:
1116 ifaceobjrunning.update_config('ipv6-addrgen', 'off')
1117
0582f185 1118 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
15ef32ea
RP
1119 if not self.ipcmd.link_exists(ifaceobjrunning.name):
1120 self.logger.debug('iface %s not found' %ifaceobjrunning.name)
15ef32ea 1121 return
007cae35
JF
1122
1123 self.query_running_ipv6_addrgen(ifaceobjrunning)
1124
15ef32ea
RP
1125 dhclientcmd = dhclient()
1126 if (dhclientcmd.is_running(ifaceobjrunning.name) or
1127 dhclientcmd.is_running6(ifaceobjrunning.name)):
1128 # If dhcp is configured on the interface, we skip it
84f33af6 1129 return
15ef32ea
RP
1130 isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name)
1131 if isloopback:
1132 default_addrs = ['127.0.0.1/8', '::1/128']
004d1e65 1133 ifaceobjrunning.addr_family.append('inet')
15ef32ea
RP
1134 ifaceobjrunning.addr_method = 'loopback'
1135 else:
1136 default_addrs = []
d486dd0d 1137 runningaddrsdict = self.ipcmd.get_running_addrs(ifaceobjrunning)
15ef32ea
RP
1138 if runningaddrsdict:
1139 [ifaceobjrunning.update_config('address', addr)
1140 for addr, addrattrs in runningaddrsdict.items()
1141 if addr not in default_addrs]
1142 mtu = self.ipcmd.link_get_mtu(ifaceobjrunning.name)
1143 if (mtu and
1144 (ifaceobjrunning.name == 'lo' and mtu != '16436') or
1145 (ifaceobjrunning.name != 'lo' and
1146 mtu != self.get_mod_subattr('mtu', 'default'))):
1147 ifaceobjrunning.update_config('mtu', mtu)
1148 alias = self.ipcmd.link_get_alias(ifaceobjrunning.name)
84f33af6 1149 if alias:
15ef32ea
RP
1150 ifaceobjrunning.update_config('alias', alias)
1151
d486dd0d
JF
1152 ipforward = self.read_file_oneline(
1153 '/proc/sys/net/ipv4/conf/%s/forwarding'
1154 %ifaceobjrunning.name)
1155
8d1e346f 1156
15ef32ea
RP
1157 _run_ops = {'up' : _up,
1158 'down' : _down,
1159 'query-checkcurr' : _query_check,
1160 'query-running' : _query_running }
1161
1162 def get_ops(self):
1163 """ returns list of ops supported by this module """
1164 return self._run_ops.keys()
1165
1166 def _init_command_handlers(self):
1167 if not self.ipcmd:
d486dd0d 1168 self.ipcmd = LinkUtils()
15ef32ea 1169
6e16e5ae 1170 def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
15ef32ea
RP
1171 """ run address configuration on the interface object passed as argument
1172
1173 Args:
1174 **ifaceobj** (object): iface object
1175
1176 **operation** (str): any of 'up', 'down', 'query-checkcurr',
1177 'query-running'
1178 Kwargs:
1179 query_ifaceobj (object): query check ifaceobject. This is only
1180 valid when op is 'query-checkcurr'. It is an object same as
1181 ifaceobj, but contains running attribute values and its config
1182 status. The modules can use it to return queried running state
1183 of interfaces. status is success if the running state is same
1184 as user required state in ifaceobj. error otherwise.
1185 """
8e113d63
RP
1186 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
1187 return
15ef32ea
RP
1188 op_handler = self._run_ops.get(operation)
1189 if not op_handler:
1190 return
15ef32ea
RP
1191 self._init_command_handlers()
1192 if operation == 'query-checkcurr':
0582f185
RP
1193 op_handler(self, ifaceobj, query_ifaceobj,
1194 ifaceobj_getfunc=ifaceobj_getfunc)
15ef32ea 1195 else:
0582f185
RP
1196 op_handler(self, ifaceobj,
1197 ifaceobj_getfunc=ifaceobj_getfunc)