mirror of
				https://github.com/CumulusNetworks/ifupdown2.git
				synced 2024-05-06 15:54:50 +00:00 
			
		
		
		
	Ticket: CM-9677 Reviewed By: nikhil Testing Done: Tested with bond config file in CM-9677 This patch replaces the following attributes: bond-ad-sys-priority with bond-ad-actor-sys-prio bond-ad-sys-mac-addr with bond-ad-actor-system The new attributes correspond to the new sysfs files below: /sys/class/net/sidelink/bonding/ad_actor_sys_prio /sys/class/net/sidelink/bonding/ad_actor_system Old values will be accepted with a deprecated warning: warning: attribute bond-ad-sys-priority is deprecated. Use bond-ad-actor-sys-prio instead warning: attribute bond-ad-sys-mac-addr is deprecated. Use bond-ad-actor-system instead
		
			
				
	
	
		
			379 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			379 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/python
 | |
| #
 | |
| # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
 | |
| # Author: Roopa Prabhu, roopa@cumulusnetworks.com
 | |
| #
 | |
| 
 | |
| import os
 | |
| import re
 | |
| from ifupdown.iface import *
 | |
| from utilsbase import *
 | |
| from iproute2 import *
 | |
| from cache import *
 | |
| 
 | |
| class bondutil(utilsBase):
 | |
|     """ This class contains methods to interact with linux kernel bond
 | |
|     related interfaces """
 | |
| 
 | |
|     _cache_fill_done = False
 | |
| 
 | |
|     def __init__(self, *args, **kargs):
 | |
|         utilsBase.__init__(self, *args, **kargs)
 | |
|         if self.CACHE and not self._cache_fill_done:
 | |
|             self._bond_linkinfo_fill_all()
 | |
|             self._cache_fill_done = True
 | |
| 
 | |
|     def _bond_linkinfo_fill_attrs(self, bondname):
 | |
|         try:
 | |
|             linkCache.links[bondname]['linkinfo'] = {}
 | |
|         except:
 | |
|             linkCache.links[bondname] = {'linkinfo': {}}
 | |
| 
 | |
|         try:
 | |
|             linkCache.set_attr([bondname, 'linkinfo', 'slaves'],
 | |
|                 self.read_file_oneline('/sys/class/net/%s/bonding/slaves'
 | |
|                 %bondname).split())
 | |
|             linkCache.set_attr([bondname, 'linkinfo', 'mode'],
 | |
|                 self.read_file_oneline('/sys/class/net/%s/bonding/mode'
 | |
|                 %bondname).split()[0])
 | |
|             linkCache.set_attr([bondname, 'linkinfo', 'xmit_hash_policy'],
 | |
|                 self.read_file_oneline(
 | |
|                     '/sys/class/net/%s/bonding/xmit_hash_policy'
 | |
|                     %bondname).split()[0])
 | |
|             linkCache.set_attr([bondname, 'linkinfo', 'lacp_rate'],
 | |
|                 self.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
 | |
|                                        %bondname).split()[1])
 | |
|             linkCache.set_attr([bondname, 'linkinfo', 'ad_actor_sys_prio'],
 | |
|                 self.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
 | |
|                                        %bondname))
 | |
|             linkCache.set_attr([bondname, 'linkinfo', 'ad_actor_system'],
 | |
|                 self.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
 | |
|                                        %bondname))
 | |
|             linkCache.set_attr([bondname, 'linkinfo', 'lacp_bypass'],
 | |
|                 self.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
 | |
|                                        %bondname).split()[1])
 | |
|             map(lambda x: linkCache.set_attr([bondname, 'linkinfo', x],
 | |
|                    self.read_file_oneline('/sys/class/net/%s/bonding/%s'
 | |
|                         %(bondname, x))),
 | |
|                        ['use_carrier', 'miimon', 'min_links', 'num_unsol_na',
 | |
|                         'num_grat_arp'])
 | |
|         except Exception, e:
 | |
|             pass
 | |
| 
 | |
|     def _bond_linkinfo_fill_all(self):
 | |
|         bondstr = self.read_file_oneline('/sys/class/net/bonding_masters')
 | |
|         if not bondstr:
 | |
|             return
 | |
|         [self._bond_linkinfo_fill_attrs(b) for b in bondstr.split()]
 | |
| 
 | |
|     def _bond_linkinfo_fill(self, bondname, refresh=False):
 | |
|         try:
 | |
|             linkCache.get_attr([bondname, 'linkinfo', 'slaves'])
 | |
|             return
 | |
|         except:
 | |
|             pass
 | |
|         bondstr = self.read_file_oneline('/sys/class/net/bonding_masters')
 | |
|         if (not bondstr or bondname not in bondstr.split()):
 | |
