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