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