Improve OVS Representor VF Lookup

This patch set addresses some of the concerns outlined in:
https://bugs.launchpad.net/os-vif/+bug/1704485

* Determining the VF number from the netdev's phys_port_name:
  phys_port_name is read and then cast to an int.

  Currently there is no standard method to associate a representor with
  the VF number.
  phys_port_name has emerged as the "default" choice, but merely casting
  it as a single number has shortcomings:

  * A switchdev can potentially have VFs, PFs and physical ports as
    representors.
  * A switchdev can have multiple PFs.

  In this case, the recommendation is to use a parse tree that accepts
  naming conventions like:

  * 42
  * vf42
  * PF1VF42
  * vf42@PF1

* Test cases have been added for the above scenarios.

* An internal function for PF matching has been added for future use.
  This is important when PF representors are eventually exposed.

Change-Id: I051fcc6fd136b389a6200076bd6fc3b73b626d5e
Closes-Bug: #1704485
Signed-off-by: Jan Gutter <jan.gutter@netronome.com>
This commit is contained in:
Jan Gutter 2017-07-19 11:28:09 +02:00 committed by Jay Pipes
parent 18f3f70234
commit f4329ffe18
2 changed files with 60 additions and 2 deletions

View File

@ -36,6 +36,13 @@ LOG = logging.getLogger(__name__)
VIRTFN_RE = re.compile("virtfn(\d+)")
# phys_port_name only contains the VF number
INT_RE = re.compile("^(\d+)$")
# phys_port_name contains VF## or vf##
VF_RE = re.compile("vf(\d+)", re.IGNORECASE)
# phys_port_name contains PF## or pf##
PF_RE = re.compile("pf(\d+)", re.IGNORECASE)
def _ovs_vsctl(args, timeout=None):
full_args = ['ovs-vsctl']
@ -225,6 +232,35 @@ def _ovs_supports_mtu_requests(timeout=None):
return True
def _parse_vf_number(phys_port_name):
"""Parses phys_port_name and returns VF number or None.
To determine the VF number of a representor, parse phys_port_name
in the following sequence and return the first valid match. If none
match, then the representor is not for a VF.
"""
match = INT_RE.search(phys_port_name)
if match:
return match.group(1)
match = VF_RE.search(phys_port_name)
if match:
return match.group(1)
return None
def _parse_pf_number(phys_port_name):
"""Parses phys_port_name and returns PF number or None.
To determine the PF number of a representor, parse phys_port_name in
the following sequence and return the first valid match. If none
match, then the representor is not for a PF.
"""
match = PF_RE.search(phys_port_name)
if match:
return match.group(1)
return None
def get_representor_port(pf_ifname, vf_num):
"""Get the representor netdevice which is corresponding to the VF.
@ -271,10 +307,16 @@ def get_representor_port(pf_ifname, vf_num):
try:
with open(device_port_name_file, 'r') as fd:
representor_num = fd.readline().rstrip()
phys_port_name = fd.readline().rstrip()
except (OSError, IOError):
continue
representor_num = _parse_vf_number(phys_port_name)
# Note: representor_num can be 0, referring to VF0
if representor_num is None:
continue
# At this point we're confident we have a representor.
try:
if int(representor_num) == int(vf_num):
return device

View File

@ -358,6 +358,22 @@ class LinuxNetTest(testtools.TestCase):
mock_open.assert_has_calls(open_calls)
self.assertEqual(test_switchdev, True)
def test_parse_vf_number(self):
self.assertEqual(linux_net._parse_vf_number("0"), "0")
self.assertEqual(linux_net._parse_vf_number("pf13vf42"), "42")
self.assertEqual(linux_net._parse_vf_number("VF19@PF13"), "19")
self.assertEqual(linux_net._parse_vf_number("p7"), None)
self.assertEqual(linux_net._parse_vf_number("pf31"), None)
self.assertEqual(linux_net._parse_vf_number("g4rbl3d"), None)
def test_parse_pf_number(self):
self.assertEqual(linux_net._parse_pf_number("0"), None)
self.assertEqual(linux_net._parse_pf_number("pf13vf42"), "13")
self.assertEqual(linux_net._parse_pf_number("VF19@PF13"), "13")
self.assertEqual(linux_net._parse_pf_number("p7"), None)
self.assertEqual(linux_net._parse_pf_number("pf31"), "31")
self.assertEqual(linux_net._parse_pf_number("g4rbl3d"), None)
@mock.patch('six.moves.builtins.open')
@mock.patch.object(os.path, 'isfile')
@mock.patch.object(os, 'listdir')
@ -369,7 +385,7 @@ class LinuxNetTest(testtools.TestCase):
mock_open.return_value.__enter__ = lambda s: s
readline_mock = mock_open.return_value.readline
readline_mock.side_effect = (
['pf_sw_id', 'pf_sw_id', '1', 'pf_sw_id', '2'])
['pf_sw_id', 'pf_sw_id', '1', 'pf_sw_id', 'pf0vf2'])
open_calls = (
[mock.call('/sys/class/net/pf_ifname/phys_switch_id', 'r'),
mock.call().readline(),