3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
10 from ipaddr
import IPNetwork
, IPv4Network
, IPv6Network
, IPv4Address
, IPv6Address
12 from ifupdown
.iface
import *
13 from ifupdown
.utils
import utils
14 from ifupdownaddons
.modulebase
import moduleBase
15 from ifupdownaddons
.iproute2
import iproute2
16 from ifupdownaddons
.dhclient
import dhclient
17 import ifupdown
.policymanager
as policymanager
18 from ifupdown
.netlink
import netlink
19 import ifupdown
.ifupdownconfig
as ifupdownConfig
20 import ifupdown
.ifupdownflags
as ifupdownflags
21 import ifupdown
.statemanager
as statemanager
22 except ImportError, e
:
23 raise ImportError (str(e
) + "- required module not found")
25 class address(moduleBase
):
26 """ ifupdown2 addon module to configure address, mtu, hwaddress, alias
27 (description) on an interface """
29 _modinfo
= {'mhelp' : 'address configuration module for interfaces',
32 {'help' : 'ipv4 or ipv6 addresses',
33 'validvals' : ['<ipv4/prefixlen>', '<ipv6/prefixlen>'],
35 'example' : ['address 10.0.12.3/24',
36 'address 2000:1000:1000:1000:3::5/128']},
39 'example' : ['netmask 255.255.255.0'],
42 {'help': 'broadcast address',
43 'validvals' : ['<ipv4>', ],
44 'example' : ['broadcast 10.0.1.255']},
47 'validvals' : ['universe', 'site', 'link', 'host', 'nowhere'],
48 'example' : ['scope host']},
49 'preferred-lifetime' :
50 {'help': 'preferred lifetime',
51 'validrange' : ['0', '65535'],
52 'example' : ['preferred-lifetime forever',
53 'preferred-lifetime 10']},
55 {'help': 'default gateway',
56 'validvals' : ['<ipv4>', '<ipv6>'],
58 'example' : ['gateway 255.255.255.0']},
60 { 'help': 'interface mtu',
61 'validrange' : ['552', '9216'],
62 'example' : ['mtu 1600'],
65 {'help' : 'hw address',
66 'validvals' : ['<mac>',],
67 'example': ['hwaddress 44:38:39:00:27:b8']},
69 { 'help': 'description/alias',
70 'example' : ['alias testnetwork']},
72 { 'help': 'purge existing addresses. By default ' +
73 'any existing ip addresses on an interface are ' +
74 'purged to match persistant addresses in the ' +
75 'interfaces file. Set this attribute to \'no\'' +
76 'if you want to preserve existing addresses',
77 'validvals' : ['yes', 'no'],
79 'example' : ['address-purge yes/no']},
80 'clagd-vxlan-anycast-ip' :
81 { 'help' : 'Anycast local IP address for ' +
82 'dual connected VxLANs',
83 'validvals' : ['<ipv4>', ],
84 'example' : ['clagd-vxlan-anycast-ip 36.0.0.11']}}}
86 def __init__(self
, *args
, **kargs
):
87 moduleBase
.__init
__(self
, *args
, **kargs
)
89 self
._bridge
_fdb
_query
_cache
= {}
90 self
.default_mtu
= policymanager
.policymanager_api
.get_attr_default(module_name
=self
.__class
__.__name
__, attr
='mtu')
91 self
.max_mtu
= policymanager
.policymanager_api
.get_module_globals(module_name
=self
.__class
__.__name
__, attr
='max_mtu')
93 if not self
.default_mtu
:
94 self
.default_mtu
= '1500'
96 self
.logger
.info('address: using default mtu %s' %self
.default_mtu
)
99 self
.logger
.info('address: using max mtu %s' %self
.max_mtu
)
101 def syntax_check(self
, ifaceobj
, ifaceobj_getfunc
=None):
102 return (self
.syntax_check_multiple_gateway(ifaceobj
)
103 and self
.syntax_check_addr_allowed_on(ifaceobj
, True)
104 and self
.syntax_check_mtu(ifaceobj
, ifaceobj_getfunc
))
106 def syntax_check_mtu(self
, ifaceobj
, ifaceobj_getfunc
):
107 mtu
= ifaceobj
.get_attr_value_first('mtu')
109 return self
._check
_mtu
_config
(ifaceobj
, mtu
, ifaceobj_getfunc
,
113 def syntax_check_addr_allowed_on(self
, ifaceobj
, syntax_check
=False):
114 if ifaceobj
.get_attr_value('address'):
115 return utils
.is_addr_ip_allowed_on(ifaceobj
, syntax_check
=syntax_check
)
118 def _syntax_check_multiple_gateway(self
, family
, found
, addr
, type_obj
):
119 if type(IPNetwork(addr
)) == type_obj
:
121 raise Exception('%s: multiple gateways for %s family'
126 def syntax_check_multiple_gateway(self
, ifaceobj
):
130 gateways
= ifaceobj
.get_attr_value('gateway')
131 for addr
in gateways
if gateways
else []:
133 if self
._syntax
_check
_multiple
_gateway
('inet', inet
, addr
,
136 if self
._syntax
_check
_multiple
_gateway
('inet6', inet6
, addr
,
139 except Exception as e
:
140 self
.logger
.warning('%s: address: %s' % (ifaceobj
.name
, str(e
)))
144 def _address_valid(self
, addrs
):
147 if any(map(lambda a
: True if a
[:7] != '0.0.0.0'
152 def _get_hwaddress(self
, ifaceobj
):
153 hwaddress
= ifaceobj
.get_attr_value_first('hwaddress')
154 if hwaddress
and hwaddress
.startswith("ether"):
155 hwaddress
= hwaddress
[5:].strip()
158 def _process_bridge(self
, ifaceobj
, up
):
159 hwaddress
= self
._get
_hwaddress
(ifaceobj
)
160 addrs
= ifaceobj
.get_attr_value_first('address')
161 is_vlan_dev_on_vlan_aware_bridge
= False
162 is_bridge
= self
.ipcmd
.is_bridge(ifaceobj
.name
)
164 if '.' in ifaceobj
.name
:
165 (bridgename
, vlan
) = ifaceobj
.name
.split('.')
166 is_vlan_dev_on_vlan_aware_bridge
= self
.ipcmd
.bridge_is_vlan_aware(bridgename
)
167 if ((is_bridge
and not self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
))
168 or is_vlan_dev_on_vlan_aware_bridge
):
169 if self
._address
_valid
(addrs
):
171 self
.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj
.name
+
174 self
.write_file('/proc/sys/net/ipv4/conf/%s' %ifaceobj
.name
+
176 if hwaddress
and is_vlan_dev_on_vlan_aware_bridge
:
178 self
.ipcmd
.bridge_fdb_add(bridgename
, hwaddress
, vlan
)
180 self
.ipcmd
.bridge_fdb_del(bridgename
, hwaddress
, vlan
)
182 def _get_anycast_addr(self
, ifaceobjlist
):
183 for ifaceobj
in ifaceobjlist
:
184 anycast_addr
= ifaceobj
.get_attr_value_first('clagd-vxlan-anycast-ip')
186 anycast_addr
= anycast_addr
+'/32'
190 def _inet_address_convert_to_cidr(self
, ifaceobjlist
):
194 for ifaceobj
in ifaceobjlist
:
195 addrs
= ifaceobj
.get_attr_value('address')
199 if not self
.syntax_check_addr_allowed_on(ifaceobj
,
201 return (False, newaddrs
, newaddr_attrs
)
202 # If user address is not in CIDR notation, convert them to CIDR
203 for addr_index
in range(0, len(addrs
)):
204 addr
= addrs
[addr_index
]
207 newaddrs
.append(addr
)
209 netmask
= ifaceobj
.get_attr_value_n('netmask', addr_index
)
211 prefixlen
= IPNetwork('%s' %addr
+
212 '/%s' %netmask
).prefixlen
213 newaddr
= addr
+ '/%s' %prefixlen
215 # we are here because there is no slash (/xx) and no netmask
216 # just let IPNetwork handle the ipv4 or ipv6 address mask
217 prefixlen
= IPNetwork(addr
).prefixlen
218 newaddr
= addr
+ '/%s' %prefixlen
219 newaddrs
.append(newaddr
)
222 for a
in ['broadcast', 'pointopoint', 'scope',
223 'preferred-lifetime']:
224 aval
= ifaceobj
.get_attr_value_n(a
, addr_index
)
229 newaddr_attrs
[newaddr
]= attrs
230 return (True, newaddrs
, newaddr_attrs
)
232 def _inet_address_list_config(self
, ifaceobj
, newaddrs
, newaddr_attrs
):
233 for addr_index
in range(0, len(newaddrs
)):
236 self
.ipcmd
.addr_add(ifaceobj
.name
, newaddrs
[addr_index
],
237 newaddr_attrs
.get(newaddrs
[addr_index
],
238 {}).get('broadcast'),
239 newaddr_attrs
.get(newaddrs
[addr_index
],
240 {}).get('pointopoint'),
241 newaddr_attrs
.get(newaddrs
[addr_index
],
243 newaddr_attrs
.get(newaddrs
[addr_index
],
244 {}).get('preferred-lifetime'))
246 self
.ipcmd
.addr_add(ifaceobj
.name
, newaddrs
[addr_index
])
248 self
.log_error(str(e
), ifaceobj
)
250 def _inet_address_config(self
, ifaceobj
, ifaceobj_getfunc
=None,
251 force_reapply
=False):
252 squash_addr_config
= (True if \
253 ifupdownConfig
.config
.get('addr_config_squash', \
254 '0') == '1' else False)
256 if (squash_addr_config
and
257 not (ifaceobj
.flags
& ifaceobj
.YOUNGEST_SIBLING
)):
260 purge_addresses
= ifaceobj
.get_attr_value_first('address-purge')
261 if not purge_addresses
:
262 purge_addresses
= 'yes'
264 if squash_addr_config
and ifaceobj
.flags
& iface
.HAS_SIBLINGS
:
265 ifaceobjlist
= ifaceobj_getfunc(ifaceobj
.name
)
267 ifaceobjlist
= [ifaceobj
]
269 (addr_supported
, newaddrs
, newaddr_attrs
) = self
._inet
_address
_convert
_to
_cidr
(ifaceobjlist
)
270 newaddrs
= utils
.get_normalized_ip_addr(ifaceobj
.name
, newaddrs
)
271 if not addr_supported
:
273 if (not squash_addr_config
and (ifaceobj
.flags
& iface
.HAS_SIBLINGS
)):
274 # if youngest sibling and squash addr is not set
275 # print a warning that addresses will not be purged
276 if (ifaceobj
.flags
& iface
.YOUNGEST_SIBLING
):
277 self
.logger
.warn('%s: interface has multiple ' %ifaceobj
.name
+
278 'iface stanzas, skip purging existing addresses')
279 purge_addresses
= 'no'
281 if not ifupdownflags
.flags
.PERFMODE
and purge_addresses
== 'yes':
282 # if perfmode is not set and purge addresses is not set to 'no'
283 # lets purge addresses not in the config
284 runningaddrs
= utils
.get_normalized_ip_addr(ifaceobj
.name
, self
.ipcmd
.addr_get(ifaceobj
.name
, details
=False))
286 # if anycast address is configured on 'lo' and is in running config
287 # add it to newaddrs so that ifreload doesn't wipe it out
288 anycast_addr
= utils
.get_normalized_ip_addr(ifaceobj
.name
, self
._get
_anycast
_addr
(ifaceobjlist
))
290 if runningaddrs
and anycast_addr
and anycast_addr
in runningaddrs
:
291 newaddrs
.append(anycast_addr
)
292 if newaddrs
== runningaddrs
:
294 self
._inet
_address
_list
_config
(ifaceobj
, newaddrs
, newaddr_attrs
)
297 # if primary address is not same, there is no need to keep any.
298 # reset all addresses
299 if (newaddrs
and runningaddrs
and
300 (newaddrs
[0] != runningaddrs
[0])):
301 self
.ipcmd
.del_addr_all(ifaceobj
.name
)
303 self
.ipcmd
.del_addr_all(ifaceobj
.name
, newaddrs
)
305 self
.log_warn(str(e
))
308 self
._inet
_address
_list
_config
(ifaceobj
, newaddrs
, newaddr_attrs
)
310 def _add_delete_gateway(self
, ifaceobj
, gateways
=[], prev_gw
=[]):
311 vrf
= ifaceobj
.get_attr_value_first('vrf')
312 metric
= ifaceobj
.get_attr_value_first('metric')
313 for del_gw
in list(set(prev_gw
) - set(gateways
)):
315 self
.ipcmd
.route_del_gateway(ifaceobj
.name
, del_gw
, vrf
, metric
)
316 except Exception as e
:
317 self
.logger
.debug('%s: %s' % (ifaceobj
.name
, str(e
)))
318 for add_gw
in gateways
:
320 self
.ipcmd
.route_add_gateway(ifaceobj
.name
, add_gw
, vrf
)
321 except Exception as e
:
322 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)))
324 def _get_prev_gateway(self
, ifaceobj
, gateways
):
326 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(ifaceobj
.name
)
327 if not saved_ifaceobjs
:
329 prev_gateways
= saved_ifaceobjs
[0].get_attr_value('gateway')
330 if not prev_gateways
:
334 def _check_mtu_config(self
, ifaceobj
, mtu
, ifaceobj_getfunc
, syntaxcheck
=False):
336 if (ifaceobj
.link_kind
& ifaceLinkKind
.BRIDGE
):
338 self
.logger
.warn('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj
.name
)
341 self
.logger
.info('%s: bridge inherits mtu from its ports. There is no need to assign mtu on a bridge' %ifaceobj
.name
)
342 elif ifaceobj_getfunc
:
343 if ((ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BOND_SLAVE
) and
344 ifaceobj
.upperifaces
):
345 masterobj
= ifaceobj_getfunc(ifaceobj
.upperifaces
[0])
347 master_mtu
= masterobj
[0].get_attr_value_first('mtu')
348 if master_mtu
and master_mtu
!= mtu
:
350 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
))
353 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
))
354 elif ((ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
) and
355 ifaceobj
.lowerifaces
):
356 lowerobj
= ifaceobj_getfunc(ifaceobj
.lowerifaces
[0])
359 lowerdev_mtu
= lowerobj
[0].get_attr_value_first('mtu')
361 lowerdev_mtu
= self
.ipcmd
.link_get_mtu(lowerobj
[0].name
)
362 if lowerdev_mtu
and int(mtu
) > int(lowerdev_mtu
):
363 self
.logger
.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
364 %(ifaceobj
.name
, mtu
, lowerobj
[0].name
, lowerdev_mtu
))
366 elif (not lowerobj
[0].link_kind
and
367 not (lowerobj
[0].link_privflags
& ifaceLinkPrivFlags
.LOOPBACK
) and
368 self
.default_mtu
and (int(mtu
) > int(self
.default_mtu
))):
369 # only check default mtu on lower device which is a physical interface
370 self
.logger
.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
371 %(ifaceobj
.name
, mtu
, lowerobj
[0].name
, self
.default_mtu
))
373 if self
.max_mtu
and mtu
> self
.max_mtu
:
374 self
.logger
.warn('%s: specified mtu %s is greater than max mtu %s'
375 %(ifaceobj
.name
, mtu
, self
.max_mtu
))
379 def _propagate_mtu_to_upper_devs(self
, ifaceobj
, mtu
, ifaceobj_getfunc
):
380 if (not ifaceobj
.upperifaces
or
381 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BOND_SLAVE
) or
382 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
) or
383 (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BRIDGE_PORT
)):
385 for u
in ifaceobj
.upperifaces
:
386 upperobjs
= ifaceobj_getfunc(u
)
388 not (upperobjs
[0].link_kind
& ifaceLinkKind
.VLAN
)):
390 # only adjust mtu for vlan devices on ifaceobj
391 umtu
= upperobjs
[0].get_attr_value_first('mtu')
393 running_mtu
= self
.ipcmd
.link_get_mtu(upperobjs
[0].name
)
394 if not running_mtu
or (running_mtu
!= mtu
):
395 self
.ipcmd
.link_set(u
, 'mtu', mtu
)
397 def _process_mtu_config(self
, ifaceobj
, ifaceobj_getfunc
):
398 mtu
= ifaceobj
.get_attr_value_first('mtu')
400 if not self
._check
_mtu
_config
(ifaceobj
, mtu
, ifaceobj_getfunc
):
402 running_mtu
= self
.ipcmd
.link_get_mtu(ifaceobj
.name
)
403 if not running_mtu
or (running_mtu
and running_mtu
!= mtu
):
404 self
.ipcmd
.link_set(ifaceobj
.name
, 'mtu', mtu
)
405 if (not ifupdownflags
.flags
.ALL
and
406 not ifaceobj
.link_kind
and
407 ifupdownConfig
.config
.get('adjust_logical_dev_mtu', '1') != '0'):
408 # This is additional cost to us, so do it only when
409 # ifupdown2 is called on a particular interface and
410 # it is a physical interface
411 self
._propagate
_mtu
_to
_upper
_devs
(ifaceobj
, mtu
, ifaceobj_getfunc
)
414 if ifaceobj
.link_kind
:
415 # bonds and vxlan devices need an explicit set of mtu.
416 # bridges don't need mtu set
417 if (ifaceobj
.link_kind
& ifaceLinkKind
.BOND
or
418 ifaceobj
.link_kind
& ifaceLinkKind
.VXLAN
):
419 running_mtu
= self
.ipcmd
.link_get_mtu(ifaceobj
.name
)
420 if (self
.default_mtu
and running_mtu
!= self
.default_mtu
):
421 self
.ipcmd
.link_set(ifaceobj
.name
, 'mtu', self
.default_mtu
)
423 if (ifupdownConfig
.config
.get('adjust_logical_dev_mtu', '1') != '0'
424 and ifaceobj
.lowerifaces
):
425 # set vlan interface mtu to lower device mtu
426 if (ifaceobj
.link_kind
& ifaceLinkKind
.VLAN
):
427 lower_iface_mtu
= self
.ipcmd
.link_get_mtu(ifaceobj
.lowerifaces
[0], refresh
=True)
428 if not lower_iface_mtu
== self
.ipcmd
.link_get_mtu(ifaceobj
.name
):
429 self
.ipcmd
.link_set_mtu(ifaceobj
.name
, lower_iface_mtu
)
431 elif (not (ifaceobj
.name
== 'lo') and not ifaceobj
.link_kind
and
432 not (ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.BOND_SLAVE
) and
434 # logical devices like bridges and vlan devices rely on mtu
435 # from their lower devices. ie mtu travels from
436 # lower devices to upper devices. For bonds mtu travels from
437 # upper to lower devices. running mtu depends on upper and
438 # lower device mtu. With all this implicit mtu
439 # config by the kernel in play, we try to be cautious here
440 # on which devices we want to reset mtu to default.
441 # essentially only physical interfaces which are not bond slaves
442 running_mtu
= self
.ipcmd
.link_get_mtu(ifaceobj
.name
)
443 if running_mtu
!= self
.default_mtu
:
444 self
.ipcmd
.link_set(ifaceobj
.name
, 'mtu', self
.default_mtu
)
446 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
447 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
450 alias
= ifaceobj
.get_attr_value_first('alias')
451 current_alias
= self
.ipcmd
.link_get_alias(ifaceobj
.name
)
452 if alias
and alias
!= current_alias
:
453 self
.ipcmd
.link_set_alias(ifaceobj
.name
, alias
)
454 elif not alias
and current_alias
:
455 self
.ipcmd
.link_set_alias(ifaceobj
.name
, '')
457 addr_method
= ifaceobj
.addr_method
458 force_reapply
= False
460 # release any stale dhcp addresses if present
461 if (addr_method
not in ["dhcp", "ppp"] and not ifupdownflags
.flags
.PERFMODE
and
462 not (ifaceobj
.flags
& iface
.HAS_SIBLINGS
)):
463 # if not running in perf mode and ifaceobj does not have
464 # any sibling iface objects, kill any stale dhclient
466 dhclientcmd
= dhclient()
467 if dhclientcmd
.is_running(ifaceobj
.name
):
468 # release any dhcp leases
469 dhclientcmd
.release(ifaceobj
.name
)
471 elif dhclientcmd
.is_running6(ifaceobj
.name
):
472 dhclientcmd
.release6(ifaceobj
.name
)
477 self
.ipcmd
.batch_start()
478 if addr_method
not in ["dhcp", "ppp"]:
479 self
._inet
_address
_config
(ifaceobj
, ifaceobj_getfunc
,
481 self
._process
_mtu
_config
(ifaceobj
, ifaceobj_getfunc
)
484 self
.ipcmd
.batch_commit()
485 except Exception as e
:
486 self
.log_error('%s: %s' % (ifaceobj
.name
, str(e
)), ifaceobj
, raise_error
=False)
489 hwaddress
= self
._get
_hwaddress
(ifaceobj
)
491 running_hwaddress
= None
492 if not ifupdownflags
.flags
.PERFMODE
: # system is clean
493 running_hwaddress
= self
.ipcmd
.link_get_hwaddress(ifaceobj
.name
)
494 if hwaddress
!= running_hwaddress
:
496 netlink
.link_set_updown(ifaceobj
.name
, "down")
497 if ifaceobj
.link_kind
& ifaceLinkKind
.BOND
:
498 # if bond, down all the slaves
499 if ifaceobj
.lowerifaces
:
500 for l
in ifaceobj
.lowerifaces
:
501 netlink
.link_set_updown(l
, "down")
504 self
.ipcmd
.link_set(ifaceobj
.name
, 'address', hwaddress
)
506 netlink
.link_set_updown(ifaceobj
.name
, "up")
508 for l
in ifaceobj
.lowerifaces
:
509 netlink
.link_set_updown(l
, "up")
511 # Handle special things on a bridge
512 self
._process
_bridge
(ifaceobj
, True)
514 self
.log_error('%s: %s' %(ifaceobj
.name
, str(e
)), ifaceobj
)
516 if addr_method
not in ["dhcp", "ppp"]:
517 gateways
= ifaceobj
.get_attr_value('gateway')
520 prev_gw
= self
._get
_prev
_gateway
(ifaceobj
, gateways
)
521 self
._add
_delete
_gateway
(ifaceobj
, gateways
, prev_gw
)
524 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
526 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
528 addr_method
= ifaceobj
.addr_method
529 if addr_method
not in ["dhcp", "ppp"]:
530 if ifaceobj
.get_attr_value_first('address-purge')=='no':
531 addrlist
= ifaceobj
.get_attr_value('address')
532 for addr
in addrlist
:
533 self
.ipcmd
.addr_del(ifaceobj
.name
, addr
)
534 #self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0])
536 self
.ipcmd
.del_addr_all(ifaceobj
.name
)
537 mtu
= ifaceobj
.get_attr_value_first('mtu')
538 if (not ifaceobj
.link_kind
and mtu
and
539 self
.default_mtu
and (mtu
!= self
.default_mtu
)):
540 self
.ipcmd
.link_set(ifaceobj
.name
, 'mtu', self
.default_mtu
)
541 alias
= ifaceobj
.get_attr_value_first('alias')
543 filename
= '/sys/class/net/%s/ifalias' %ifaceobj
.name
544 self
.logger
.info('executing echo "" > %s' %filename
)
545 os
.system('echo "" > %s' %filename
)
546 # XXX hwaddress reset cannot happen because we dont know last
549 # Handle special things on a bridge
550 self
._process
_bridge
(ifaceobj
, False)
552 self
.logger
.debug('%s : %s' %(ifaceobj
.name
, str(e
)))
555 def _get_iface_addresses(self
, ifaceobj
):
556 addrlist
= ifaceobj
.get_attr_value('address')
559 if not addrlist
: return None
560 for addrindex
in range(0, len(addrlist
)):
561 addr
= addrlist
[addrindex
]
562 netmask
= ifaceobj
.get_attr_value_n('netmask', addrindex
)
564 prefixlen
= IPNetwork('%s' %addr
+
565 '/%s' %netmask
).prefixlen
566 addr
= addr
+ '/%s' %prefixlen
567 outaddrlist
.append(addr
)
570 def _get_bridge_fdbs(self
, bridgename
, vlan
):
571 fdbs
= self
._bridge
_fdb
_query
_cache
.get(bridgename
)
573 fdbs
= self
.ipcmd
.bridge_fdb_show_dev(bridgename
)
576 self
._bridge
_fdb
_query
_cache
[bridgename
] = fdbs
577 return fdbs
.get(vlan
)
579 def _check_addresses_in_bridge(self
, ifaceobj
, hwaddress
):
580 """ If the device is a bridge, make sure the addresses
581 are in the bridge """
582 if '.' in ifaceobj
.name
:
583 (bridgename
, vlan
) = ifaceobj
.name
.split('.')
584 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
585 fdb_addrs
= self
._get
_bridge
_fdbs
(bridgename
, vlan
)
586 if not fdb_addrs
or hwaddress
not in fdb_addrs
:
590 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
591 runningaddrsdict
= None
592 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
593 self
.logger
.debug('iface %s not found' %ifaceobj
.name
)
595 addr_method
= ifaceobj
.addr_method
596 self
.query_n_update_ifaceobjcurr_attr(ifaceobj
, ifaceobjcurr
,
597 'mtu', self
.ipcmd
.link_get_mtu
)
598 hwaddress
= self
._get
_hwaddress
(ifaceobj
)
600 rhwaddress
= self
.ipcmd
.link_get_hwaddress(ifaceobj
.name
)
601 if not rhwaddress
or rhwaddress
!= hwaddress
:
602 ifaceobjcurr
.update_config_with_status('hwaddress', rhwaddress
,
604 elif not self
._check
_addresses
_in
_bridge
(ifaceobj
, hwaddress
):
605 # XXX: hw address is not in bridge
606 ifaceobjcurr
.update_config_with_status('hwaddress', rhwaddress
,
608 ifaceobjcurr
.status_str
= 'bridge fdb error'
610 ifaceobjcurr
.update_config_with_status('hwaddress', rhwaddress
,
612 self
.query_n_update_ifaceobjcurr_attr(ifaceobj
, ifaceobjcurr
,
613 'alias', self
.ipcmd
.link_get_alias
)
615 if addr_method
in ["dhcp", "ppp"]:
617 addrs
= utils
.get_normalized_ip_addr(ifaceobj
.name
,
618 self
._get
_iface
_addresses
(ifaceobj
))
619 runningaddrsdict
= self
.ipcmd
.addr_get(ifaceobj
.name
)
620 # if anycast address is configured on 'lo' and is in running config
621 # add it to addrs so that query_check doesn't fail
622 anycast_addr
= utils
.get_normalized_ip_addr(ifaceobj
.name
, ifaceobj
.get_attr_value_first('clagd-vxlan-anycast-ip'))
624 anycast_addr
= anycast_addr
+'/32'
625 if runningaddrsdict
and anycast_addr
and runningaddrsdict
.get(anycast_addr
):
626 addrs
.append(anycast_addr
)
628 # Set ifaceobjcurr method and family
629 ifaceobjcurr
.addr_method
= ifaceobj
.addr_method
630 ifaceobjcurr
.addr_family
= ifaceobj
.addr_family
631 if not runningaddrsdict
and not addrs
:
633 runningaddrs
= runningaddrsdict
.keys() if runningaddrsdict
else []
634 # Add /32 netmask to configured address without netmask.
635 # This may happen on interfaces where pointopoint is used.
636 runningaddrs
= [ addr
if '/' in addr
else addr
+ '/32' for addr
in runningaddrs
]
637 if runningaddrs
!= addrs
:
638 runningaddrsset
= set(runningaddrs
) if runningaddrs
else set([])
639 addrsset
= set(addrs
) if addrs
else set([])
640 if (ifaceobj
.flags
& iface
.HAS_SIBLINGS
):
643 # only check for addresses present in running config
644 addrsdiff
= addrsset
.difference(runningaddrsset
)
646 if addr
in addrsdiff
:
647 ifaceobjcurr
.update_config_with_status('address',
650 ifaceobjcurr
.update_config_with_status('address',
653 addrsdiff
= addrsset
.symmetric_difference(runningaddrsset
)
654 for addr
in addrsset
.union(runningaddrsset
):
655 if addr
in addrsdiff
:
656 ifaceobjcurr
.update_config_with_status('address',
659 ifaceobjcurr
.update_config_with_status('address',
662 [ifaceobjcurr
.update_config_with_status('address',
663 addr
, 0) for addr
in addrs
]
664 #XXXX Check broadcast address, scope, etc
667 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
668 if not self
.ipcmd
.link_exists(ifaceobjrunning
.name
):
669 self
.logger
.debug('iface %s not found' %ifaceobjrunning
.name
)
671 dhclientcmd
= dhclient()
672 if (dhclientcmd
.is_running(ifaceobjrunning
.name
) or
673 dhclientcmd
.is_running6(ifaceobjrunning
.name
)):
674 # If dhcp is configured on the interface, we skip it
676 isloopback
= self
.ipcmd
.link_isloopback(ifaceobjrunning
.name
)
678 default_addrs
= ['127.0.0.1/8', '::1/128']
679 ifaceobjrunning
.addr_family
.append('inet')
680 ifaceobjrunning
.addr_method
= 'loopback'
683 runningaddrsdict
= self
.ipcmd
.addr_get(ifaceobjrunning
.name
)
685 [ifaceobjrunning
.update_config('address', addr
)
686 for addr
, addrattrs
in runningaddrsdict
.items()
687 if addr
not in default_addrs
]
688 mtu
= self
.ipcmd
.link_get_mtu(ifaceobjrunning
.name
)
690 (ifaceobjrunning
.name
== 'lo' and mtu
!= '16436') or
691 (ifaceobjrunning
.name
!= 'lo' and
692 mtu
!= self
.get_mod_subattr('mtu', 'default'))):
693 ifaceobjrunning
.update_config('mtu', mtu
)
694 alias
= self
.ipcmd
.link_get_alias(ifaceobjrunning
.name
)
696 ifaceobjrunning
.update_config('alias', alias
)
699 _run_ops
= {'up' : _up
,
701 'query-checkcurr' : _query_check
,
702 'query-running' : _query_running
}
705 """ returns list of ops supported by this module """
706 return self
._run
_ops
.keys()
708 def _init_command_handlers(self
):
710 self
.ipcmd
= iproute2()
712 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, ifaceobj_getfunc
=None):
713 """ run address configuration on the interface object passed as argument
716 **ifaceobj** (object): iface object
718 **operation** (str): any of 'up', 'down', 'query-checkcurr',
721 query_ifaceobj (object): query check ifaceobject. This is only
722 valid when op is 'query-checkcurr'. It is an object same as
723 ifaceobj, but contains running attribute values and its config
724 status. The modules can use it to return queried running state
725 of interfaces. status is success if the running state is same
726 as user required state in ifaceobj. error otherwise.
728 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
730 op_handler
= self
._run
_ops
.get(operation
)
733 self
._init
_command
_handlers
()
734 if operation
== 'query-checkcurr':
735 op_handler(self
, ifaceobj
, query_ifaceobj
,
736 ifaceobj_getfunc
=ifaceobj_getfunc
)
738 op_handler(self
, ifaceobj
,
739 ifaceobj_getfunc
=ifaceobj_getfunc
)