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