]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/address.py
addons: address: fix merge-indentation issue
[mirror_ifupdown2.git] / ifupdown2 / addons / address.py
CommitLineData
35681c06 1#!/usr/bin/env python3
15ef32ea 2#
d486dd0d 3# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
15ef32ea
RP
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6
007cae35 7import socket
b99c724a
AB
8import json
9import time
10import subprocess
007cae35 11
793fb44a 12from setuptools.dist import strtobool
8126ef0c 13
15ef32ea 14try:
3eb08b79 15 from ifupdown2.lib.addon import AddonWithIpBlackList
223ba5af
JF
16 from ifupdown2.nlmanager.nlmanager import Link
17
421e9573 18 from ifupdown2.ifupdown.iface import ifaceType, ifaceLinkKind, ifaceLinkPrivFlags, ifaceStatus, iface
d486dd0d 19 from ifupdown2.ifupdown.utils import utils
d486dd0d
JF
20
21 from ifupdown2.ifupdownaddons.dhclient import dhclient
d486dd0d
JF
22 from ifupdown2.ifupdownaddons.modulebase import moduleBase
23
0e936c3f
JF
24 import ifupdown2.nlmanager.ipnetwork as ipnetwork
25
d486dd0d
JF
26 import ifupdown2.ifupdown.statemanager as statemanager
27 import ifupdown2.ifupdown.policymanager as policymanager
28 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
29 import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
bd441a51 30except (ImportError, ModuleNotFoundError):
3eb08b79 31 from lib.addon import AddonWithIpBlackList
223ba5af
JF
32 from nlmanager.nlmanager import Link
33
421e9573 34 from ifupdown.iface import ifaceType, ifaceLinkKind, ifaceLinkPrivFlags, ifaceStatus, iface
82908a2d 35 from ifupdown.utils import utils
d486dd0d 36
15ef32ea 37 from ifupdownaddons.dhclient import dhclient
d486dd0d
JF
38 from ifupdownaddons.modulebase import moduleBase
39
0e936c3f
JF
40 import nlmanager.ipnetwork as ipnetwork
41
d486dd0d 42 import ifupdown.statemanager as statemanager
84f33af6 43 import ifupdown.policymanager as policymanager
fc5e1735 44 import ifupdown.ifupdownflags as ifupdownflags
d486dd0d
JF
45 import ifupdown.ifupdownconfig as ifupdownconfig
46
15ef32ea 47
3eb08b79 48class address(AddonWithIpBlackList, moduleBase):
15ef32ea
RP
49 """ ifupdown2 addon module to configure address, mtu, hwaddress, alias
50 (description) on an interface """
51
223ba5af
JF
52 _modinfo = {
53 'mhelp': 'address configuration module for interfaces',
54 'attrs': {
55 'address': {
56 'help': 'The address of the interface. The format of the '
57 'address depends on the protocol. It is a dotted '
58 'quad for IP and a sequence of hexadecimal halfwords '
59 'separated by colons for IPv6. The ADDRESS may be '
60 'followed by a slash and a decimal number which '
61 'encodes the network prefix length.',
62 'validvals': ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
63 'multiline': True,
64 'example': [
65 'address 10.0.12.3/24',
66 'address 2000:1000:1000:1000:3::5/128'
67 ]
68 },
69 'netmask': {
70 'help': 'Address netmask',
71 'example': ['netmask 255.255.255.0'],
72 'compat': True
73 },
eb6ad1f7
AB
74 'dad-attempts': {
75 'help': 'Number of attempts to settle DAD (0 to disable DAD). '
76 'To use this feature, the ipv6_dad_handling_enabled '
77 'module global must be set to true',
78 'example': ['dad-attempts 0'],
79 'default': '60',
80 },
81 'dad-interval': {
82 'help': 'DAD state polling interval in seconds. '
83 'To use this feature, the ipv6_dad_handling_enabled '
84 'module global must be set to true',
85 'example': ['dad-interval 0.5'],
86 'default': '0.1',
87 },
223ba5af
JF
88 'broadcast': {
89 'help': 'The broadcast address on the interface.',
90 'validvals': ['<ipv4>'],
91 'example': ['broadcast 10.0.1.255']
92 },
93 'scope': {
94 'help': 'The scope of the area where this address is valid. '
95 'The available scopes are listed in file /etc/iproute2/rt_scopes. '
96 'Predefined scope values are: '
97 'global - the address is globally valid. '
98 'site - (IPv6 only, deprecated) the address is site local, i.e. it is valid inside this site. '
99 'link - the address is link local, i.e. it is valid only on this device. '
100 'host - the address is valid only inside this host.',
101 'validvals': ['universe', 'site', 'link', 'host', 'nowhere'],
102 'example': ['scope host']
103 },
104 'preferred-lifetime': {
105 'help': 'The preferred lifetime of this address; see section '
106 '5.5.4 of RFC 4862. When it expires, the address is '
107 'no longer used for new outgoing connections. '
108 'Defaults to forever.',
109 'validrange': ['0', '65535'],
110 'example': [
111 'preferred-lifetime forever',
112 'preferred-lifetime 10'
113 ]
114 },
115 'pointopoint': {
116 'help': 'Set the remote IP address for a point-to-point link',
117 'validvals': ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
118 'example': [
119 'pointopoint 10.10.10.42/32'
120 ]
121 },
122 'gateway': {
123 'help': 'Default gateway',
124 'validvals': ['<ipv4>', '<ipv6>'],
125 'multiline': True,
126 'example': ['gateway 255.255.255.0']
127 },
128 'mtu': {
129 'help': 'Interface MTU (maximum transmission unit)',
130 'validrange': ['552', '9216'],
131 'example': ['mtu 1600'],
132 'default': '1500'
133 },
134 'hwaddress': {
135 'help': 'Hardware address (mac)',
136 'validvals': ['<mac>'],
137 'example': ['hwaddress 44:38:39:00:27:b8']
138 },
139 'alias': {
140 'help': 'description/alias: give the device a symbolic name for easy reference.',
141 'example': ['alias testnetwork']
142 },
143 'address-purge': {
144 'help': 'Purge existing addresses. By default any existing '
145 'ip addresses on an interface are purged to match '
146 'persistant addresses in the interfaces file. Set '
147 'this attribute to \'no\' if you want to preserve '
148 'existing addresses',
149 'validvals': ['yes', 'no'],
150 'default': 'yes',
151 'example': ['address-purge yes/no']
152 },
153 'clagd-vxlan-anycast-ip': {
154 'help': 'Anycast local IP address for dual connected VxLANs',
155 'validvals': ['<ipv4>'],
156 'example': ['clagd-vxlan-anycast-ip 36.0.0.11']
157 },
158 'ip-forward': {
159 'help': 'ip forwarding flag',
160 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
161 'default': 'off',
162 'example': ['ip-forward off']
163 },
164 'ip6-forward': {
165 'help': 'ipv6 forwarding flag',
166 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
167 'default': 'off',
168 'example': ['ip6-forward off']
169 },
170 'mpls-enable': {
171 'help': 'mpls enable flag',
172 'validvals': ['yes', 'no'],
173 'default': 'no',
174 'example': ['mpls-enable yes']
175 },
176 'ipv6-addrgen': {
177 'help': 'enable disable ipv6 link addrgenmode',
178 'validvals': ['on', 'off'],
179 'default': 'on',
180 'example': [
181 'ipv6-addrgen on',
182 'ipv6-addrgen off'
183 ]
184 },
185 'arp-accept': {
186 'help': 'Allow gratuitous arp to update arp table',
187 'validvals': ['on', 'off', 'yes', 'no', '0', '1'],
188 'default': 'off',
189 'example': ['arp-accept on']
190 },
191 }
192 }
193
194 DEFAULT_MTU_STRING = "1500"
15ef32ea
RP
195
196 def __init__(self, *args, **kargs):
3eb08b79 197 AddonWithIpBlackList.__init__(self)
15ef32ea 198 moduleBase.__init__(self, *args, **kargs)
8e113d63 199 self._bridge_fdb_query_cache = {}
d486dd0d
JF
200 self.ipforward = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='ip-forward')
201 self.ip6forward = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='ip6-forward')
202 self.ifaces_defaults = policymanager.policymanager_api.get_iface_defaults(module_name=self.__class__.__name__)
203 self.enable_l3_iface_forwarding_checks = utils.get_boolean_from_string(
204 policymanager.policymanager_api.get_module_globals(
205 self.__class__.__name__,
206 'enable_l3_iface_forwarding_checks'
207 )
208 )
f4764e0f
AB
209 self.ipv6_dad_handling_enabled = utils.get_boolean_from_string(
210 policymanager.policymanager_api.get_module_globals(
211 self.__class__.__name__,
212 'ipv6_dad_handling_enabled'
213 ),
214 default=False
215 )
9f30b2cc 216
90937759 217 self.default_mtu = str(self.__policy_get_default_mtu())
cbda6dda
JF
218 self.default_mgmt_intf_mtu = self.__policy_get_mgmt_intf_mtu()
219 if not self.default_mgmt_intf_mtu:
220 self.default_mgmt_intf_mtu = self.default_mtu
221 self.default_mgmt_intf_mtu_int = self.default_mtu_int
222 self.max_mtu = self.__policy_get_max_mtu()
9f30b2cc 223
0e936c3f 224 self.default_loopback_addresses = (ipnetwork.IPNetwork('127.0.0.1/8'), ipnetwork.IPNetwork('::1/128'))
d486dd0d 225
8b57a467
JF
226 self.l3_intf_arp_accept = utils.get_boolean_from_string(
227 policymanager.policymanager_api.get_module_globals(
228 module_name=self.__class__.__name__,
229 attr='l3_intf_arp_accept'
230 ),
8126ef0c 231 default=0
8b57a467
JF
232 )
233
8126ef0c
JF
234 try:
235 l3_intf_arp_accept_str = policymanager.policymanager_api.get_module_globals(
236 module_name=self.__class__.__name__,
237 attr="l3_intf_arp_accept"
238 )
239 try:
240 self.l3_intf_arp_accept = int(l3_intf_arp_accept_str)
7c8627f8 241 except ValueError:
8126ef0c 242 self.l3_intf_arp_accept = int(strtobool(l3_intf_arp_accept_str))
7c8627f8 243 except Exception:
8126ef0c
JF
244 self.l3_intf_arp_accept = 0
245
9d505185
JF
246 self.l3_intf_default_gateway_set_onlink = utils.get_boolean_from_string(
247 policymanager.policymanager_api.get_module_globals(
248 module_name=self.__class__.__name__,
249 attr='l3_intf_default_gateway_set_onlink'
250 ),
251 default=True
252 )
253
20eab2b1
JF
254 self.check_l3_svi_ip_forwarding = utils.get_boolean_from_string(policymanager.policymanager_api.get_module_globals(
255 module_name=self.__class__.__name__,
256 attr="check_l3_svi_ip_forwarding")
257 )
258
223ba5af
JF
259 def __policy_get_default_mtu(self):
260 default_mtu = policymanager.policymanager_api.get_attr_default(
261 module_name=self.__class__.__name__,
262 attr="mtu"
263 )
264
265 if not default_mtu:
266 default_mtu = self.DEFAULT_MTU_STRING
267
268 try:
269 self.default_mtu_int = int(default_mtu)
270 except ValueError as e:
271 self.logger.error("address: invalid default mtu \"%s\" set via policy: %s" % (default_mtu, str(e)))
272 default_mtu = self.DEFAULT_MTU_STRING
273 self.default_mtu_int = int(self.DEFAULT_MTU_STRING)
274
275 self.logger.info("address: using default mtu %s" % default_mtu)
276
277 return default_mtu
278
279 def __policy_get_max_mtu(self):
280 max_mtu = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr="max_mtu")
281 if max_mtu:
282 try:
283 max_mtu_int = int(max_mtu)
284 self.logger.info("address: using max mtu %s" % self.max_mtu)
285 return max_mtu_int
286 except ValueError as e:
287 self.logger.warning("address: policy max_mtu: %s" % str(e))
288 else:
289 self.logger.info("address: max_mtu undefined")
290 return 0
291
cbda6dda
JF
292 def __policy_get_mgmt_intf_mtu(self):
293 default_mgmt_mtu = policymanager.policymanager_api.get_module_globals(
294 module_name=self.__class__.__name__,
295 attr="mgmt_intf_mtu")
296 self.default_mgmt_mtu_int = None
297
298 if not default_mgmt_mtu:
299 return None
300
301 try:
302 self.default_mgmt_mtu_int = int(default_mgmt_mtu)
303 except ValueError as e:
304 self.logger.error("address: invalid default mgmt mtu \"%s\" set via policy: %s" % (default_mgmt_mtu, str(e)))
305 default_mgmt_mtu = self.DEFAULT_MTU_STRING
306 self.default_mgmt_mtu_int = int(self.DEFAULT_MTU_STRING)
307
308 self.logger.info("address: using default mgmt interface mtu %s" % default_mgmt_mtu)
309
310 return default_mgmt_mtu
311
09096420 312 def syntax_check(self, ifaceobj, ifaceobj_getfunc=None):
20eab2b1 313 self.syntax_check_l3_svi_ip_forward(ifaceobj)
22b49c28 314 return (self.syntax_check_multiple_gateway(ifaceobj)
09096420 315 and self.syntax_check_addr_allowed_on(ifaceobj, True)
d486dd0d
JF
316 and self.syntax_check_mtu(ifaceobj, ifaceobj_getfunc)
317 and self.syntax_check_sysctls(ifaceobj)
20eab2b1 318 and self.syntax_check_enable_l3_iface_forwardings(ifaceobj, ifaceobj_getfunc, syntax_check=True))
0b34071b
JF
319
320 def syntax_check_l3_svi_ip_forward(self, ifaceobj):
20eab2b1
JF
321 """ enabled via policy: 'check_l3_svi_ip_forwarding' """
322
323 if not self.check_l3_svi_ip_forwarding:
324 return True
325
0b34071b
JF
326 if ifaceobj.link_kind & ifaceLinkKind.VLAN and ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
327 ip_forward = ifaceobj.get_attr_value_first("ip-forward")
328
329 if ip_forward and not utils.get_boolean_from_string(ip_forward):
20eab2b1 330 self.logger.error("%s: misconfiguration: disabling ip4 forwarding on an l3-svi is not allowed" % ifaceobj.name)
0b34071b
JF
331 return False
332
333 ip6_forward = ifaceobj.get_attr_value_first("ip6-forward")
334
335 if ip6_forward and not utils.get_boolean_from_string(ip6_forward):
20eab2b1 336 self.logger.error("%s: misconfiguration: disabling ip6 forwarding on an l3-svi is not allowed" % ifaceobj.name)
0b34071b
JF
337 return False
338
339 return True
d486dd0d
JF
340
341 def syntax_check_enable_l3_iface_forwardings(self, ifaceobj, ifaceobj_getfunc, syntax_check=False):
342 if (self.enable_l3_iface_forwarding_checks
343 and (ifaceobj.link_kind & ifaceLinkKind.VLAN
344 or ifaceobj.link_kind & ifaceLinkKind.BRIDGE)
345 and not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
346
347 ifname = ifaceobj.name
348 vlan_addr = None
349 vlan_ipforward_off = None
350
351 for obj in ifaceobj_getfunc(ifname) or [ifaceobj]:
352 if not vlan_addr:
353 vlan_addr = obj.get_attr_value('address')
354
355 if not vlan_ipforward_off:
356 ip_forward_value = obj.get_attr_value_first('ip-forward')
357
358 if ip_forward_value and not utils.get_boolean_from_string(ip_forward_value):
359 vlan_ipforward_off = True
360
361 if vlan_addr and vlan_ipforward_off:
362 if syntax_check:
363 raise Exception(
364 'configuring ip-forward off and ip address(es) (%s) is not compatible'
365 % (', '.join(vlan_addr))
366 )
367 else:
368 raise Exception(
369 '%s: configuring ip-forward off and ip address(es) (%s) is not compatible'
370 % (ifname, ', '.join(vlan_addr))
371 )
372
373 return True
374
375 def syntax_check_sysctls(self, ifaceobj):
376 result = True
377 bridge_port = (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT)
378 ipforward = ifaceobj.get_attr_value_first('ip-forward')
379 if bridge_port and ipforward:
380 result = False
381 self.log_error('%s: \'ip-forward\' is not supported for '
382 'bridge port' %ifaceobj.name)
383 ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
384 if bridge_port and ip6forward:
385 result = False
386 self.log_error('%s: \'ip6-forward\' is not supported for '
387 'bridge port' %ifaceobj.name)
388 return result
09096420
RP
389
390 def syntax_check_mtu(self, ifaceobj, ifaceobj_getfunc):
223ba5af
JF
391 mtu_str = ifaceobj.get_attr_value_first('mtu')
392 if mtu_str:
393 try:
394 mtu_int = int(mtu_str)
395 except ValueError as e:
396 self.logger.warning("%s: invalid mtu %s: %s" % (ifaceobj.name, mtu_str, str(e)))
397 return False
398 return self._check_mtu_config(ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc, syntaxcheck=True)
09096420 399 return True
22b49c28
JF
400
401 def syntax_check_addr_allowed_on(self, ifaceobj, syntax_check=False):
402 if ifaceobj.get_attr_value('address'):
403 return utils.is_addr_ip_allowed_on(ifaceobj, syntax_check=syntax_check)
404 return True
405
0e936c3f
JF
406 def _syntax_check_multiple_gateway(self, family, found, addr, version):
407 if ipnetwork.IPNetwork(addr).version == version:
38365d4a
JF
408 if found:
409 raise Exception('%s: multiple gateways for %s family'
410 % (addr, family))
411 return True
412 return False
413
22b49c28 414 def syntax_check_multiple_gateway(self, ifaceobj):
38365d4a
JF
415 result = True
416 inet = False
417 inet6 = False
418 gateways = ifaceobj.get_attr_value('gateway')
419 for addr in gateways if gateways else []:
420 try:
0e936c3f 421 if self._syntax_check_multiple_gateway('inet', inet, addr, 4):
38365d4a 422 inet = True
0e936c3f 423 if self._syntax_check_multiple_gateway('inet6', inet6, addr, 6):
38365d4a
JF
424 inet6 = True
425 except Exception as e:
426 self.logger.warning('%s: address: %s' % (ifaceobj.name, str(e)))
427 result = False
428 return result
429
75afe2a7
RP
430 def _address_valid(self, addrs):
431 if not addrs:
432 return False
3b01ed76
JF
433 if any([True if a[:7] != '0.0.0.0'
434 else False for a in addrs]):
75afe2a7
RP
435 return True
436 return False
437
428206bf 438 def _get_hwaddress(self, ifaceobj):
d486dd0d 439 return utils.strip_hwaddress(ifaceobj.get_attr_value_first('hwaddress'))
428206bf 440
4e0f16d0 441 def _process_bridge(self, ifaceobj, up, hwaddress, old_mac_addr=None):
75afe2a7 442 addrs = ifaceobj.get_attr_value_first('address')
45db39f6
AD
443 arp_accept = ifaceobj.get_attr_value_first('arp-accept')
444 arp_accept = utils.boolean_support_binary(arp_accept)
75afe2a7 445 is_vlan_dev_on_vlan_aware_bridge = False
223ba5af 446 is_bridge = self.cache.get_link_kind(ifaceobj.name) == 'bridge'
75afe2a7 447 if not is_bridge:
d486dd0d
JF
448 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
449 bridgename = ifaceobj.lowerifaces[0]
450 vlan = self._get_vlan_id(ifaceobj)
223ba5af
JF
451 is_vlan_dev_on_vlan_aware_bridge = self.cache.bridge_is_vlan_aware(bridgename)
452 if ((is_bridge and not self.cache.bridge_is_vlan_aware(ifaceobj.name))
8c2c9f26 453 or is_vlan_dev_on_vlan_aware_bridge):
8b57a467
JF
454 if self._address_valid(addrs):
455 if self.l3_intf_arp_accept:
456 if up:
457 self.write_file('/proc/sys/net/ipv4/conf/%s' % ifaceobj.name +
8126ef0c 458 '/arp_accept', str(self.l3_intf_arp_accept))
8b57a467
JF
459 else:
460 self.write_file('/proc/sys/net/ipv4/conf/%s' % ifaceobj.name +
461 '/arp_accept', '0')
462 else:
45db39f6 463 self.write_file('/proc/sys/net/ipv4/conf/%s/arp_accept' % ifaceobj.name, arp_accept)
75afe2a7 464 if hwaddress and is_vlan_dev_on_vlan_aware_bridge:
1db0cb7a
JF
465 if old_mac_addr:
466 # corner case, first the user's /e/n/i is configured without 'hwaddress', then it is used to fix the svi
467 # mac address. The current code only checks for the statemanager for old 'hwaddress' attribute but
468 # couldn't find any. Now we save the mac addr before updating it, so we can later clear it from the fdb.
469 try:
4e0f16d0
JF
470 if utils.mac_str_to_int(old_mac_addr) != utils.mac_str_to_int(hwaddress):
471 self.iproute2.bridge_fdb_del(bridgename, old_mac_addr, vlan)
7c8627f8 472 except Exception:
1db0cb7a 473 pass
15897163
JF
474 if up:
475 # check statemanager to delete the old entry if necessary
476 try:
477 for old_obj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
478 old_hwaddress = old_obj.get_attr_value_first("hwaddress")
223ba5af 479 if old_hwaddress and utils.mac_str_to_int(old_hwaddress) != utils.mac_str_to_int(hwaddress):
1db0cb7a
JF
480 if old_hwaddress != old_mac_addr:
481 self.iproute2.bridge_fdb_del(bridgename, old_hwaddress, vlan)
15897163 482 break
3218f49d 483 except Exception:
15897163 484 pass
223ba5af 485 self.iproute2.bridge_fdb_add(bridgename, hwaddress, vlan)
15897163 486 else:
223ba5af 487 self.iproute2.bridge_fdb_del(bridgename, hwaddress, vlan)
cb46a208 488
223ba5af 489 def __get_ip_addr_with_attributes(self, ifaceobj_list, ifname):
0e936c3f 490 user_config_ip_addrs_list = []
0582f185 491
223ba5af 492 try:
01a65536 493 for ifaceobj in ifaceobj_list or []:
0582f185 494
223ba5af 495 user_addrs = ifaceobj.get_attr_value("address")
0582f185 496
223ba5af
JF
497 if not user_addrs:
498 continue
499
500 if not self.syntax_check_addr_allowed_on(ifaceobj, syntax_check=False):
501 return False, None
502
503 for index, addr in enumerate(user_addrs):
504 addr_attributes = {}
505 addr_obj = None
506
507 # convert the ip from string to IPNetwork object
508 if "/" in addr:
0e936c3f 509 addr_obj = ipnetwork.IPNetwork(addr)
8de397ef 510 else:
223ba5af
JF
511 netmask = ifaceobj.get_attr_value_n("netmask", index)
512
513 if netmask:
0e936c3f 514 addr_obj = ipnetwork.IPNetwork(addr, netmask)
223ba5af 515 else:
0e936c3f 516 addr_obj = ipnetwork.IPNetwork(addr)
223ba5af 517
3fd6c201 518 for attr_name in ("broadcast", "scope", "preferred-lifetime"):
223ba5af
JF
519 attr_value = ifaceobj.get_attr_value_n(attr_name, index)
520 if attr_value:
521 addr_attributes[attr_name] = attr_value
522
523 pointopoint = ifaceobj.get_attr_value_n("pointopoint", index)
524 try:
525 if pointopoint:
0e936c3f 526 addr_attributes["pointopoint"] = ipnetwork.IPNetwork(pointopoint)
223ba5af
JF
527 except Exception as e:
528 self.logger.warning("%s: pointopoint %s: %s" % (ifaceobj.name, pointopoint, str(e)))
529
530 user_config_ip_addrs_list.append((addr_obj, addr_attributes))
531 except Exception as e:
01a65536 532 self.log_error("%s: convert string ip address into IPNetwork object: %s" % (ifname, str(e)), ifaceobj)
223ba5af
JF
533 return False, None
534
535 return True, user_config_ip_addrs_list
536
537 def __add_ip_addresses_with_attributes(self, ifaceobj, ifname, user_config_ip_addrs):
190cf3e6 538 ipv6_is_disabled = None
beaffab6
AB
539 nodad = False
540 if self.ipv6_dad_handling_enabled:
541 nodad = ifaceobj.get_attr_value_first('dad-attempts') == '0'
190cf3e6 542
e90c33ca
JF
543 for ip, attributes in user_config_ip_addrs:
544 try:
190cf3e6
JF
545 if ip.version == 6 and ipv6_is_disabled is None:
546 # check (only once) if ipv6 is disabled on this device
547 proc_path = "/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname
548 ipv6_is_disabled = utils.get_boolean_from_string(self.read_file_oneline(proc_path))
549
550 if ipv6_is_disabled:
551 # enable ipv6
552 self.write_file(proc_path, "0")
553
3eb08b79
JF
554 # check if ip is not blacklisted
555 self.ip_blacklist_check(ifname, ip)
556
223ba5af
JF
557 if attributes:
558 self.netlink.addr_add(
559 ifname, ip,
560 scope=attributes.get("scope"),
561 peer=attributes.get("pointopoint"),
562 broadcast=attributes.get("broadcast"),
beaffab6
AB
563 preferred_lifetime=attributes.get("preferred-lifetime"),
564 nodad=nodad
223ba5af 565 )
77021aa1 566 else:
beaffab6 567 self.netlink.addr_add(ifname, ip, nodad=nodad)
e90c33ca
JF
568 except Exception as e:
569 self.log_error(str(e), ifaceobj, raise_error=False)
77021aa1 570
223ba5af
JF
571 @staticmethod
572 def __add_loopback_anycast_ip_to_running_ip_addr_list(ifaceobjlist):
573 """
574 if anycast address is configured on 'lo' and is in running
575 config add it to newaddrs so that ifreload doesn't wipe it out
576 :param ifaceobjlist:
577 :param running_ip_addrs:
578 """
579 anycast_ip_addr = None
0582f185 580
223ba5af
JF
581 for ifaceobj in ifaceobjlist:
582 anycast_addr = ifaceobj.get_attr_value_first("clagd-vxlan-anycast-ip")
583 if anycast_addr:
0e936c3f 584 anycast_ip_addr = ipnetwork.IPNetwork(anycast_addr)
223ba5af 585
0e936c3f 586 return anycast_ip_addr
223ba5af
JF
587
588 def process_addresses(self, ifaceobj, ifaceobj_getfunc=None, force_reapply=False):
589 squash_addr_config = ifupdownconfig.config.get("addr_config_squash", "0") == "1"
590
591 if squash_addr_config and not ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING:
0582f185
RP
592 return
593
223ba5af
JF
594 ifname = ifaceobj.name
595 purge_addresses = utils.get_boolean_from_string(ifaceobj.get_attr_value_first("address-purge"), default=True)
596
597 if not squash_addr_config and ifaceobj.flags & iface.HAS_SIBLINGS:
598 # if youngest sibling and squash addr is not set
599 # print a warning that addresses will not be purged
600 if ifaceobj.flags & iface.YOUNGEST_SIBLING:
601 self.logger.warning("%s: interface has multiple iface stanzas, skip purging existing addresses" % ifname)
602 purge_addresses = False
0582f185
RP
603
604 if squash_addr_config and ifaceobj.flags & iface.HAS_SIBLINGS:
223ba5af 605 ifaceobj_list = ifaceobj_getfunc(ifname)
0582f185 606 else:
223ba5af 607 ifaceobj_list = [ifaceobj]
d486dd0d 608
223ba5af 609 addr_supported, user_config_ip_addrs_list = self.__get_ip_addr_with_attributes(ifaceobj_list, ifname)
d486dd0d 610
0582f185
RP
611 if not addr_supported:
612 return
0582f185 613
223ba5af
JF
614 if not ifupdownflags.flags.PERFMODE and purge_addresses:
615 # if perfmode is not set and purge addresses is set to True
0582f185 616 # lets purge addresses not in the config
223ba5af
JF
617 anycast_ip = None
618
0e936c3f 619 running_ip_addrs = self.cache.get_managed_ip_addresses(ifname, ifaceobj_list)
0582f185 620
223ba5af
JF
621 if ifaceobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK:
622 anycast_ip = self.__add_loopback_anycast_ip_to_running_ip_addr_list(ifaceobj_list)
0582f185 623
223ba5af 624 user_ip4, user_ip6, ordered_user_configured_ips = self.order_user_configured_addrs(user_config_ip_addrs_list)
d486dd0d 625
223ba5af 626 if ordered_user_configured_ips == running_ip_addrs or self.compare_running_ips_and_user_config(user_ip4, user_ip6, running_ip_addrs):
77021aa1 627 if force_reapply:
223ba5af 628 self.__add_ip_addresses_with_attributes(ifaceobj, ifname, user_config_ip_addrs_list)
15ef32ea
RP
629 return
630 try:
223ba5af 631 # if primary address is not same, there is no need to keep any, reset all addresses.
0e936c3f 632 if ordered_user_configured_ips and running_ip_addrs and ordered_user_configured_ips[0] != running_ip_addrs[0]:
223ba5af 633 self.logger.info("%s: primary ip changed (from %s to %s) we need to purge all ip addresses and re-add them"
0e936c3f 634 % (ifname, ordered_user_configured_ips[0], running_ip_addrs[0]))
d486dd0d 635 skip_addrs = []
15ef32ea 636 else:
223ba5af
JF
637 skip_addrs = ordered_user_configured_ips
638
639 if anycast_ip:
640 skip_addrs.append(anycast_ip)
641
0e936c3f 642 for addr in running_ip_addrs:
d486dd0d
JF
643 if addr in skip_addrs:
644 continue
0e936c3f 645 self.netlink.addr_del(ifname, addr)
3b01ed76 646 except Exception as e:
15ef32ea 647 self.log_warn(str(e))
223ba5af 648 if not user_config_ip_addrs_list:
15ef32ea 649 return
223ba5af
JF
650 self.__add_ip_addresses_with_attributes(ifaceobj, ifname, user_config_ip_addrs_list)
651
d486dd0d
JF
652 def compare_running_ips_and_user_config(self, user_ip4, user_ip6, running_addrs):
653 """
654 We need to compare the user config ips and the running ips.
655 ip4 ordering matters (primary etc) but ip6 order doesn't matter
656
657 this function replaces the strict comparison previously in place
658 if newaddrs == running_addrs ?
659
660 We will compare if the ip4 ordering is correct, then check if all
661 ip6 are present in the list (without checking the ordering)
662 """
663 if (user_ip4 or user_ip6) and not running_addrs:
664 return False
665 elif running_addrs and not user_ip4 and not user_ip6:
666 return False
667 elif not running_addrs and not user_ip4 and not user_ip6:
668 return True
669
670 len_ip4 = len(user_ip4)
671 len_running_addrs = len(running_addrs)
672
673 if len_ip4 > len_running_addrs:
674 return False
675
676 i = 0
677 while i < len_ip4:
678 if user_ip4[i] != running_addrs[i]:
679 return False
680 i += 1
681
682 if len_ip4 > 0:
683 running_ip6 = running_addrs[len_ip4:]
684 else:
685 running_ip6 = running_addrs
686
687 i = 0
688 len_ip6 = len(user_ip6)
689
690 for ip6 in running_ip6:
691 if ip6 not in user_ip6:
692 return False
693 i += 1
694
695 return i == len_ip6
696
223ba5af
JF
697 @staticmethod
698 def order_user_configured_addrs(user_config_addrs):
d486dd0d
JF
699 ip4 = []
700 ip6 = []
701
223ba5af
JF
702 for a, _ in user_config_addrs:
703 if a.version == 6:
0e936c3f 704 ip6.append(a)
d486dd0d 705 else:
0e936c3f 706 ip4.append(a)
d486dd0d
JF
707
708 return ip4, ip6, ip4 + ip6
709
710 def _delete_gateway(self, ifaceobj, gateways, vrf, metric):
711 for del_gw in gateways:
0232d1bb 712 try:
223ba5af 713 self.iproute2.route_del_gateway(ifaceobj.name, del_gw, vrf, metric)
5b666749
JF
714 except Exception as e:
715 self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
d486dd0d
JF
716
717 def _add_delete_gateway(self, ifaceobj, gateways=[], prev_gw=[]):
718 vrf = ifaceobj.get_attr_value_first('vrf')
719 metric = ifaceobj.get_attr_value_first('metric')
720 self._delete_gateway(ifaceobj, list(set(prev_gw) - set(gateways)),
721 vrf, metric)
4b875c17 722 for add_gw in gateways:
0232d1bb 723 try:
223ba5af 724 self.iproute2.route_add_gateway(ifaceobj.name, add_gw, vrf, metric, onlink=self.l3_intf_default_gateway_set_onlink)
5b666749
JF
725 except Exception as e:
726 self.log_error('%s: %s' % (ifaceobj.name, str(e)))
0232d1bb
N
727
728 def _get_prev_gateway(self, ifaceobj, gateways):
729 ipv = []
730 saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name)
731 if not saved_ifaceobjs:
732 return ipv
733 prev_gateways = saved_ifaceobjs[0].get_attr_value('gateway')
734 if not prev_gateways:
735 return ipv
736 return prev_gateways
737
223ba5af 738 def _check_mtu_config(self, ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc, syntaxcheck=False):
8d1e346f
RP
739 retval = True
740 if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
741 if syntaxcheck:
c46af1c9 742 self.logger.warning('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj.name)
8d1e346f
RP
743 retval = False
744 else:
9f30b2cc 745 self.logger.info('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj.name)
8d1e346f
RP
746 elif ifaceobj_getfunc:
747 if ((ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) and
748 ifaceobj.upperifaces):
9f30b2cc
RP
749 masterobj = ifaceobj_getfunc(ifaceobj.upperifaces[0])
750 if masterobj:
751 master_mtu = masterobj[0].get_attr_value_first('mtu')
223ba5af
JF
752 if master_mtu and master_mtu != mtu_str:
753 log_msg = ("%s: bond slave mtu %s is different from bond master %s mtu %s. "
754 "There is no need to configure mtu on a bond slave." %
755 (ifaceobj.name, mtu_str, masterobj[0].name, master_mtu))
8d1e346f 756 if syntaxcheck:
c46af1c9 757 self.logger.warning(log_msg)
8d1e346f
RP
758 retval = False
759 else:
223ba5af 760 self.logger.info(log_msg)
8d1e346f
RP
761 elif ((ifaceobj.link_kind & ifaceLinkKind.VLAN) and
762 ifaceobj.lowerifaces):
763 lowerobj = ifaceobj_getfunc(ifaceobj.lowerifaces[0])
764 if lowerobj:
765 if syntaxcheck:
223ba5af 766 lowerdev_mtu = int(lowerobj[0].get_attr_value_first('mtu') or 0)
8d1e346f 767 else:
223ba5af
JF
768 lowerdev_mtu = self.cache.get_link_mtu(lowerobj[0].name) # return type: int
769 if lowerdev_mtu and mtu_int > lowerdev_mtu:
c46af1c9 770 self.logger.warning('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
223ba5af 771 %(ifaceobj.name, mtu_str, lowerobj[0].name, lowerdev_mtu))
8d1e346f
RP
772 retval = False
773 elif (not lowerobj[0].link_kind and
774 not (lowerobj[0].link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
223ba5af 775 not lowerdev_mtu and self.default_mtu and (mtu_int > self.default_mtu_int)):
8d1e346f 776 # only check default mtu on lower device which is a physical interface
c46af1c9 777 self.logger.warning('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
223ba5af 778 %(ifaceobj.name, mtu_str, lowerobj[0].name, self.default_mtu))
8d1e346f 779 retval = False
223ba5af 780 if self.max_mtu and mtu_int > self.max_mtu:
c46af1c9 781 self.logger.warning('%s: specified mtu %s is greater than max mtu %s'
223ba5af 782 %(ifaceobj.name, mtu_str, self.max_mtu))
8d1e346f
RP
783 retval = False
784 return retval
785
223ba5af 786 def _propagate_mtu_to_upper_devs(self, ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc):
8d1e346f
RP
787 if (not ifaceobj.upperifaces or
788 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE) or
789 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) or
790 (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT)):
791 return
792 for u in ifaceobj.upperifaces:
793 upperobjs = ifaceobj_getfunc(u)
794 if (not upperobjs or
795 not (upperobjs[0].link_kind & ifaceLinkKind.VLAN)):
796 continue
797 # only adjust mtu for vlan devices on ifaceobj
798 umtu = upperobjs[0].get_attr_value_first('mtu')
799 if not umtu:
223ba5af
JF
800 running_mtu = self.cache.get_link_mtu(upperobjs[0].name)
801 if not running_mtu or running_mtu != mtu_int:
802 self.sysfs.link_set_mtu(u, mtu_str=mtu_str, mtu_int=mtu_int)
8d1e346f 803
223ba5af
JF
804 def _process_mtu_config_mtu_valid(self, ifaceobj, ifaceobj_getfunc, mtu_str, mtu_int):
805 if not self._check_mtu_config(ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc):
806 return
807
808 if mtu_int != self.cache.get_link_mtu(ifaceobj.name):
809 self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=mtu_str, mtu_int=mtu_int)
810
811 if (not ifupdownflags.flags.ALL and
8d1e346f 812 not ifaceobj.link_kind and
d486dd0d 813 ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'):
223ba5af
JF
814 # This is additional cost to us, so do it only when
815 # ifupdown2 is called on a particular interface and
816 # it is a physical interface
817 self._propagate_mtu_to_upper_devs(ifaceobj, mtu_str, mtu_int, ifaceobj_getfunc)
818 return
819
820 def _process_mtu_config_mtu_none(self, ifaceobj):
cbda6dda
JF
821
822 if (ifaceobj.link_privflags & ifaceLinkPrivFlags.MGMT_INTF):
823 return
824
223ba5af 825 cached_link_mtu = self.cache.get_link_mtu(ifaceobj.name)
9f30b2cc
RP
826
827 if ifaceobj.link_kind:
19ee2b11 828 # bonds, vxlan and custom devices (like dummy) need an explicit set of mtu.
9f30b2cc 829 # bridges don't need mtu set
223ba5af
JF
830 if ifaceobj.link_kind & ifaceLinkKind.BOND \
831 or ifaceobj.link_kind & ifaceLinkKind.VXLAN \
a3df9e69 832 or ifaceobj.link_kind & ifaceLinkKind.BRIDGE \
223ba5af
JF
833 or ifaceobj.link_kind & ifaceLinkKind.OTHER:
834 if cached_link_mtu != self.default_mtu_int:
835 self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=self.default_mtu, mtu_int=self.default_mtu_int)
9f30b2cc 836 return
223ba5af 837
c30ed567
JF
838 # set vlan interface mtu to lower device mtu
839 if (
840 ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'
841 and ifaceobj.lowerifaces
842 and ifaceobj.link_kind & ifaceLinkKind.VLAN
843 ):
844 lower_iface = ifaceobj.lowerifaces[0]
845 lower_iface_mtu_int = self.cache.get_link_mtu(lower_iface)
846
847 if lower_iface_mtu_int != cached_link_mtu:
848 self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=str(lower_iface_mtu_int), mtu_int=lower_iface_mtu_int)
849
850 elif (
e8b9d3ab 851 ifaceobj.name != 'lo'
c30ed567
JF
852 and not ifaceobj.link_kind
853 and not (ifaceobj.link_privflags & ifaceLinkPrivFlags.BOND_SLAVE)
854 and self.default_mtu
855 and cached_link_mtu != self.default_mtu_int
856 ):
9f30b2cc
RP
857 # logical devices like bridges and vlan devices rely on mtu
858 # from their lower devices. ie mtu travels from
859 # lower devices to upper devices. For bonds mtu travels from
860 # upper to lower devices. running mtu depends on upper and
861 # lower device mtu. With all this implicit mtu
862 # config by the kernel in play, we try to be cautious here
863 # on which devices we want to reset mtu to default.
864 # essentially only physical interfaces which are not bond slaves
c30ed567 865 self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=self.default_mtu, mtu_int=self.default_mtu_int)
9f30b2cc 866
d486dd0d
JF
867 def _set_bridge_forwarding(self, ifaceobj):
868 """ set ip forwarding to 0 if bridge interface does not have a
869 ip nor svi """
2185a108 870 ifname = ifaceobj.name
223ba5af
JF
871
872 netconf_ipv4_forwarding = self.cache.get_netconf_forwarding(socket.AF_INET, ifname)
873 netconf_ipv6_forwarding = self.cache.get_netconf_forwarding(socket.AF_INET6, ifname)
874
69825bb4 875 if not ifaceobj.upperifaces and not ifaceobj.get_attr_value('address') and (ifaceobj.addr_method and "dhcp" not in ifaceobj.addr_method):
223ba5af 876 if netconf_ipv4_forwarding:
2185a108 877 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv4", 0)
223ba5af 878 if netconf_ipv6_forwarding:
2185a108 879 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv6", 0)
d486dd0d 880 else:
223ba5af 881 if not netconf_ipv4_forwarding:
2185a108 882 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv4", 1)
223ba5af 883 if not netconf_ipv6_forwarding:
2185a108
JF
884 self.sysctl_write_forwarding_value_to_proc(ifname, "ipv6", 1)
885
2185a108
JF
886 def sysctl_write_forwarding_value_to_proc(self, ifname, family, value):
887 self.write_file("/proc/sys/net/%s/conf/%s/forwarding" % (family, ifname), "%s\n" % value)
d486dd0d
JF
888
889 def _sysctl_config(self, ifaceobj):
890 setting_default_value = False
891 mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
892 if not mpls_enable:
893 setting_default_value = True
894 mpls_enable = self.get_mod_subattr('mpls-enable', 'default')
895 mpls_enable = utils.boolean_support_binary(mpls_enable)
896 # File read has been used for better performance
897 # instead of using sysctl command
898 if ifupdownflags.flags.PERFMODE:
899 running_mpls_enable = '0'
900 else:
223ba5af 901 running_mpls_enable = str(self.cache.get_netconf_mpls_input(ifaceobj.name))
d486dd0d
JF
902
903 if mpls_enable != running_mpls_enable:
904 try:
905 self.sysctl_set('net.mpls.conf.%s.input'
906 %('/'.join(ifaceobj.name.split("."))),
907 mpls_enable)
908 except Exception as e:
909 if not setting_default_value:
910 ifaceobj.status = ifaceStatus.ERROR
911 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
912
913 if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
914 self._set_bridge_forwarding(ifaceobj)
915 return
916 if not self.syntax_check_sysctls(ifaceobj):
917 return
0b34071b
JF
918 if not self.syntax_check_l3_svi_ip_forward(ifaceobj):
919 return
920
d486dd0d
JF
921 ipforward = ifaceobj.get_attr_value_first('ip-forward')
922 ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
923 if ifupdownflags.flags.PERFMODE:
924 if ipforward:
925 self.sysctl_set('net.ipv4.conf.%s.forwarding'
926 %('/'.join(ifaceobj.name.split("."))),
927 utils.boolean_support_binary(ipforward))
928 if ip6forward:
929 self.sysctl_set('net.ipv6.conf.%s.forwarding'
930 %('/'.join(ifaceobj.name.split("."))),
931 utils.boolean_support_binary(ip6forward))
932 return
933 bridge_port = ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
934 if bridge_port:
935 if ipforward:
936 self.log_error('%s: \'ip-forward\' is not supported for '
937 'bridge port' %ifaceobj.name)
938 if ip6forward:
939 self.log_error('%s: \'ip6-forward\' is not supported for '
940 'bridge port' %ifaceobj.name)
941 return
52712b1a
AD
942 setting_default_value = False
943 if not ipforward:
944 setting_default_value = True
34de8712
AD
945 ipforward = self.ipforward
946 if ipforward:
947 ipforward = int(utils.get_boolean_from_string(ipforward))
948 running_ipforward = self.cache.get_netconf_forwarding(socket.AF_INET, ifaceobj.name)
949 if ipforward != running_ipforward:
950 try:
951 self.sysctl_set('net.ipv4.conf.%s.forwarding'
952 %('/'.join(ifaceobj.name.split("."))),
953 ipforward)
954 except Exception as e:
955 if not setting_default_value:
956 ifaceobj.status = ifaceStatus.ERROR
957 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
52712b1a
AD
958
959 setting_default_value = False
34de8712 960
52712b1a
AD
961 if not ip6forward:
962 setting_default_value = True
34de8712
AD
963 ip6forward = self.ip6forward
964
965 if ip6forward:
966 ip6forward = int(utils.get_boolean_from_string(ip6forward))
967 running_ip6forward = self.cache.get_netconf_forwarding(socket.AF_INET6, ifaceobj.name)
968 if ip6forward != running_ip6forward:
969 try:
970 self.sysctl_set('net.ipv6.conf.%s.forwarding'
971 %('/'.join(ifaceobj.name.split("."))),
972 ip6forward)
973 except Exception as e:
974 # There is chance of ipv6 being removed because of,
975 # for example, setting mtu < 1280
976 # In such cases, log error only if user has configured
977 # ip6-forward
978 if not setting_default_value:
979 ifaceobj.status = ifaceStatus.ERROR
980 self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
d486dd0d
JF
981
982 def process_mtu(self, ifaceobj, ifaceobj_getfunc):
8994bdd3
AD
983
984 if ifaceobj.link_privflags & ifaceLinkPrivFlags.OPENVSWITCH:
985 return
986
223ba5af
JF
987 mtu_str = ifaceobj.get_attr_value_first('mtu')
988 mtu_from_policy = False
d486dd0d 989
223ba5af 990 if not mtu_str:
cbda6dda
JF
991 if (ifaceobj.link_privflags & ifaceLinkPrivFlags.MGMT_INTF):
992 mtu_str = self.default_mgmt_intf_mtu
993 if not mtu_str:
994 mtu_str = self.ifaces_defaults.get(ifaceobj.name, {}).get('mtu')
995
223ba5af 996 mtu_from_policy = True
d486dd0d 997
223ba5af
JF
998 if mtu_str:
999 try:
1000 mtu_int = int(mtu_str)
1001 except Exception as e:
1002 if mtu_from_policy:
1003 self.logger.warning("%s: invalid MTU value from policy file (iface_defaults): %s" % (ifaceobj.name, str(e)))
1004 else:
1005 self.logger.warning("%s: invalid MTU value: %s" % (ifaceobj.name, str(e)))
1006 return
d486dd0d 1007
223ba5af
JF
1008 self._process_mtu_config_mtu_valid(ifaceobj, ifaceobj_getfunc, mtu_str, mtu_int)
1009 else:
1010 self._process_mtu_config_mtu_none(ifaceobj)
d486dd0d 1011
3fc54eef 1012 def up_ipv6_addrgen(self, ifaceobj):
007cae35
JF
1013 user_configured_ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
1014
b306a8b6
JF
1015 if not user_configured_ipv6_addrgen and ifupdownflags.flags.PERFMODE:
1016 # no need to go further during perfmode (boot)
1017 return
1018
223ba5af 1019 if not user_configured_ipv6_addrgen and ifaceobj.addr_method in ["dhcp", "ppp"]:
cd890b06
JF
1020 return
1021
007cae35 1022 if not user_configured_ipv6_addrgen:
17da0561
JF
1023 # if user didn't configure ipv6-addrgen, should we reset to default?
1024 user_configured_ipv6_addrgen = self.get_attr_default_value('ipv6-addrgen')
007cae35
JF
1025
1026 ipv6_addrgen_nl = {
1027 'on': 0,
1028 'yes': 0,
1029 '0': 0,
1030 'off': 1,
1031 'no': 1,
1032 '1': 1
1033 }.get(user_configured_ipv6_addrgen.lower(), None)
1034
1035 if ipv6_addrgen_nl is not None:
223ba5af
JF
1036 self.iproute2.batch_start()
1037 self.iproute2.link_set_ipv6_addrgen(ifaceobj.name, ipv6_addrgen_nl, link_created=True)
1038 self.iproute2.batch_commit()
007cae35
JF
1039 # link_create=False will flush the addr cache of that intf
1040 else:
1041 self.logger.warning('%s: invalid value "%s" for attribute ipv6-addrgen' % (ifaceobj.name, user_configured_ipv6_addrgen))
3fc54eef 1042
223ba5af
JF
1043 def _pre_up(self, ifaceobj, ifaceobj_getfunc=None):
1044 if not self.cache.link_exists(ifaceobj.name):
15ef32ea 1045 return
2ff98bb9 1046
d486dd0d
JF
1047 if not self.syntax_check_enable_l3_iface_forwardings(ifaceobj, ifaceobj_getfunc):
1048 return
1049
223ba5af
JF
1050 #
1051 # alias
1052 #
1053 self.sysfs.link_set_alias(ifaceobj.name, ifaceobj.get_attr_value_first("alias"))
2ff98bb9 1054
d486dd0d
JF
1055 self._sysctl_config(ifaceobj)
1056
68d9fee0 1057 addr_method = ifaceobj.addr_method
77021aa1 1058 force_reapply = False
15ef32ea
RP
1059 try:
1060 # release any stale dhcp addresses if present
223ba5af 1061 if (addr_method not in ["dhcp", "ppp"] and not ifupdownflags.flags.PERFMODE and
15ef32ea
RP
1062 not (ifaceobj.flags & iface.HAS_SIBLINGS)):
1063 # if not running in perf mode and ifaceobj does not have
1064 # any sibling iface objects, kill any stale dhclient
1065 # processes
75afe2a7 1066 dhclientcmd = dhclient()
7c1135ea 1067 if dhclientcmd.is_running(ifaceobj.name):
15ef32ea
RP
1068 # release any dhcp leases
1069 dhclientcmd.release(ifaceobj.name)
223ba5af 1070 self.cache.force_address_flush_family(ifaceobj.name, socket.AF_INET)
77021aa1 1071 force_reapply = True
7c1135ea 1072 elif dhclientcmd.is_running6(ifaceobj.name):
15ef32ea 1073 dhclientcmd.release6(ifaceobj.name)
223ba5af 1074 self.cache.force_address_flush_family(ifaceobj.name, socket.AF_INET6)
77021aa1 1075 force_reapply = True
3218f49d 1076 except Exception:
15ef32ea 1077 pass
8e113d63 1078
2c152f83 1079 self.process_mtu(ifaceobj, ifaceobj_getfunc)
3fc54eef
JF
1080 self.up_ipv6_addrgen(ifaceobj)
1081
a0522546 1082 try:
86bd267c 1083 hwaddress, old_mac_addr = self.process_hwaddress(ifaceobj)
a0522546 1084 except Exception as e:
86bd267c
JF
1085 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
1086
77054f7f 1087 if addr_method not in ["dhcp", "ppp"]:
223ba5af 1088 self.process_addresses(ifaceobj, ifaceobj_getfunc, force_reapply)
2e2dcdaf
JF
1089 else:
1090 # remove old addresses added by ifupdown2
1091 # (if intf was moved from static config to dhcp)
1092 for old_ifaceobj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
1093 for addr in old_ifaceobj.get_attr_value("address") or []:
a3f9506e 1094 self.netlink.addr_del(ifaceobj.name, ipnetwork.IPNetwork(addr))
d486dd0d 1095
13e22530 1096
093ffa00 1097 try:
223ba5af 1098 # Handle special things on a bridge
86bd267c 1099 self._process_bridge(ifaceobj, True, hwaddress, old_mac_addr)
3b01ed76 1100 except Exception as e:
223ba5af 1101 self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj)
d1477c4b 1102
b99c724a
AB
1103 def _settle_dad(self, ifaceobj, ips):
1104 """ Settle dad for any given ips """
1105 def ip_addr_list(what):
1106 raw = json.loads(utils.exec_commandl([
1107 'ip', '-j', '-o', '-6', 'address', 'list', 'dev',
1108 ifaceobj.name, what
1109 ]))
1110 addr_infos = (x for t in raw for x in t.get('addr_info', []))
1111 ip_list = [f'{x["local"]}/{x["prefixlen"]}' for x in addr_infos if x]
1112 return ip_list
1113
1114 def get_param(key, default=None):
1115 return (ifaceobj.get_attr_value_first(key)
1116 or policymanager.policymanager_api.get_iface_default(
1117 self.__class__.__name__, ifaceobj.name, key)
1118 or default)
1119
1120 interval = float(get_param('dad-interval', '0.1')) # 0.1: ifupdown default value
1121 attempts = int(get_param('dad-attempts', '60')) # 60: ifupdown default value
1122 if not attempts or not ips:
1123 return
1124 try:
1125 for _attempt in range(0, attempts):
1126 tentative = ip_addr_list('tentative')
1127 if all(str(ip) not in tentative for ip in ips):
1128 break
cccf76e4 1129 self.logger.info("%s: dad-interval: sleeping for %s" % (ifaceobj.name, interval))
b99c724a
AB
1130 time.sleep(interval)
1131 else:
1132 timeout = ','.join(ip for ip in ips if str(ip) not in tentative)
1133 self.logger.warning('address: %s: dad timeout "%s"', ifaceobj.name, timeout)
1134 return
1135 failure = ip_addr_list('dadfailed')
1136 if failure:
1137 self.logger.warning('address: %s: dad failure "%s"', ifaceobj.name, ','.join(failure))
1138 except subprocess.CalledProcessError as exc:
1139 self.logger.error('address: %s: could not settle dad %s', ifaceobj.name, str(exc))
1140
d594fb86
AB
1141 def _get_ifaceobjs(self, ifaceobj, ifaceobj_getfunc):
1142 squash_addr_config = ifupdownconfig.config.get("addr_config_squash", "0") == "1"
1143 if not squash_addr_config:
1144 return [ifaceobj] # no squash, returns current ifaceobj
1145 if not ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING:
1146 return [] # when squash is present, work only on the youngest sibling
1147 if ifaceobj.flags & iface.HAS_SIBLINGS:
1148 return ifaceobj_getfunc(ifaceobj.name) # get sibling interfaces
1149 return [ifaceobj]
1150
223ba5af 1151 def _up(self, ifaceobj, ifaceobj_getfunc=None):
d1477c4b
JF
1152 gateways = ifaceobj.get_attr_value('gateway')
1153 if not gateways:
1154 gateways = []
1155 prev_gw = self._get_prev_gateway(ifaceobj, gateways)
1156 self._add_delete_gateway(ifaceobj, gateways, prev_gw)
d594fb86
AB
1157 # settle dad
1158 if not self.ipv6_dad_handling_enabled:
1159 return
21a7bd2d
AB
1160 if not self.cache.link_exists(ifaceobj.name):
1161 return
d594fb86
AB
1162 ifname = ifaceobj.name
1163 ifaceobjs = self._get_ifaceobjs(ifaceobj, ifaceobj_getfunc)
1164 addr_supported, user_addrs_list = self.__get_ip_addr_with_attributes(ifaceobjs, ifname)
1165 if not addr_supported:
1166 return
1167 self._settle_dad(ifaceobj, [ip for ip, _ in user_addrs_list if ip.version == 6])
d1477c4b 1168
223ba5af
JF
1169 def process_hwaddress(self, ifaceobj):
1170 hwaddress = self._get_hwaddress(ifaceobj)
d1477c4b 1171
223ba5af
JF
1172 if not hwaddress:
1173 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
1174 # When hwaddress is removed from vlan config
1175 # we should go back to system or bridge mac
1176 for lower in ifaceobj.lowerifaces:
1177 if self.cache.get_link_kind(lower) == "bridge":
1178 hwaddress = self.cache.get_link_address(lower)
1179 break
1180 if not hwaddress:
4e0f16d0 1181 return None, None
223ba5af 1182 else:
4e0f16d0 1183 return None, None
707aeb73 1184
223ba5af
JF
1185 if not ifupdownflags.flags.PERFMODE: # system is clean
1186 running_hwaddress = self.cache.get_link_address(ifaceobj.name)
1187 else:
1188 running_hwaddress = None
1189
1db0cb7a
JF
1190 old_mac_addr = None
1191
859b8643
JF
1192 hwaddress_int = utils.mac_str_to_int(hwaddress)
1193
1194 if hwaddress_int != utils.mac_str_to_int(running_hwaddress):
223ba5af 1195 slave_down = False
c30ed567 1196 if ifaceobj.link_kind & ifaceLinkKind.BOND and ifaceobj.lowerifaces:
223ba5af 1197 # if bond, down all the slaves
c30ed567
JF
1198 for l in ifaceobj.lowerifaces:
1199 self.netlink.link_down(l)
1200 slave_down = True
223ba5af 1201 try:
859b8643 1202 self.netlink.link_set_address(ifaceobj.name, hwaddress, hwaddress_int)
1db0cb7a 1203 old_mac_addr = running_hwaddress
223ba5af
JF
1204 finally:
1205 if slave_down:
1206 for l in ifaceobj.lowerifaces:
1207 self.netlink.link_up(l)
15ef32ea 1208
4e0f16d0 1209 return hwaddress, old_mac_addr
1db0cb7a 1210
0582f185 1211 def _down(self, ifaceobj, ifaceobj_getfunc=None):
15ef32ea 1212 try:
223ba5af 1213 if not self.cache.link_exists(ifaceobj.name):
15ef32ea 1214 return
68d9fee0 1215 addr_method = ifaceobj.addr_method
77054f7f 1216 if addr_method not in ["dhcp", "ppp"]:
aa052170
N
1217 if ifaceobj.get_attr_value_first('address-purge')=='no':
1218 addrlist = ifaceobj.get_attr_value('address')
223ba5af
JF
1219 for addr in addrlist or []:
1220 self.netlink.addr_del(ifaceobj.name, addr)
d486dd0d
JF
1221 elif not ifaceobj.link_kind:
1222 # for logical interfaces we don't need to remove the ip addresses
1223 # kernel will do it for us on 'ip link del'
223ba5af
JF
1224 if ifaceobj_getfunc:
1225 ifaceobj_list = ifaceobj_getfunc(ifaceobj.name) or [ifaceobj]
1226 else:
1227 ifaceobj_list = [ifaceobj]
1228
0e936c3f 1229 for addr in self.cache.get_managed_ip_addresses(ifaceobj.name, ifaceobj_list):
223ba5af
JF
1230 self.netlink.addr_del(ifaceobj.name, addr)
1231
d486dd0d
JF
1232 gateways = ifaceobj.get_attr_value('gateway')
1233 if gateways:
1234 self._delete_gateway(ifaceobj, gateways,
1235 ifaceobj.get_attr_value_first('vrf'),
1236 ifaceobj.get_attr_value_first('metric'))
223ba5af
JF
1237
1238 #
1239 # mtu --
1240 # If device is not a logical intf and has its MTU configured by
1241 # ifupdown2. If this MTU is different from our default mtu,
1242 # if so we need to reset it back to default.
1243 if not ifaceobj.link_kind and self.default_mtu and ifaceobj.get_attr_value_first('mtu') and self.cache.get_link_mtu(ifaceobj.name) != self.default_mtu_int:
1244 self.sysfs.link_set_mtu(ifaceobj.name, mtu_str=self.default_mtu, mtu_int=self.default_mtu_int)
1245
1246 #
1247 # alias
1248 # only reset alias on non-logical device
1249 if not ifaceobj.link_kind:
1250 alias = ifaceobj.get_attr_value_first("alias")
1251 if alias:
1252 self.sysfs.link_set_alias(ifaceobj.name, None) # None to reset alias.
1253
75afe2a7
RP
1254 # XXX hwaddress reset cannot happen because we dont know last
1255 # address.
1256
1257 # Handle special things on a bridge
4e0f16d0
JF
1258 hwaddress = self._get_hwaddress(ifaceobj)
1259 if not hwaddress:
1260 hwaddress = self.cache.get_link_address(ifaceobj.name)
1261 self._process_bridge(ifaceobj, False, hwaddress, None)
3b01ed76 1262 except Exception as e:
bcf11b14
RP
1263 self.logger.debug('%s : %s' %(ifaceobj.name, str(e)))
1264 pass
15ef32ea 1265
8e113d63
RP
1266 def _get_bridge_fdbs(self, bridgename, vlan):
1267 fdbs = self._bridge_fdb_query_cache.get(bridgename)
1268 if not fdbs:
223ba5af 1269 fdbs = self.iproute2.bridge_fdb_show_dev(bridgename)
8e113d63
RP
1270 if not fdbs:
1271 return
1272 self._bridge_fdb_query_cache[bridgename] = fdbs
1273 return fdbs.get(vlan)
1274
1275 def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
1276 """ If the device is a bridge, make sure the addresses
1277 are in the bridge """
d486dd0d
JF
1278 if ifaceobj.link_kind & ifaceLinkKind.VLAN:
1279 bridgename = ifaceobj.lowerifaces[0]
1280 vlan = self._get_vlan_id(ifaceobj)
223ba5af
JF
1281 if self.cache.bridge_is_vlan_aware(bridgename):
1282 fdb_addrs = [utils.mac_str_to_int(fdb_addr) for fdb_addr in self._get_bridge_fdbs(bridgename, str(vlan))]
d1477c4b 1283 if not fdb_addrs:
223ba5af
JF
1284 return False
1285 hwaddress_int = utils.mac_str_to_int(hwaddress)
d1477c4b
JF
1286 if hwaddress_int not in fdb_addrs:
1287 return False
8e113d63
RP
1288 return True
1289
d486dd0d
JF
1290 def _query_sysctl(self, ifaceobj, ifaceobjcurr):
1291 bridge_port = ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
1292 ipforward = ifaceobj.get_attr_value_first('ip-forward')
1293 if ipforward:
1294 if bridge_port:
1295 ifaceobjcurr.status = ifaceStatus.ERROR
1296 ifaceobjcurr.status_str = ('\'ip-forward\' not supported ' +
1297 'for bridge port')
1298 ifaceobjcurr.update_config_with_status('ip-forward', 1, None)
1299 else:
223ba5af 1300 running_ipforward = self.cache.get_netconf_forwarding(socket.AF_INET, ifaceobj.name)
307e814c
JF
1301 config_ipforward = utils.get_boolean_from_string(ipforward)
1302 ifaceobjcurr.update_config_with_status(
1303 'ip-forward',
1304 'on' if running_ipforward else 'off',
1305 running_ipforward != config_ipforward
1306 )
d486dd0d
JF
1307
1308 ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
1309 if ip6forward:
1310 if bridge_port:
1311 ifaceobjcurr.status = ifaceStatus.ERROR
1312 ifaceobjcurr.status_str = ('\'ip6-forward\' not supported ' +
1313 'for bridge port')
1314 ifaceobjcurr.update_config_with_status('ip6-forward', 1, None)
1315 else:
223ba5af 1316 running_ip6forward = self.cache.get_netconf_forwarding(socket.AF_INET6, ifaceobj.name)
307e814c
JF
1317 config_ip6forward = utils.get_boolean_from_string(ip6forward)
1318 ifaceobjcurr.update_config_with_status(
1319 'ip6-forward',
1320 'on' if running_ip6forward else 'off',
1321 running_ip6forward != config_ip6forward
1322 )
d486dd0d
JF
1323 mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
1324 if mpls_enable:
223ba5af 1325 running_mpls_enable = utils.get_yesno_from_onezero(str(self.cache.get_netconf_mpls_input(ifaceobj.name)))
d486dd0d
JF
1326 ifaceobjcurr.update_config_with_status('mpls-enable',
1327 running_mpls_enable,
1328 mpls_enable != running_mpls_enable)
1329 return
1330
007cae35
JF
1331 def query_check_ipv6_addrgen(self, ifaceobj, ifaceobjcurr):
1332 ipv6_addrgen = ifaceobj.get_attr_value_first('ipv6-addrgen')
1333
1334 if not ipv6_addrgen:
1335 return
1336
1337 if ipv6_addrgen in utils._string_values:
1338 ifaceobjcurr.update_config_with_status(
1339 'ipv6-addrgen',
1340 ipv6_addrgen,
223ba5af 1341 utils.get_boolean_from_string(ipv6_addrgen) == self.cache.get_link_ipv6_addrgen_mode(ifaceobj.name)
007cae35
JF
1342 )
1343 else:
1344 ifaceobjcurr.update_config_with_status('ipv6-addrgen', ipv6_addrgen, 1)
1345
0582f185 1346 def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
223ba5af
JF
1347 """
1348 TODO: Check broadcast address, scope, etc
1349 """
15ef32ea 1350 runningaddrsdict = None
223ba5af 1351 if not self.cache.link_exists(ifaceobj.name):
15ef32ea
RP
1352 self.logger.debug('iface %s not found' %ifaceobj.name)
1353 return
007cae35
JF
1354
1355 self.query_check_ipv6_addrgen(ifaceobj, ifaceobjcurr)
1356
16d854b4 1357 addr_method = ifaceobj.addr_method
15ef32ea 1358 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
223ba5af 1359 'mtu', self.cache.get_link_mtu_str)
428206bf 1360 hwaddress = self._get_hwaddress(ifaceobj)
8e113d63 1361 if hwaddress:
223ba5af
JF
1362 rhwaddress = self.cache.get_link_address(ifaceobj.name)
1363 if not rhwaddress or utils.mac_str_to_int(rhwaddress) != utils.mac_str_to_int(hwaddress):
8e113d63
RP
1364 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1365 1)
1366 elif not self._check_addresses_in_bridge(ifaceobj, hwaddress):
1367 # XXX: hw address is not in bridge
1368 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1369 1)
1370 ifaceobjcurr.status_str = 'bridge fdb error'
1371 else:
1372 ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1373 0)
15ef32ea 1374 self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
223ba5af 1375 'alias', self.cache.get_link_alias)
0e936c3f 1376
d486dd0d 1377 self._query_sysctl(ifaceobj, ifaceobjcurr)
9a6a3050 1378
0e936c3f
JF
1379 self._query_check_address(ifaceobj, ifaceobjcurr, ifaceobj_getfunc)
1380
1381 def _query_check_address(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc):
1382 """ ifquery-check: attribute: "address" """
1383 if ifaceobj.addr_method in ["dhcp", "ppp"]:
1384 return
223ba5af
JF
1385
1386 if ifaceobj_getfunc:
1387 ifaceobj_list = ifaceobj_getfunc(ifaceobj.name)
1388 else:
1389 ifaceobj_list = [ifaceobj]
1390
0e936c3f
JF
1391 intf_running_addrs = self.cache.get_managed_ip_addresses(ifaceobj.name, ifaceobj_list)
1392 user_config_addrs = self.cache.get_user_configured_addresses([ifaceobj])
223ba5af
JF
1393
1394 try:
0e936c3f 1395 clagd_vxlan_anycast_ip = ipnetwork.IPNetwork(ifaceobj.get_attr_value_first("clagd-vxlan-anycast-ip"))
223ba5af
JF
1396
1397 if clagd_vxlan_anycast_ip in intf_running_addrs:
1398 user_config_addrs.append(clagd_vxlan_anycast_ip)
3218f49d 1399 except Exception:
223ba5af 1400 pass
15ef32ea
RP
1401
1402 # Set ifaceobjcurr method and family
1403 ifaceobjcurr.addr_method = ifaceobj.addr_method
1404 ifaceobjcurr.addr_family = ifaceobj.addr_family
223ba5af
JF
1405
1406 if not intf_running_addrs and not user_config_addrs:
1407 # The device doesn't have any ips configured and the
1408 # the user didn't specify any ip in the configuration file
15ef32ea 1409 return
223ba5af
JF
1410
1411 for address in user_config_addrs:
1412 ifaceobjcurr.update_config_with_status('address', str(address), address not in intf_running_addrs)
1413 try:
1414 intf_running_addrs.remove(address)
3218f49d 1415 except Exception:
223ba5af
JF
1416 pass
1417
0e936c3f
JF
1418 # if any ip address is left in 'intf_running_addrs' it means that they
1419 # used to be configured by ifupdown2 but not anymore. The entry was
1420 # removed from the configuration file but the IP is still configured on
1421 # the device, so we need to mark them as FAIL (we will only mark them
1422 # as failure on the first sibling).
c30ed567 1423 if ifaceobj.flags & iface.HAS_SIBLINGS and not ifaceobj.flags & iface.YOUNGEST_SIBLING:
223ba5af
JF
1424 return
1425
0e936c3f 1426 all_stanza_user_config_ip = self.cache.get_user_configured_addresses(ifaceobj_list)
223ba5af
JF
1427
1428 for address in intf_running_addrs:
1429 if address not in all_stanza_user_config_ip:
1430 ifaceobjcurr.update_config_with_status('address', str(address), 1)
1431
007cae35 1432 def query_running_ipv6_addrgen(self, ifaceobjrunning):
223ba5af 1433 ipv6_addrgen = self.cache.get_link_ipv6_addrgen_mode(ifaceobjrunning.name)
007cae35
JF
1434
1435 if ipv6_addrgen:
1436 ifaceobjrunning.update_config('ipv6-addrgen', 'off')
1437
0582f185 1438 def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
223ba5af 1439 if not self.cache.link_exists(ifaceobjrunning.name):
15ef32ea 1440 self.logger.debug('iface %s not found' %ifaceobjrunning.name)
15ef32ea 1441 return
007cae35
JF
1442
1443 self.query_running_ipv6_addrgen(ifaceobjrunning)
1444
15ef32ea
RP
1445 dhclientcmd = dhclient()
1446 if (dhclientcmd.is_running(ifaceobjrunning.name) or
1447 dhclientcmd.is_running6(ifaceobjrunning.name)):
1448 # If dhcp is configured on the interface, we skip it
84f33af6 1449 return
223ba5af 1450
0e936c3f 1451 intf_running_addrs = self.cache.get_ip_addresses(ifaceobjrunning.name) or []
223ba5af
JF
1452
1453 if self.cache.link_is_loopback(ifaceobjrunning.name):
1454 for default_addr in self.default_loopback_addresses:
1455 try:
1456 intf_running_addrs.remove(default_addr)
3218f49d 1457 except Exception:
223ba5af 1458 pass
004d1e65 1459 ifaceobjrunning.addr_family.append('inet')
15ef32ea 1460 ifaceobjrunning.addr_method = 'loopback'
223ba5af
JF
1461
1462 for addr in intf_running_addrs:
580a567b 1463 ifaceobjrunning.update_config('address', str(addr))
223ba5af
JF
1464
1465 mtu = self.cache.get_link_mtu_str(ifaceobjrunning.name)
15ef32ea
RP
1466 if (mtu and
1467 (ifaceobjrunning.name == 'lo' and mtu != '16436') or
1468 (ifaceobjrunning.name != 'lo' and
1469 mtu != self.get_mod_subattr('mtu', 'default'))):
1470 ifaceobjrunning.update_config('mtu', mtu)
223ba5af
JF
1471
1472 alias = self.cache.get_link_alias(ifaceobjrunning.name)
84f33af6 1473 if alias:
15ef32ea
RP
1474 ifaceobjrunning.update_config('alias', alias)
1475
63155c61
JF
1476 ifaceobjrunning.update_config("hwaddress", self.cache.get_link_address(ifaceobjrunning.name))
1477
223ba5af
JF
1478 _run_ops = {
1479 'pre-up': _pre_up,
1480 'up': _up,
1481 'down': _down,
1482 'query-checkcurr': _query_check,
1483 'query-running': _query_running
1484 }
15ef32ea
RP
1485
1486 def get_ops(self):
1487 """ returns list of ops supported by this module """
3b01ed76 1488 return list(self._run_ops.keys())
15ef32ea 1489
6e16e5ae 1490 def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
15ef32ea
RP
1491 """ run address configuration on the interface object passed as argument
1492
1493 Args:
1494 **ifaceobj** (object): iface object
1495
1496 **operation** (str): any of 'up', 'down', 'query-checkcurr',
1497 'query-running'
1498 Kwargs:
1499 query_ifaceobj (object): query check ifaceobject. This is only
1500 valid when op is 'query-checkcurr'. It is an object same as
1501 ifaceobj, but contains running attribute values and its config
1502 status. The modules can use it to return queried running state
1503 of interfaces. status is success if the running state is same
1504 as user required state in ifaceobj. error otherwise.
1505 """
8e113d63
RP
1506 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
1507 return
15ef32ea
RP
1508 op_handler = self._run_ops.get(operation)
1509 if not op_handler:
1510 return
15ef32ea 1511 if operation == 'query-checkcurr':
0582f185
RP
1512 op_handler(self, ifaceobj, query_ifaceobj,
1513 ifaceobj_getfunc=ifaceobj_getfunc)
15ef32ea 1514 else:
0582f185
RP
1515 op_handler(self, ifaceobj,
1516 ifaceobj_getfunc=ifaceobj_getfunc)