|             raise Exception('bond %s not found' %bondname)
 | |
|         self._bond_linkinfo_fill_attrs(bondname)
 | |
| 
 | |
|     def _cache_get(self, attrlist, refresh=False):
 | |
|         try:
 | |
|             if self.DRYRUN:
 | |
|                 return None
 | |
|             if self.CACHE:
 | |
|                 if not bondutil._cache_fill_done: 
 | |
|                     self._bond_linkinfo_fill_all()
 | |
|                     bondutil._cache_fill_done = True
 | |
|                     return linkCache.get_attr(attrlist)
 | |
|                 if not refresh:
 | |
|                     return linkCache.get_attr(attrlist)
 | |
|             self._bond_linkinfo_fill(attrlist[0], refresh)
 | |
|             return linkCache.get_attr(attrlist)
 | |
|         except Exception, e:
 | |
|             self.logger.debug('_cache_get(%s) : [%s]'
 | |
|                     %(str(attrlist), str(e)))
 | |
|             pass
 | |
|         return None
 | |
| 
 | |
|     def _cache_check(self, attrlist, value, refresh=False):
 | |
|         try:
 | |
|             attrvalue = self._cache_get(attrlist, refresh)
 | |
|             if attrvalue and attrvalue == value:
 | |
|                 return True
 | |
|         except Exception, e:
 | |
|             self.logger.debug('_cache_check(%s) : [%s]'
 | |
|                     %(str(attrlist), str(e)))
 | |
|             pass
 | |
|         return False
 | |
| 
 | |
|     def _cache_update(self, attrlist, value):
 | |
|         if self.DRYRUN: return
 | |
|         try:
 | |
|             if attrlist[-1] == 'slaves':
 | |
|                 linkCache.add_to_attrlist(attrlist, value)
 | |
|                 return
 | |
|             linkCache.add_attr(attrlist, value)
 | |
|         except:
 | |
|             pass
 | |
| 
 | |
|     def _cache_delete(self, attrlist, value=None):
 | |
|         if self.DRYRUN: return
 | |
|         try:
 | |
|             if attrlist[-1] == 'slaves':
 | |
|                 linkCache.remove_from_attrlist(attrlist, value)
 | |
|                 return
 | |
|             linkCache.del_attr(attrlist)
 | |
|         except:
 | |
|             pass
 | |
| 
 | |
|     def _cache_invalidate(self):
 | |
|         if self.DRYRUN: return
 | |
|         linkCache.invalidate()
 | |
| 
 | |
|     def set_attrs(self, bondname, attrdict, prehook):
 | |
|         for attrname, attrval in attrdict.items():
 | |
|             if (self._cache_check([bondname, 'linkinfo',
 | |
|                 attrname], attrval)):
 | |
|                 continue
 | |
|             if (attrname == 'mode' or attrname == 'xmit_hash_policy' or
 | |
|                     attrname == 'lacp_rate' or attrname == 'min_links'):
 | |
|                 if prehook:
 | |
|                     prehook(bondname)
 | |
|             try:
 | |
|                 if ((attrname not in ['lacp_rate',
 | |
|                                       'lacp_bypass']) or
 | |
|                     ('mode', '802.3ad') in attrdict.items()):
 | |
|                     self.write_file('/sys/class/net/%s/bonding/%s'
 | |
|                                     %(bondname, attrname), attrval)
 | |
|             except Exception, e:
 | |
|                 if self.FORCE:
 | |
|                     self.logger.warn(str(e))
 | |
|                     pass
 | |
|                 else:
 | |
|                     raise
 | |
| 
 | |
|     def set_use_carrier(self, bondname, use_carrier):
 | |
|         if not use_carrier or (use_carrier != '0' and use_carrier != '1'):
 | |
|             return
 | |
|         if (self._cache_check([bondname, 'linkinfo', 'use_carrier'],
 | |
|                 use_carrier)):
 | |
|                 return
 | |
|         self.write_file('/sys/class/net/%s' %bondname +
 | |
|                          '/bonding/use_carrier', use_carrier)
 | |
|         self._cache_update([bondname, 'linkinfo',
 | |
|                             'use_carrier'], use_carrier)
 | |
| 
 | |
|     def get_use_carrier(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'use_carrier'])
 | |
| 
 | |
|     def set_xmit_hash_policy(self, bondname, hash_policy, prehook=None):
 | |
|         valid_values = ['layer2', 'layer3+4', 'layer2+3']
 | |
|         if not hash_policy:
 | |
|             return
 | |
|         if hash_policy not in valid_values:
 | |
|             raise Exception('invalid hash policy value %s' %hash_policy)
 | |
