summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2021-01-01 18:40:21 +0100
committerGitHub <noreply@github.com>2021-01-01 18:40:21 +0100
commitb13235d2b2a186be059690af88b243b33b37d60f (patch)
treef08b577494673b0c553025b344e3a640de7e6242
parent215ddbe0bc51417b7ba66298764810754b204082 (diff)
parent9fb9e5cade4ceccd98aefb854a12a2a42db7c672 (diff)
downloadvyos-1x-b13235d2b2a186be059690af88b243b33b37d60f.tar.gz
vyos-1x-b13235d2b2a186be059690af88b243b33b37d60f.zip
Merge pull request #666 from c-po/t3171-rps
T3171: Ethernet RPS support
-rw-r--r--interface-definitions/interfaces-ethernet.xml.in14
-rw-r--r--python/vyos/ifconfig/ethernet.py35
-rw-r--r--python/vyos/validate.py4
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_ethernet.py25
-rwxr-xr-xsrc/conf_mode/interfaces-ethernet.py10
5 files changed, 78 insertions, 10 deletions
diff --git a/interface-definitions/interfaces-ethernet.xml.in b/interface-definitions/interfaces-ethernet.xml.in
index 9564f5ab8..be44072a6 100644
--- a/interface-definitions/interfaces-ethernet.xml.in
+++ b/interface-definitions/interfaces-ethernet.xml.in
@@ -77,6 +77,12 @@
<valueless/>
</properties>
</leafNode>
+ <leafNode name="rps">
+ <properties>
+ <help>Enable Receive Packet Steering</help>
+ <valueless/>
+ </properties>
+ </leafNode>
<leafNode name="sg">
<properties>
<help>Enable Scatter-Gather</help>
@@ -99,13 +105,13 @@
</node>
<leafNode name="speed">
<properties>
- <help>Link speed</help>
+ <help>Link speed (default: auto)</help>
<completionHelp>
<list>auto 10 100 1000 2500 5000 10000 25000 40000 50000 100000</list>
</completionHelp>
<valueHelp>
<format>auto</format>
- <description>Auto negotiation (default)</description>
+ <description>Auto negotiation</description>
</valueHelp>
<valueHelp>
<format>10</format>
@@ -163,7 +169,7 @@
<properties>
<help>RX ring buffer</help>
<valueHelp>
- <format>80-16384</format>
+ <format>u32:80-16384</format>
<description>ring buffer size</description>
</valueHelp>
<constraint>
@@ -175,7 +181,7 @@
<properties>
<help>TX ring buffer</help>
<valueHelp>
- <format>80-16384</format>
+ <format>u32:80-16384</format>
<description>ring buffer size</description>
</valueHelp>
<constraint>
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index 1bec45879..7cf79bead 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2021 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -17,9 +17,10 @@ import os
import re
from vyos.ifconfig.interface import Interface
-from vyos.validate import assert_list
from vyos.util import run
from vyos.util import dict_search
+from vyos.validate import assert_list
+from vyos.validate import assert_range
@Interface.register
class EthernetIf(Interface):
@@ -75,6 +76,13 @@ class EthernetIf(Interface):
},
}}
+ _sysfs_set = {**Interface._sysfs_set, **{
+ 'rps': {
+ 'validate': lambda cpu: assert_range(cpu, 0, 4294967295),
+ 'location': '/sys/class/net/{ifname}/queues/rx-0/rps_cpus',
+ },
+ }}
+
def get_driver_name(self):
"""
Return the driver name used by NIC. Some NICs don't support all
@@ -231,6 +239,26 @@ class EthernetIf(Interface):
raise ValueError("Value out of range")
return self.set_interface('gso', 'on' if state else 'off')
+ def set_rps(self, state):
+ if not isinstance(state, bool):
+ raise ValueError("Value out of range")
+
+ rps_cpus = 0
+ if state:
+ # enable RPS on all available CPUs, RPS works woth a CPU bitmask,
+ # where each bit represents a CPU (core/thread). The formula below
+ # expands to rps_cpus = 255 for a 8 core system
+ rps_cpus = (1 << os.cpu_count()) -1
+
+ # XXX: we should probably reserve one core when the system is under
+ # high preasure so we can still have a core left for housekeeping.
+ # This is done by masking out the lowst bit so CPU0 is spared from
+ # receive packet steering.
+ rps_cpus &= ~1
+
+ # send bitmask representation as hex string without leading '0x'
+ return self.set_interface('rps', f'{rps_cpus:x}')
+
def set_sg(self, state):
"""
Enable Scatter-Gather support. State can be either True or False.
@@ -307,6 +335,9 @@ class EthernetIf(Interface):
# GSO (generic segmentation offload)
self.set_gso(dict_search('offload.gso', config) != None)
+ # RPS - Receive Packet Steering
+ self.set_rps(dict_search('offload.rps', config) != None)
+
# scatter-gather option
self.set_sg(dict_search('offload.sg', config) != None)
diff --git a/python/vyos/validate.py b/python/vyos/validate.py
index 98bd40f74..acd6086ff 100644
--- a/python/vyos/validate.py
+++ b/python/vyos/validate.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2018-2021 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -165,7 +165,7 @@ def assert_boolean(b):
def assert_range(value, lower=0, count=3):
- if int(value) not in range(lower,lower+count):
+ if int(value, 16) not in range(lower, lower+count):
raise ValueError("Value out of range")
diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py
index d5dcdc536..2d0a4827d 100755
--- a/smoketest/scripts/cli/test_interfaces_ethernet.py
+++ b/smoketest/scripts/cli/test_interfaces_ethernet.py
@@ -99,6 +99,31 @@ class EthernetInterfaceTest(BasicInterfaceTest.BaseTest):
flags = f.read()
self.assertEqual(int(flags, 16) & 1, 0)
+ def test_offloading_rps(self):
+ # enable RPS on all available CPUs, RPS works woth a CPU bitmask,
+ # where each bit represents a CPU (core/thread). The formula below
+ # expands to rps_cpus = 255 for a 8 core system
+ rps_cpus = (1 << os.cpu_count()) -1
+
+ # XXX: we should probably reserve one core when the system is under
+ # high preasure so we can still have a core left for housekeeping.
+ # This is done by masking out the lowst bit so CPU0 is spared from
+ # receive packet steering.
+ rps_cpus &= ~1
+
+ for interface in self._interfaces:
+ self.session.set(self._base_path + [interface, 'offload', 'rps'])
+
+ self.session.commit()
+
+ for interface in self._interfaces:
+ cpus = read_file('/sys/class/net/eth1/queues/rx-0/rps_cpus')
+ # remove the nasty ',' separation on larger strings
+ cpus = cpus.replace(',','')
+ cpus = int(cpus, 16)
+
+ self.assertEqual(f'{cpus:x}', f'{rps_cpus:x}')
+
def test_eapol_support(self):
for interface in self._interfaces:
diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py
index d8b637dd7..ed6396acf 100755
--- a/src/conf_mode/interfaces-ethernet.py
+++ b/src/conf_mode/interfaces-ethernet.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -75,9 +75,15 @@ def verify(ethernet):
verify_vrf(ethernet)
verify_eapol(ethernet)
+ ifname = ethernet['ifname']
+ # verify offloading capabilities
+ if 'offload' in ethernet and 'rps' in ethernet['offload']:
+ if not os.path.exists(f'/sys/class/net/{ifname}/queues/rx-0/rps_cpus'):
+ raise ConfigError('Interface does not suport RPS!')
+
# XDP requires multiple TX queues
if 'xdp' in ethernet:
- queues = glob('/sys/class/net/{ifname}/queues/tx-*'.format(**ethernet))
+ queues = glob(f'/sys/class/net/{ifname}/queues/tx-*')
if len(queues) < 2:
raise ConfigError('XDP requires additional TX queues, too few available!')