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