|         if (self._cache_check([bondname, 'linkinfo', 'xmit_hash_policy'],
 | |
|                 hash_policy)):
 | |
|             return
 | |
|         if prehook:
 | |
|             prehook(bondname)
 | |
|         self.write_file('/sys/class/net/%s' %bondname +
 | |
|                          '/bonding/xmit_hash_policy', hash_policy)
 | |
|         self._cache_update([bondname, 'linkinfo', 'xmit_hash_policy'],
 | |
|                 hash_policy)
 | |
| 
 | |
|     def get_xmit_hash_policy(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'xmit_hash_policy'])
 | |
| 
 | |
|     def set_miimon(self, bondname, miimon):
 | |
|         if (self._cache_check([bondname, 'linkinfo', 'miimon'],
 | |
|                 miimon)):
 | |
|             return
 | |
|         self.write_file('/sys/class/net/%s' %bondname +
 | |
|                 '/bonding/miimon', miimon)
 | |
|         self._cache_update([bondname, 'linkinfo', 'miimon'], miimon)
 | |
| 
 | |
|     def get_miimon(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'miimon'])
 | |
| 
 | |
|     def set_mode(self, bondname, mode, prehook=None):
 | |
|         valid_modes = ['balance-rr', 'active-backup', 'balance-xor',
 | |
|                        'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
 | |
|         if not mode:
 | |
|             return
 | |
|         if mode not in valid_modes:
 | |
|             raise Exception('invalid mode %s' %mode)
 | |
|         if (self._cache_check([bondname, 'linkinfo', 'mode'],
 | |
|                 mode)):
 | |
|             return
 | |
|         if prehook:
 | |
|             prehook(bondname)
 | |
|         self.write_file('/sys/class/net/%s' %bondname + '/bonding/mode', mode)
 | |
|         self._cache_update([bondname, 'linkinfo', 'mode'], mode)
 | |
| 
 | |
|     def get_mode(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'mode'])
 | |
| 
 | |
|     def set_lacp_rate(self, bondname, lacp_rate, prehook=None, posthook=None):
 | |
|         if not lacp_rate or (lacp_rate != '0' and lacp_rate != '1'):
 | |
|             return
 | |
|         if (self._cache_check([bondname, 'linkinfo', 'lacp_rate'],
 | |
|                 lacp_rate)):
 | |
|             return
 | |
|         if prehook:
 | |
|             prehook(bondname)
 | |
|         try:
 | |
|             self.write_file('/sys/class/net/%s' %bondname +
 | |
|                             '/bonding/lacp_rate', lacp_rate)
 | |
|         except:
 | |
|             raise
 | |
|         finally:
 | |
|             if posthook:
 | |
|                 prehook(bondname)
 | |
|             self._cache_update([bondname, 'linkinfo',
 | |
|                                 'lacp_rate'], lacp_rate)
 | |
| 
 | |
|     def get_lacp_rate(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'lacp_rate'])
 | |
| 
 | |
|     def set_lacp_bypass_allow(self, bondname, allow, prehook=None, posthook=None):
 | |
|         if (self._cache_check([bondname, 'linkinfo', 'lacp_bypass'],
 | |
|                 lacp_bypass)):
 | |
|             return
 | |
|         if prehook:
 | |
|             prehook(bondname)
 | |
|         try:
 | |
|             self.write_file('/sys/class/net/%s' %bondname +
 | |
|                             '/bonding/lacp_bypass', allow)
 | |
|         except:
 | |
|             raise
 | |
|         finally:
 | |
|             if posthook:
 | |
|                 posthook(bondname)
 | |
|             self._cache_update([bondname, 'linkinfo',
 | |
|                                'lacp_bypass'], allow)
 | |
| 
 | |
|     def get_lacp_bypass_allow(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'lacp_bypass'])
 | |
| 
 | |
|     def set_min_links(self, bondname, min_links, prehook=None):
 | |
|         if (self._cache_check([bondname, 'linkinfo', 'min_links'],
 | |
|                 min_links)):
 | |
|             return
 | |
|         if prehook:
 | |
|             prehook(bondname)
 | |
|         self.write_file('/sys/class/net/%s/bonding/min_links' %bondname,
 | |
|                          min_links)
 | |
|         self._cache_update([bondname, 'linkinfo', 'min_links'], min_links)
 | |
| 
 | |
|     def get_min_links(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'min_links'])
 | |
| 
 | |
|     def get_ad_actor_system(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'ad_actor_system'])
 | |
| 
 | |
|     def get_ad_actor_sys_prio(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'ad_actor_sys_prio'])
 | |
| 
 | |
|     def get_num_unsol_na(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'num_unsol_na'])
 | |
| 
 | |
|     def get_num_grat_arp(self, bondname):
 | |
