Skip to content

Commit

Permalink
scripts/perftune.py: add support for tweaking VLAN interfaces
Browse files Browse the repository at this point in the history
Handle VLAN interfaces similar to bond ones: discover the underlying physical
devices and tweak them.

Fixes scylladb#765
  • Loading branch information
vladzcloudius committed Jul 6, 2024
1 parent 1604104 commit e07b9cd
Showing 1 changed file with 46 additions and 15 deletions.
61 changes: 46 additions & 15 deletions scripts/perftune.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,9 +576,10 @@ def __init__(self, args):
self.nics=args.nics

self.__nic_is_bond_iface = NetPerfTuner.__get_bond_ifaces()
self.__nic_is_vlan_iface = NetPerfTuner.__get_vlan_ifaces()
self.__slaves = self.__learn_slaves()

# check that self.nics contain a HW device or a bonding interface
# check that self.nics contain a HW device or a supported composite interface
self.__check_nics()

# Fetch IRQs related info
Expand All @@ -595,8 +596,8 @@ def tune(self):
perftune_print("Setting a physical interface {}...".format(nic))
self.__setup_one_hw_iface(nic)
else:
perftune_print("Setting {} bonding interface...".format(nic))
self.__setup_bonding_iface(nic)
perftune_print(f"Setting a {nic} {'bond' if self.nic_is_bond_iface(nic) else 'VLAN'} interface...")
self.__setup_composite_iface(nic)

# Increase the socket listen() backlog
fwriteln_and_log('/proc/sys/net/core/somaxconn', '4096')
Expand All @@ -608,6 +609,12 @@ def tune(self):
def nic_is_bond_iface(self, nic):
return self.__nic_is_bond_iface.get(nic, False)

def nic_is_vlan_iface(self, nic):
return self.__nic_is_vlan_iface.get(nic, False)

def nic_is_composite_iface(self, nic):
return self.nic_is_bond_iface(nic) or self.nic_is_vlan_iface(nic)

def nic_exists(self, nic):
return self.__iface_exists(nic)

Expand All @@ -617,8 +624,8 @@ def nic_is_hw_iface(self, nic):
def slaves(self, nic):
"""
Returns an iterator for all slaves of the nic.
If agrs.nic is not a bonding interface an attempt to use the returned iterator
will immediately raise a StopIteration exception - use __dev_is_bond_iface() check to avoid this.
If agrs.nic is not a composite interface an attempt to use the returned iterator
will immediately raise a StopIteration exception - use nic_is_composite_iface() check to avoid this.
"""
return iter(self.__slaves[nic])

Expand Down Expand Up @@ -646,7 +653,7 @@ def __check_nics(self):
for nic in self.nics:
if not self.nic_exists(nic):
raise Exception("Device {} does not exist".format(nic))
if not self.nic_is_hw_iface(nic) and not self.nic_is_bond_iface(nic):
if not self.nic_is_hw_iface(nic) and not self.nic_is_composite_iface(nic):
raise Exception("Not supported virtual device {}".format(nic))

def __get_irqs_one(self, iface):
Expand Down Expand Up @@ -744,24 +751,44 @@ def __get_bond_ifaces():

return bond_dict

@staticmethod
def __get_vlan_ifaces():
# Each VLAN interface is going to have a corresponding entry in /proc/net/vlan/ directory
return {pathlib.PurePath(pathlib.Path(f)).name: True
for f in filter(lambda vlan_name: vlan_name != "/proc/net/vlan/config", glob.glob("/proc/net/vlan/*"))}

def __learn_slaves_one(self, nic):
"""
Learn underlying physical devices a given NIC
:param nic: An interface to search slaves for
"""
slaves_list = set()
top_slaves_list = set()

if self.nic_is_bond_iface(nic):
top_slaves_list = set(itertools.chain.from_iterable(
[line.split() for line in open("/sys/class/net/{}/bonding/slaves".format(nic), 'r').readlines()]))

# Slaves can be themselves bonded devices: let's descend (DFS) all the way down to get physical devices
for s in top_slaves_list:
if self.nic_is_bond_iface(s):
slaves_list |= self.__learn_slaves_one(s)
else:
slaves_list.add(s)
elif self.nic_is_vlan_iface(nic):
# VLAN interfaces have a symbolic link 'lower_<parent_interface_name>' under
# /sys/class/net/<VLAN interface name>.
#
# For example:
#
# lrwxrwxrwx 1 root root 0 Jul 5 18:38 lower_eno1 -> ../../../pci0000:00/0000:00:1f.6/net/eno1/
#
top_slaves_list = set([pathlib.PurePath(pathlib.Path(f).resolve()).name
for f in glob.glob(f"/sys/class/net/{nic}/lower_*")])

# Slaves can be themselves bond or VLAN devices: let's descend (DFS) all the way down to get physical devices.
# Bond slaves can't be VLAN interfaces but VLAN interface parent device can be a bond interface.
# Bond slaves can also be bonds.
# For simplicity let's not discriminate.
for s in top_slaves_list:
if self.nic_is_composite_iface(s):
slaves_list |= self.__learn_slaves_one(s)
else:
slaves_list.add(s)

return slaves_list

Expand Down Expand Up @@ -972,7 +999,7 @@ def __learn_irqs(self):
"""
nic_irq_dict={}
for nic in self.nics:
if self.nic_is_bond_iface(nic):
if self.nic_is_composite_iface(nic):
for slave in filter(self.__dev_is_hw_iface, self.slaves(nic)):
nic_irq_dict[slave] = self.__learn_irqs_one(slave)
else:
Expand Down Expand Up @@ -1064,7 +1091,11 @@ def __setup_one_hw_iface(self, iface):
self.__setup_rps(iface, self.cpu_mask)
self.__setup_xps(iface)

def __setup_bonding_iface(self, nic):
def __setup_composite_iface(self, nic):
"""
Set up the interface which is a bond or a VLAN interface
:param nic: name of a composite interface to set up
"""
for slave in self.slaves(nic):
if self.__dev_is_hw_iface(slave):
perftune_print("Setting up {}...".format(slave))
Expand Down

0 comments on commit e07b9cd

Please sign in to comment.