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