|         return self._cache_get([bondname, 'linkinfo', 'num_grat_arp'])
 | |
| 
 | |
|     def enslave_slave(self, bondname, slave, prehook=None, posthook=None):
 | |
|         slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
 | |
|         if slaves and slave in slaves: return
 | |
|         if prehook:
 | |
|             prehook(slave)
 | |
|         self.write_file('/sys/class/net/%s' %bondname +
 | |
|                          '/bonding/slaves', '+' + slave)
 | |
|         if posthook:
 | |
|             posthook(slave)
 | |
|         self._cache_update([bondname, 'linkinfo', 'slaves'], slave) 
 | |
| 
 | |
|     def remove_slave(self, bondname, slave):
 | |
|         slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
 | |
|         if slave not in slaves:
 | |
|             return
 | |
|         sysfs_bond_path = ('/sys/class/net/%s' %bondname +
 | |
|                            '/bonding/slaves')
 | |
|         if not os.path.exists(sysfs_bond_path):
 | |
|            return
 | |
|         self.write_file(sysfs_bond_path, '-' + slave)
 | |
|         self._cache_delete([bondname, 'linkinfo', 'slaves'], slave) 
 | |
| 
 | |
|     def remove_slaves_all(self, bondname):
 | |
|         if not _self._cache_get([bondname, 'linkinfo', 'slaves']):
 | |
|             return
 | |
|         slaves = None
 | |
|         sysfs_bond_path = ('/sys/class/net/%s' %bondname +
 | |
|                            '/bonding/slaves')
 | |
|         ipcmd = iproute2()
 | |
|         try:
 | |
|             f = open(sysfs_bond_path, 'r')
 | |
|             slaves = f.readline().strip().split()
 | |
|             f.close()
 | |
|         except IOError, e:
 | |
|             raise Exception('error reading slaves of bond %s' %bondname
 | |
|                 + '(' + str(e) + ')')
 | |
|         for slave in slaves:
 | |
|             ipcmd.ip_link_down(slave)
 | |
|             try:
 | |
|                 self.remove_slave(bondname, slave)
 | |
|             except Exception, e:
 | |
|                 if not self.FORCE:
 | |
|                     raise Exception('error removing slave %s'
 | |
|                         %slave + ' from bond %s' %bondname +
 | |
|                         '(%s)' %str(e))
 | |
|                 else:
 | |
|                     pass
 | |
|         self._cache_del([bondname, 'linkinfo', 'slaves'])
 | |
| 
 | |
|     def load_bonding_module(self):
 | |
|         return self.exec_command('modprobe -q bonding')
 | |
| 
 | |
|     def create_bond(self, bondname):
 | |
|         if self.bond_exists(bondname):
 | |
|             return
 | |
|         sysfs_net = '/sys/class/net/'
 | |
|         sysfs_bonding_masters = sysfs_net + 'bonding_masters'
 | |
|         if not os.path.exists(sysfs_bonding_masters):
 | |
|             self.logger.debug('loading bonding driver')
 | |
|             self.load_bonding_module()
 | |
|         self.write_file(sysfs_bonding_masters, '+' + bondname)
 | |
|         self._cache_update([bondname], {})
 | |
| 
 | |
|     def delete_bond(self, bondname):
 | |
|         if not os.path.exists('/sys/class/net/%s' %bondname):
 | |
|             return
 | |
|         self.write_file('/sys/class/net/bonding_masters', '-' + bondname)
 | |
|         self._cache_delete([bondname])
 | |
| 
 | |
|     def unset_master(self, bondname):
 | |
|         print 'Do nothing yet'
 | |
|         return 0
 | |
| 
 | |
|     def get_slaves(self, bondname):
 | |
|         slaves = self._cache_get([bondname, 'linkinfo', 'slaves'])
 | |
|         if slaves:
 | |
|             return list(slaves)
 | |
|         slavefile = '/sys/class/net/%s/bonding/slaves' %bondname
 | |
|         if os.path.exists(slavefile):
 | |
|             buf = self.read_file_oneline(slavefile)
 | |
|             if buf:
 | |
|                 slaves = buf.split()
 | |
|         if not slaves:
 | |
|             return slaves
 | |
|         self._cache_update([bondname, 'linkinfo', 'slaves'], slaves)
 | |
|         return list(slaves)
 | |
| 
 | |
|     def bond_slave_exists(self, bond, slave):
 | |
|         slaves = self.get_slaves(bond)
 | |
|         if not slaves: return False
 | |
|         return slave in slaves
 | |
| 
 | |
|     def bond_exists(self, bondname):
 | |
|         return os.path.exists('/sys/class/net/%s/bonding' %bondname)
 |