2014-10-09 16:02:46 -07:00
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
2016-03-10 01:40:15 +01:00
import os
2014-10-09 16:02:46 -07:00
try :
2016-05-31 13:12:21 -07:00
from ipaddr import IPNetwork , IPv4Network , IPv6Network , IPv4Address , IPv6Address
2014-10-09 16:02:46 -07:00
from sets import Set
from ifupdown . iface import *
2016-09-14 16:00:25 -07:00
from ifupdown . utils import utils
2014-10-09 16:02:46 -07:00
from ifupdownaddons . modulebase import moduleBase
from ifupdownaddons . iproute2 import iproute2
from ifupdownaddons . dhclient import dhclient
2016-04-15 10:16:53 +02:00
import ifupdown . policymanager as policymanager
2016-05-29 18:04:23 +01:00
from ifupdown . netlink import netlink
2015-11-16 21:00:40 -08:00
import ifupdown . ifupdownconfig as ifupdownConfig
2016-04-14 14:45:47 -07:00
import ifupdown . ifupdownflags as ifupdownflags
2016-07-20 15:23:13 -07:00
import ifupdown . statemanager as statemanager
2014-10-09 16:02:46 -07:00
except ImportError , e :
raise ImportError ( str ( e ) + " - required module not found " )
class address ( moduleBase ) :
""" ifupdown2 addon module to configure address, mtu, hwaddress, alias
( description ) on an interface """
_modinfo = { ' mhelp ' : ' address configuration module for interfaces ' ,
' attrs ' : {
' address ' :
{ ' help ' : ' ipv4 or ipv6 addresses ' ,
2016-08-01 09:19:31 +02:00
' validvals ' : [ ' <ipv4/prefixlen> ' , ' <ipv6/prefixlen> ' ] ,
2016-05-31 13:12:21 -07:00
' multiline ' : True ,
2014-10-09 16:02:46 -07:00
' example ' : [ ' address 10.0.12.3/24 ' ,
' address 2000:1000:1000:1000:3::5/128 ' ] } ,
' netmask ' :
{ ' help ' : ' netmask ' ,
' example ' : [ ' netmask 255.255.255.0 ' ] ,
' compat ' : True } ,
' broadcast ' :
{ ' help ' : ' broadcast address ' ,
2016-08-01 09:19:31 +02:00
' validvals ' : [ ' <ipv4> ' , ] ,
2014-10-09 16:02:46 -07:00
' example ' : [ ' broadcast 10.0.1.255 ' ] } ,
' scope ' :
{ ' help ' : ' scope ' ,
2016-05-31 13:12:21 -07:00
' validvals ' : [ ' universe ' , ' site ' , ' link ' , ' host ' , ' nowhere ' ] ,
2014-10-09 16:02:46 -07:00
' example ' : [ ' scope host ' ] } ,
' preferred-lifetime ' :
{ ' help ' : ' preferred lifetime ' ,
2016-05-31 13:12:21 -07:00
' validrange ' : [ ' 0 ' , ' 65535 ' ] ,
2014-10-09 16:02:46 -07:00
' example ' : [ ' preferred-lifetime forever ' ,
' preferred-lifetime 10 ' ] } ,
' gateway ' :
{ ' help ' : ' default gateway ' ,
2016-08-01 09:19:31 +02:00
' validvals ' : [ ' <ipv4> ' , ' <ipv6> ' ] ,
2016-09-07 16:57:55 +00:00
' multiline ' : True ,
2014-10-09 16:02:46 -07:00
' example ' : [ ' gateway 255.255.255.0 ' ] } ,
' mtu ' :
{ ' help ' : ' interface mtu ' ,
2016-05-31 13:12:21 -07:00
' validrange ' : [ ' 552 ' , ' 9216 ' ] ,
2014-10-09 16:02:46 -07:00
' example ' : [ ' mtu 1600 ' ] ,
' default ' : ' 1500 ' } ,
' hwaddress ' :
{ ' help ' : ' hw address ' ,
2016-05-31 13:12:21 -07:00
' validvals ' : [ ' <mac> ' , ] ,
2014-10-09 16:02:46 -07:00
' example ' : [ ' hwaddress 44:38:39:00:27:b8 ' ] } ,
' alias ' :
{ ' help ' : ' description/alias ' ,
2014-11-11 21:08:38 -08:00
' example ' : [ ' alias testnetwork ' ] } ,
' address-purge ' :
{ ' help ' : ' purge existing addresses. By default ' +
' any existing ip addresses on an interface are ' +
' purged to match persistant addresses in the ' +
' interfaces file. Set this attribute to \' no \' ' +
' if you want to preserve existing addresses ' ,
2016-05-31 13:12:21 -07:00
' validvals ' : [ ' yes ' , ' no ' ] ,
2014-11-11 21:08:38 -08:00
' default ' : ' yes ' ,
2015-09-04 00:32:15 -07:00
' example ' : [ ' address-purge yes/no ' ] } ,
' clagd-vxlan-anycast-ip ' :
{ ' help ' : ' Anycast local IP address for ' +
' dual connected VxLANs ' ,
2016-08-01 09:19:31 +02:00
' validvals ' : [ ' <ipv4> ' , ] ,
2015-09-04 00:32:15 -07:00
' example ' : [ ' clagd-vxlan-anycast-ip 36.0.0.11 ' ] } } }
2014-10-09 16:02:46 -07:00
def __init__ ( self , * args , * * kargs ) :
moduleBase . __init__ ( self , * args , * * kargs )
self . ipcmd = None
2014-11-03 17:55:51 -08:00
self . _bridge_fdb_query_cache = { }
2016-04-15 10:16:53 +02:00
self . default_mtu = policymanager . policymanager_api . get_attr_default ( module_name = self . __class__ . __name__ , attr = ' mtu ' )
2016-11-07 10:48:24 -08:00
self . max_mtu = policymanager . policymanager_api . get_module_globals ( module_name = self . __class__ . __name__ , attr = ' max_mtu ' )
if not self . default_mtu :
self . default_mtu = ' 1500 '
self . logger . info ( ' address: using default mtu %s ' % self . default_mtu )
if self . max_mtu :
self . logger . info ( ' address: using max mtu %s ' % self . max_mtu )
2014-10-09 16:02:46 -07:00
2014-11-17 16:23:42 -08:00
def _address_valid ( self , addrs ) :
if not addrs :
return False
if any ( map ( lambda a : True if a [ : 7 ] != ' 0.0.0.0 '
else False , addrs ) ) :
return True
return False
2016-03-15 15:41:04 +01:00
def _get_hwaddress ( self , ifaceobj ) :
2016-03-11 15:56:34 -08:00
hwaddress = ifaceobj . get_attr_value_first ( ' hwaddress ' )
2016-03-15 15:41:04 +01:00
if hwaddress and hwaddress . startswith ( " ether " ) :
hwaddress = hwaddress [ 5 : ] . strip ( )
return hwaddress
def _process_bridge ( self , ifaceobj , up ) :
hwaddress = self . _get_hwaddress ( ifaceobj )
2014-11-17 16:23:42 -08:00
addrs = ifaceobj . get_attr_value_first ( ' address ' )
is_vlan_dev_on_vlan_aware_bridge = False
is_bridge = self . ipcmd . is_bridge ( ifaceobj . name )
if not is_bridge :
if ' . ' in ifaceobj . name :
( bridgename , vlan ) = ifaceobj . name . split ( ' . ' )
is_vlan_dev_on_vlan_aware_bridge = self . ipcmd . bridge_is_vlan_aware ( bridgename )
2014-12-17 15:09:52 -08:00
if ( ( is_bridge and not self . ipcmd . bridge_is_vlan_aware ( ifaceobj . name ) )
or is_vlan_dev_on_vlan_aware_bridge ) :
2014-11-17 16:23:42 -08:00
if self . _address_valid ( addrs ) :
if up :
self . write_file ( ' /proc/sys/net/ipv4/conf/ %s ' % ifaceobj . name +
' /arp_accept ' , ' 1 ' )
else :
self . write_file ( ' /proc/sys/net/ipv4/conf/ %s ' % ifaceobj . name +
' /arp_accept ' , ' 0 ' )
if hwaddress and is_vlan_dev_on_vlan_aware_bridge :
if up :
self . ipcmd . bridge_fdb_add ( bridgename , hwaddress , vlan )
else :
self . ipcmd . bridge_fdb_del ( bridgename , hwaddress , vlan )
2014-10-28 23:04:40 -07:00
2015-11-16 21:00:40 -08:00
def _get_anycast_addr ( self , ifaceobjlist ) :
for ifaceobj in ifaceobjlist :
anycast_addr = ifaceobj . get_attr_value_first ( ' clagd-vxlan-anycast-ip ' )
if anycast_addr :
anycast_addr = anycast_addr + ' /32 '
return anycast_addr
return None
def _inet_address_convert_to_cidr ( self , ifaceobjlist ) :
2014-10-09 16:02:46 -07:00
newaddrs = [ ]
2015-11-16 21:00:40 -08:00
newaddr_attrs = { }
for ifaceobj in ifaceobjlist :
addrs = ifaceobj . get_attr_value ( ' address ' )
if not addrs :
continue
2016-03-30 11:54:58 -07:00
if ( ( ( ifaceobj . role & ifaceRole . SLAVE ) and
not ( ifaceobj . link_privflags & ifaceLinkPrivFlags . VRF_SLAVE ) ) or
( ( ifaceobj . link_kind & ifaceLinkKind . BRIDGE ) and
( ifaceobj . link_privflags & ifaceLinkPrivFlags . BRIDGE_VLAN_AWARE ) ) ) :
2015-10-09 16:32:02 -07:00
# we must not configure an IP address if the interface is
# enslaved or is a VLAN AWARE BRIDGE
self . logger . info ( ' %s : ignoring ip address. Interface is '
' enslaved or a vlan aware bridge and cannot '
' have an IP Address ' % ( ifaceobj . name ) )
2015-11-16 21:00:40 -08:00
return ( False , newaddrs , newaddr_attrs )
2014-10-09 16:02:46 -07:00
# If user address is not in CIDR notation, convert them to CIDR
for addr_index in range ( 0 , len ( addrs ) ) :
addr = addrs [ addr_index ]
if ' / ' in addr :
newaddrs . append ( addr )
continue
2015-12-23 19:23:51 -08:00
newaddr = addr
2014-10-09 16:02:46 -07:00
netmask = ifaceobj . get_attr_value_n ( ' netmask ' , addr_index )
if netmask :
prefixlen = IPNetwork ( ' %s ' % addr +
' / %s ' % netmask ) . prefixlen
2015-11-16 21:00:40 -08:00
newaddr = addr + ' / %s ' % prefixlen
2016-05-19 08:14:13 -07:00
else :
# we are here because there is no slash (/xx) and no netmask
# just let IPNetwork handle the ipv4 or ipv6 address mask
prefixlen = IPNetwork ( addr ) . prefixlen
newaddr = addr + ' / %s ' % prefixlen
2015-11-16 21:00:40 -08:00
newaddrs . append ( newaddr )
2014-10-09 16:02:46 -07:00
2015-11-16 21:00:40 -08:00
attrs = { }
for a in [ ' broadcast ' , ' pointopoint ' , ' scope ' ,
' preferred-lifetime ' ] :
aval = ifaceobj . get_attr_value_n ( a , addr_index )
if aval :
2016-02-08 13:05:33 -08:00
attrs [ a ] = aval
2015-11-16 21:00:40 -08:00
if attrs :
newaddr_attrs [ newaddr ] = attrs
return ( True , newaddrs , newaddr_attrs )
2016-05-09 18:48:52 -07:00
def _inet_address_list_config ( self , ifaceobj , newaddrs , newaddr_attrs ) :
for addr_index in range ( 0 , len ( newaddrs ) ) :
try :
if newaddr_attrs :
self . ipcmd . addr_add ( ifaceobj . name , newaddrs [ addr_index ] ,
newaddr_attrs . get ( newaddrs [ addr_index ] ,
{ } ) . get ( ' broadcast ' ) ,
newaddr_attrs . get ( newaddrs [ addr_index ] ,
{ } ) . get ( ' pointopoint ' ) ,
newaddr_attrs . get ( newaddrs [ addr_index ] ,
{ } ) . get ( ' scope ' ) ,
newaddr_attrs . get ( newaddrs [ addr_index ] ,
{ } ) . get ( ' preferred-lifetime ' ) )
else :
self . ipcmd . addr_add ( ifaceobj . name , newaddrs [ addr_index ] )
except Exception , e :
2016-05-15 13:28:10 -07:00
self . log_error ( str ( e ) , ifaceobj )
2016-05-09 18:48:52 -07:00
def _inet_address_config ( self , ifaceobj , ifaceobj_getfunc = None ,
force_reapply = False ) :
2015-11-16 21:00:40 -08:00
squash_addr_config = ( True if \
ifupdownConfig . config . get ( ' addr_config_squash ' , \
' 0 ' ) == ' 1 ' else False )
if ( squash_addr_config and
not ( ifaceobj . flags & ifaceobj . YOUNGEST_SIBLING ) ) :
return
purge_addresses = ifaceobj . get_attr_value_first ( ' address-purge ' )
if not purge_addresses :
purge_addresses = ' yes '
if squash_addr_config and ifaceobj . flags & iface . HAS_SIBLINGS :
ifaceobjlist = ifaceobj_getfunc ( ifaceobj . name )
else :
ifaceobjlist = [ ifaceobj ]
( addr_supported , newaddrs , newaddr_attrs ) = self . _inet_address_convert_to_cidr ( ifaceobjlist )
2016-09-14 16:00:25 -07:00
newaddrs = utils . get_normalized_ip_addr ( ifaceobj . name , newaddrs )
2015-11-16 21:00:40 -08:00
if not addr_supported :
return
if ( not squash_addr_config and ( ifaceobj . flags & iface . HAS_SIBLINGS ) ) :
# if youngest sibling and squash addr is not set
# print a warning that addresses will not be purged
if ( ifaceobj . flags & iface . YOUNGEST_SIBLING ) :
self . logger . warn ( ' %s : interface has multiple ' % ifaceobj . name +
' iface stanzas, skip purging existing addresses ' )
purge_addresses = ' no '
2016-04-14 14:45:47 -07:00
if not ifupdownflags . flags . PERFMODE and purge_addresses == ' yes ' :
2015-11-16 21:00:40 -08:00
# if perfmode is not set and purge addresses is not set to 'no'
# lets purge addresses not in the config
2016-09-14 16:00:25 -07:00
runningaddrs = utils . get_normalized_ip_addr ( ifaceobj . name , self . ipcmd . addr_get ( ifaceobj . name , details = False ) )
2015-11-16 21:00:40 -08:00
2015-09-04 00:32:15 -07:00
# if anycast address is configured on 'lo' and is in running config
# add it to newaddrs so that ifreload doesn't wipe it out
2016-09-14 16:00:25 -07:00
anycast_addr = utils . get_normalized_ip_addr ( ifaceobj . name , self . _get_anycast_addr ( ifaceobjlist ) )
2015-11-16 21:00:40 -08:00
2015-09-04 00:32:15 -07:00
if runningaddrs and anycast_addr and anycast_addr in runningaddrs :
newaddrs . append ( anycast_addr )
2014-10-09 16:02:46 -07:00
if newaddrs == runningaddrs :
2016-05-09 18:48:52 -07:00
if force_reapply :
self . _inet_address_list_config ( ifaceobj , newaddrs , newaddr_attrs )
2014-10-09 16:02:46 -07:00
return
try :
# if primary address is not same, there is no need to keep any.
# reset all addresses
if ( newaddrs and runningaddrs and
( newaddrs [ 0 ] != runningaddrs [ 0 ] ) ) :
self . ipcmd . del_addr_all ( ifaceobj . name )
else :
self . ipcmd . del_addr_all ( ifaceobj . name , newaddrs )
except Exception , e :
self . log_warn ( str ( e ) )
if not newaddrs :
return
2016-05-09 18:48:52 -07:00
self . _inet_address_list_config ( ifaceobj , newaddrs , newaddr_attrs )
2014-10-09 16:02:46 -07:00
2016-07-20 15:23:13 -07:00
def _add_delete_gateway ( self , ifaceobj , gateways = [ ] , prev_gw = [ ] ) :
vrf = ifaceobj . get_attr_value_first ( ' vrf ' )
metric = ifaceobj . get_attr_value_first ( ' metric ' )
for del_gw in list ( set ( prev_gw ) - set ( gateways ) ) :
try :
self . ipcmd . route_del_gateway ( ifaceobj . name , del_gw , vrf , metric )
except :
pass
for add_gw in list ( set ( gateways ) - set ( prev_gw ) ) :
try :
self . ipcmd . route_add_gateway ( ifaceobj . name , add_gw , vrf )
except :
pass
def _get_prev_gateway ( self , ifaceobj , gateways ) :
ipv = [ ]
saved_ifaceobjs = statemanager . statemanager_api . get_ifaceobjs ( ifaceobj . name )
if not saved_ifaceobjs :
return ipv
prev_gateways = saved_ifaceobjs [ 0 ] . get_attr_value ( ' gateway ' )
if not prev_gateways :
return ipv
return prev_gateways
2016-11-07 10:48:24 -08:00
def _process_mtu_config ( self , ifaceobj , ifaceobj_getfunc ) :
mtu = ifaceobj . get_attr_value_first ( ' mtu ' )
if mtu :
if ( ifaceobj . link_kind & ifaceLinkKind . BRIDGE ) :
self . logger . info ( ' %s : bridge inherits mtu from its ports. There is no need to assign mtu on a bridge ' % ifaceobj . name )
elif ( ifaceobj_getfunc and
( ifaceobj . link_privflags & ifaceLinkPrivFlags . BOND_SLAVE ) and
ifaceobj . upperifaces ) :
masterobj = ifaceobj_getfunc ( ifaceobj . upperifaces [ 0 ] )
if masterobj :
master_mtu = masterobj [ 0 ] . get_attr_value_first ( ' mtu ' )
if master_mtu and master_mtu != mtu :
self . logger . info ( ' %s : bond slave mtu %s is different from bond master mtu %s . There is no need to configure mtu on a bond slave. ' % ( ifaceobj . name , mtu , master_mtu ) )
return
if self . max_mtu and mtu > self . max_mtu :
self . logger . warn ( ' %s : specified mtu %s is greater than max mtu %s '
% ( ifaceobj . name , mtu , self . max_mtu ) )
self . ipcmd . link_set ( ifaceobj . name , ' mtu ' , mtu )
return
if ifaceobj . link_kind :
# bonds and vxlan devices need an explicit set of mtu.
# bridges don't need mtu set
if ( ifaceobj . link_kind & ifaceLinkKind . BOND or
ifaceobj . link_kind & ifaceLinkKind . VXLAN ) :
running_mtu = self . ipcmd . link_get_mtu ( ifaceobj . name )
if ( self . default_mtu and running_mtu != self . default_mtu ) :
self . ipcmd . link_set ( ifaceobj . name , ' mtu ' , self . default_mtu )
return
if ( ifupdownConfig . config . get ( ' adjust_logical_dev_mtu ' , ' 1 ' ) != ' 0 '
and ifaceobj . lowerifaces ) :
# set vlan interface mtu to lower device mtu
if ( ifaceobj . link_kind & ifaceLinkKind . VLAN ) :
lower_iface_mtu = self . ipcmd . link_get_mtu ( ifaceobj . lowerifaces [ 0 ] , refresh = True )
if not lower_iface_mtu == self . ipcmd . link_get_mtu ( ifaceobj . name ) :
self . ipcmd . link_set_mtu ( ifaceobj . name , lower_iface_mtu )
elif ( not ( ifaceobj . name == ' lo ' ) and not ifaceobj . link_kind and
not ( ifaceobj . link_privflags & ifaceLinkPrivFlags . BOND_SLAVE ) and
self . default_mtu ) :
# logical devices like bridges and vlan devices rely on mtu
# from their lower devices. ie mtu travels from
# lower devices to upper devices. For bonds mtu travels from
# upper to lower devices. running mtu depends on upper and
# lower device mtu. With all this implicit mtu
# config by the kernel in play, we try to be cautious here
# on which devices we want to reset mtu to default.
# essentially only physical interfaces which are not bond slaves
running_mtu = self . ipcmd . link_get_mtu ( ifaceobj . name )
if running_mtu != self . default_mtu :
self . ipcmd . link_set ( ifaceobj . name , ' mtu ' , self . default_mtu )
2015-11-16 21:00:40 -08:00
def _up ( self , ifaceobj , ifaceobj_getfunc = None ) :
2014-10-09 16:02:46 -07:00
if not self . ipcmd . link_exists ( ifaceobj . name ) :
return
2014-11-18 16:52:00 -08:00
addr_method = ifaceobj . addr_method
2016-05-09 18:48:52 -07:00
force_reapply = False
2014-10-09 16:02:46 -07:00
try :
# release any stale dhcp addresses if present
2016-04-14 14:45:47 -07:00
if ( addr_method != " dhcp " and not ifupdownflags . flags . PERFMODE and
2014-10-09 16:02:46 -07:00
not ( ifaceobj . flags & iface . HAS_SIBLINGS ) ) :
# if not running in perf mode and ifaceobj does not have
# any sibling iface objects, kill any stale dhclient
# processes
2014-11-17 16:23:42 -08:00
dhclientcmd = dhclient ( )
2016-05-09 13:50:56 -07:00
if dhclientcmd . is_running ( ifaceobj . name ) :
2014-10-09 16:02:46 -07:00
# release any dhcp leases
dhclientcmd . release ( ifaceobj . name )
2016-05-09 18:48:52 -07:00
force_reapply = True
2016-05-09 13:50:56 -07:00
elif dhclientcmd . is_running6 ( ifaceobj . name ) :
2014-10-09 16:02:46 -07:00
dhclientcmd . release6 ( ifaceobj . name )
2016-05-09 18:48:52 -07:00
force_reapply = True
2014-10-09 16:02:46 -07:00
except :
pass
2014-11-03 17:55:51 -08:00
2014-10-09 16:02:46 -07:00
self . ipcmd . batch_start ( )
2014-11-18 16:52:00 -08:00
if addr_method != " dhcp " :
2016-05-09 18:48:52 -07:00
self . _inet_address_config ( ifaceobj , ifaceobj_getfunc ,
force_reapply )
2016-11-07 10:48:24 -08:00
self . _process_mtu_config ( ifaceobj , ifaceobj_getfunc )
2016-04-15 15:56:24 -07:00
2014-10-09 16:02:46 -07:00
alias = ifaceobj . get_attr_value_first ( ' alias ' )
if alias :
2014-11-03 17:55:51 -08:00
self . ipcmd . link_set_alias ( ifaceobj . name , alias )
2016-08-10 15:08:38 +02:00
try :
self . ipcmd . batch_commit ( )
except Exception as e :
2016-09-13 17:03:24 -07:00
self . log_error ( ' %s : %s ' % ( ifaceobj . name , str ( e ) ) , ifaceobj , raise_error = False )
2015-09-17 11:26:56 -07:00
2014-11-18 16:52:00 -08:00
try :
2016-08-24 14:20:45 -07:00
hwaddress = self . _get_hwaddress ( ifaceobj )
if hwaddress :
running_hwaddress = None
if not ifupdownflags . flags . PERFMODE : # system is clean
running_hwaddress = self . ipcmd . link_get_hwaddress ( ifaceobj . name )
if hwaddress != running_hwaddress :
slave_down = False
netlink . link_set_updown ( ifaceobj . name , " down " )
if ifaceobj . link_kind & ifaceLinkKind . BOND :
# if bond, down all the slaves
if ifaceobj . lowerifaces :
for l in ifaceobj . lowerifaces :
netlink . link_set_updown ( l , " down " )
slave_down = True
try :
self . ipcmd . link_set ( ifaceobj . name , ' address ' , hwaddress )
finally :
netlink . link_set_updown ( ifaceobj . name , " up " )
if slave_down :
for l in ifaceobj . lowerifaces :
netlink . link_set_updown ( l , " up " )
2014-11-18 16:52:00 -08:00
# Handle special things on a bridge
self . _process_bridge ( ifaceobj , True )
except Exception , e :
2016-05-15 13:28:10 -07:00
self . log_error ( ' %s : %s ' % ( ifaceobj . name , str ( e ) ) , ifaceobj )
2014-10-28 23:04:40 -07:00
2014-11-18 16:52:00 -08:00
if addr_method != " dhcp " :
2016-07-20 15:23:13 -07:00
gateways = ifaceobj . get_attr_value ( ' gateway ' )
if not gateways :
gateways = [ ]
prev_gw = self . _get_prev_gateway ( ifaceobj , gateways )
self . _add_delete_gateway ( ifaceobj , gateways , prev_gw )
return
2014-10-09 16:02:46 -07:00
2015-11-16 21:00:40 -08:00
def _down ( self , ifaceobj , ifaceobj_getfunc = None ) :
2014-10-09 16:02:46 -07:00
try :
if not self . ipcmd . link_exists ( ifaceobj . name ) :
return
2014-11-18 16:52:00 -08:00
addr_method = ifaceobj . addr_method
if addr_method != " dhcp " :
2016-03-03 12:13:23 -08:00
if ifaceobj . get_attr_value_first ( ' address-purge ' ) == ' no ' :
addrlist = ifaceobj . get_attr_value ( ' address ' )
for addr in addrlist :
self . ipcmd . addr_del ( ifaceobj . name , addr )
#self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0])
else :
self . ipcmd . del_addr_all ( ifaceobj . name )
2016-04-15 10:16:53 +02:00
mtu = ifaceobj . get_attr_value_first ( ' mtu ' )
2016-05-05 15:49:41 -07:00
if ( not ifaceobj . link_kind and mtu and
self . default_mtu and ( mtu != self . default_mtu ) ) :
2016-04-15 10:16:53 +02:00
self . ipcmd . link_set ( ifaceobj . name , ' mtu ' , self . default_mtu )
2014-10-09 16:02:46 -07:00
alias = ifaceobj . get_attr_value_first ( ' alias ' )
if alias :
2016-03-10 01:40:15 +01:00
filename = ' /sys/class/net/ %s /ifalias ' % ifaceobj . name
2016-04-10 18:55:56 +02:00
self . logger . info ( ' executing echo " " > %s ' % filename )
2016-03-10 01:40:15 +01:00
os . system ( ' echo " " > %s ' % filename )
2014-11-17 16:23:42 -08:00
# XXX hwaddress reset cannot happen because we dont know last
# address.
# Handle special things on a bridge
self . _process_bridge ( ifaceobj , False )
2014-10-09 16:02:46 -07:00
except Exception , e :
2014-11-15 23:31:42 -08:00
self . logger . debug ( ' %s : %s ' % ( ifaceobj . name , str ( e ) ) )
pass
2014-10-09 16:02:46 -07:00
def _get_iface_addresses ( self , ifaceobj ) :
addrlist = ifaceobj . get_attr_value ( ' address ' )
outaddrlist = [ ]
if not addrlist : return None
for addrindex in range ( 0 , len ( addrlist ) ) :
addr = addrlist [ addrindex ]
netmask = ifaceobj . get_attr_value_n ( ' netmask ' , addrindex )
if netmask :
prefixlen = IPNetwork ( ' %s ' % addr +
' / %s ' % netmask ) . prefixlen
addr = addr + ' / %s ' % prefixlen
outaddrlist . append ( addr )
return outaddrlist
2014-11-03 17:55:51 -08:00
def _get_bridge_fdbs ( self , bridgename , vlan ) :
fdbs = self . _bridge_fdb_query_cache . get ( bridgename )
if not fdbs :
fdbs = self . ipcmd . bridge_fdb_show_dev ( bridgename )
if not fdbs :
return
self . _bridge_fdb_query_cache [ bridgename ] = fdbs
return fdbs . get ( vlan )
def _check_addresses_in_bridge ( self , ifaceobj , hwaddress ) :
""" If the device is a bridge, make sure the addresses
are in the bridge """
if ' . ' in ifaceobj . name :
( bridgename , vlan ) = ifaceobj . name . split ( ' . ' )
if self . ipcmd . bridge_is_vlan_aware ( bridgename ) :
fdb_addrs = self . _get_bridge_fdbs ( bridgename , vlan )
if not fdb_addrs or hwaddress not in fdb_addrs :
return False
return True
2015-11-16 21:00:40 -08:00
def _query_check ( self , ifaceobj , ifaceobjcurr , ifaceobj_getfunc = None ) :
2014-10-09 16:02:46 -07:00
runningaddrsdict = None
if not self . ipcmd . link_exists ( ifaceobj . name ) :
self . logger . debug ( ' iface %s not found ' % ifaceobj . name )
return
2014-11-19 17:25:26 -08:00
addr_method = ifaceobj . addr_method
2014-10-09 16:02:46 -07:00
self . query_n_update_ifaceobjcurr_attr ( ifaceobj , ifaceobjcurr ,
' mtu ' , self . ipcmd . link_get_mtu )
2016-03-15 15:41:04 +01:00
hwaddress = self . _get_hwaddress ( ifaceobj )
2014-11-03 17:55:51 -08:00
if hwaddress :
2016-03-11 15:56:34 -08:00
rhwaddress = self . ipcmd . link_get_hwaddress ( ifaceobj . name )
2014-11-03 17:55:51 -08:00
if not rhwaddress or rhwaddress != hwaddress :
ifaceobjcurr . update_config_with_status ( ' hwaddress ' , rhwaddress ,
1 )
elif not self . _check_addresses_in_bridge ( ifaceobj , hwaddress ) :
# XXX: hw address is not in bridge
ifaceobjcurr . update_config_with_status ( ' hwaddress ' , rhwaddress ,
1 )
ifaceobjcurr . status_str = ' bridge fdb error '
else :
ifaceobjcurr . update_config_with_status ( ' hwaddress ' , rhwaddress ,
0 )
2014-10-09 16:02:46 -07:00
self . query_n_update_ifaceobjcurr_attr ( ifaceobj , ifaceobjcurr ,
' alias ' , self . ipcmd . link_get_alias )
# compare addresses
2014-11-19 17:25:26 -08:00
if addr_method == ' dhcp ' :
return
2016-09-14 16:00:25 -07:00
addrs = utils . get_normalized_ip_addr ( ifaceobj . name ,
self . _get_iface_addresses ( ifaceobj ) )
2014-10-09 16:02:46 -07:00
runningaddrsdict = self . ipcmd . addr_get ( ifaceobj . name )
2015-09-04 00:32:15 -07:00
# if anycast address is configured on 'lo' and is in running config
# add it to addrs so that query_check doesn't fail
2016-09-14 16:00:25 -07:00
anycast_addr = utils . get_normalized_ip_addr ( ifaceobj . name , ifaceobj . get_attr_value_first ( ' clagd-vxlan-anycast-ip ' ) )
2015-09-04 00:32:15 -07:00
if anycast_addr :
anycast_addr = anycast_addr + ' /32 '
if runningaddrsdict and anycast_addr and runningaddrsdict . get ( anycast_addr ) :
addrs . append ( anycast_addr )
2014-10-09 16:02:46 -07:00
# Set ifaceobjcurr method and family
ifaceobjcurr . addr_method = ifaceobj . addr_method
ifaceobjcurr . addr_family = ifaceobj . addr_family
if not runningaddrsdict and not addrs :
return
runningaddrs = runningaddrsdict . keys ( ) if runningaddrsdict else [ ]
if runningaddrs != addrs :
runningaddrsset = set ( runningaddrs ) if runningaddrs else set ( [ ] )
addrsset = set ( addrs ) if addrs else set ( [ ] )
if ( ifaceobj . flags & iface . HAS_SIBLINGS ) :
if not addrsset :
return
# only check for addresses present in running config
addrsdiff = addrsset . difference ( runningaddrsset )
for addr in addrs :
if addr in addrsdiff :
ifaceobjcurr . update_config_with_status ( ' address ' ,
addr , 1 )
else :
ifaceobjcurr . update_config_with_status ( ' address ' ,
addr , 0 )
else :
addrsdiff = addrsset . symmetric_difference ( runningaddrsset )
for addr in addrsset . union ( runningaddrsset ) :
if addr in addrsdiff :
ifaceobjcurr . update_config_with_status ( ' address ' ,
addr , 1 )
else :
ifaceobjcurr . update_config_with_status ( ' address ' ,
addr , 0 )
elif addrs :
[ ifaceobjcurr . update_config_with_status ( ' address ' ,
addr , 0 ) for addr in addrs ]
#XXXX Check broadcast address, scope, etc
return
2015-11-16 21:00:40 -08:00
def _query_running ( self , ifaceobjrunning , ifaceobj_getfunc = None ) :
2014-10-09 16:02:46 -07:00
if not self . ipcmd . link_exists ( ifaceobjrunning . name ) :
self . logger . debug ( ' iface %s not found ' % ifaceobjrunning . name )
return
dhclientcmd = dhclient ( )
if ( dhclientcmd . is_running ( ifaceobjrunning . name ) or
dhclientcmd . is_running6 ( ifaceobjrunning . name ) ) :
# If dhcp is configured on the interface, we skip it
2016-04-15 10:16:53 +02:00
return
2014-10-09 16:02:46 -07:00
isloopback = self . ipcmd . link_isloopback ( ifaceobjrunning . name )
if isloopback :
default_addrs = [ ' 127.0.0.1/8 ' , ' ::1/128 ' ]
2016-11-15 18:33:07 +01:00
ifaceobjrunning . addr_family . append ( ' inet ' )
2014-10-09 16:02:46 -07:00
ifaceobjrunning . addr_method = ' loopback '
else :
default_addrs = [ ]
runningaddrsdict = self . ipcmd . addr_get ( ifaceobjrunning . name )
if runningaddrsdict :
[ ifaceobjrunning . update_config ( ' address ' , addr )
for addr , addrattrs in runningaddrsdict . items ( )
if addr not in default_addrs ]
mtu = self . ipcmd . link_get_mtu ( ifaceobjrunning . name )
if ( mtu and
( ifaceobjrunning . name == ' lo ' and mtu != ' 16436 ' ) or
( ifaceobjrunning . name != ' lo ' and
mtu != self . get_mod_subattr ( ' mtu ' , ' default ' ) ) ) :
ifaceobjrunning . update_config ( ' mtu ' , mtu )
alias = self . ipcmd . link_get_alias ( ifaceobjrunning . name )
2016-04-15 10:16:53 +02:00
if alias :
2014-10-09 16:02:46 -07:00
ifaceobjrunning . update_config ( ' alias ' , alias )
_run_ops = { ' up ' : _up ,
' down ' : _down ,
' query-checkcurr ' : _query_check ,
' query-running ' : _query_running }
def get_ops ( self ) :
""" returns list of ops supported by this module """
return self . _run_ops . keys ( )
def _init_command_handlers ( self ) :
if not self . ipcmd :
2016-04-14 14:45:47 -07:00
self . ipcmd = iproute2 ( )
2014-10-09 16:02:46 -07:00
2016-04-20 03:02:26 -07:00
def run ( self , ifaceobj , operation , query_ifaceobj = None , ifaceobj_getfunc = None ) :
2014-10-09 16:02:46 -07:00
""" run address configuration on the interface object passed as argument
Args :
* * ifaceobj * * ( object ) : iface object
* * operation * * ( str ) : any of ' up ' , ' down ' , ' query-checkcurr ' ,
' query-running '
Kwargs :
query_ifaceobj ( object ) : query check ifaceobject . This is only
valid when op is ' query-checkcurr ' . It is an object same as
ifaceobj , but contains running attribute values and its config
status . The modules can use it to return queried running state
of interfaces . status is success if the running state is same
as user required state in ifaceobj . error otherwise .
"""
2014-11-03 17:55:51 -08:00
if ifaceobj . type == ifaceType . BRIDGE_VLAN :
return
2014-10-09 16:02:46 -07:00
op_handler = self . _run_ops . get ( operation )
if not op_handler :
return
self . _init_command_handlers ( )
if operation == ' query-checkcurr ' :
2015-11-16 21:00:40 -08:00
op_handler ( self , ifaceobj , query_ifaceobj ,
ifaceobj_getfunc = ifaceobj_getfunc )
2014-10-09 16:02:46 -07:00
else :
2015-11-16 21:00:40 -08:00
op_handler ( self , ifaceobj ,
ifaceobj_getfunc = ifaceobj_getfunc )