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