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