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