mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
1553a88121
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)
|