Workaround for TCP checksum issue with ovs-dpdk and veth pair

The need for this change stems from following issues:
1) When ovs_use_veth = False with ovs-dpdk issue with ovs
was observed - after vswitch restart interface is not comming up.
Meaning ovs-dpdk uses ovs internal ports and it is not able to bring
them up on restart.
2) When ovs_use_veth = True and ovs-dpkd is used, packets sent with
incorrect checksum due to the fact that ovs-dpdk does not do checksum
calculations for veth interface.

This commit allows to use second option and resolve checksum issue by
disabling checksum offload.

Closes-Bug: #1832021
Related-Bug: #1831935

Change-Id: Iecce8d2c6c2c46718cc1020c6e8f914cd4560e4b
This commit is contained in:
Alexander Vlasov 2020-03-18 13:35:20 -05:00
parent 48fe3d2a46
commit 11838a2bc5
5 changed files with 60 additions and 0 deletions

View File

@ -10,6 +10,7 @@
# dhcp-agent
dnsmasq: CommandFilter, dnsmasq, root
ethtool: CommandFilter, ethtool, root
# dhcp-agent uses kill as well, that's handled by the generic KillFilter
# it looks like these are the only signals needed, per
# neutron/agent/linux/dhcp.py

View File

@ -12,6 +12,7 @@
arping: CommandFilter, arping, root
# l3_agent
ethtool: CommandFilter, ethtool, root
sysctl: CommandFilter, sysctl, root
route: CommandFilter, route, root
radvd: CommandFilter, radvd, root

View File

@ -0,0 +1,34 @@
# Copyright 2020 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.agent.linux import ip_lib
class Ethtool(object):
COMMAND = 'ethtool'
@staticmethod
def _cmd(cmd, namespace, **kwargs):
ip_wrapper = ip_lib.IPWrapper(namespace)
return ip_wrapper.netns.execute(cmd, run_as_root=True, **kwargs)
@classmethod
def offload(cls, device, rx, tx, namespace=None):
rx = 'on' if rx else 'off'
tx = 'on' if tx else 'off'
cmd = ['--offload', device, 'rx', rx, 'tx', tx]
cmd = [cls.COMMAND] + cmd
cls._cmd(cmd, namespace)

View File

@ -25,8 +25,12 @@ from pyroute2.netlink import exceptions as pyroute2_exc
import six
from neutron.agent.common import ovs_lib
from neutron.agent.linux import ethtool
from neutron.agent.linux import ip_lib
from neutron.common import utils
from neutron.conf.plugins.ml2.drivers import ovs_conf
from neutron.plugins.ml2.drivers.openvswitch.agent.common \
import constants as ovs_const
LOG = logging.getLogger(__name__)
@ -317,6 +321,7 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
def __init__(self, conf, **kwargs):
super(OVSInterfaceDriver, self).__init__(conf, **kwargs)
ovs_conf.register_ovs_agent_opts(self.conf)
if self.conf.ovs_use_veth:
self.DEV_NAME_PREFIX = 'ns-'
@ -402,6 +407,11 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
ns_dev.link.set_up()
if self.conf.ovs_use_veth:
# ovs-dpdk does not do checksum calculations for veth interface
# (bug 1832021)
if self.conf.OVS.datapath_type == ovs_const.OVS_DATAPATH_NETDEV:
ethtool.Ethtool.offload(ns_dev.name, rx=False, tx=False,
namespace=namespace)
root_dev.link.set_up()
def unplug(self, device_name, bridge=None, namespace=None, prefix=None):

View File

@ -19,11 +19,14 @@ from oslo_utils import excutils
from pyroute2.netlink import exceptions as pyroute2_exc
from neutron.agent.common import ovs_lib
from neutron.agent.linux import ethtool
from neutron.agent.linux import interface
from neutron.agent.linux import ip_lib
from neutron.common import utils
from neutron.conf.agent import common as config
from neutron.conf.plugins.ml2.drivers import ovs_conf
from neutron.plugins.ml2.drivers.openvswitch.agent.common \
import constants as ovs_const
from neutron.tests import base
@ -63,6 +66,8 @@ class TestBase(base.BaseTestCase):
self.conf = config.setup_conf()
ovs_conf.register_ovs_opts(self.conf)
config.register_interface_opts(self.conf)
self.eth_tool_p = mock.patch.object(ethtool, 'Ethtool')
self.eth_tool = self.eth_tool_p.start()
self.ip_dev_p = mock.patch.object(ip_lib, 'IPDevice')
self.ip_dev = self.ip_dev_p.start()
self.ip_p = mock.patch.object(ip_lib, 'IPWrapper')
@ -507,7 +512,12 @@ class TestOVSInterfaceDriverWithVeth(TestOVSInterfaceDriver):
def setUp(self):
super(TestOVSInterfaceDriverWithVeth, self).setUp()
ovs_conf.register_ovs_agent_opts(self.conf)
self.conf.set_override('ovs_use_veth', True)
self.conf.set_override(
'datapath_type',
ovs_const.OVS_DATAPATH_NETDEV,
group='OVS')
def test_get_device_name(self):
br = interface.OVSInterfaceDriver(self.conf)
@ -538,6 +548,7 @@ class TestOVSInterfaceDriverWithVeth(TestOVSInterfaceDriver):
mock.patch.object(
interface, '_get_veth',
return_value=(root_dev, ns_dev)).start()
ns_dev.name = devname
expected = [mock.call(),
mock.call().add_veth('tap0', devname,
@ -568,6 +579,9 @@ class TestOVSInterfaceDriverWithVeth(TestOVSInterfaceDriver):
self.ip.assert_has_calls(expected)
root_dev.assert_has_calls([mock.call.link.set_up()])
ns_dev.assert_has_calls([mock.call.link.set_up()])
self.eth_tool.assert_has_calls([mock.call.offload(
devname, rx=False,
tx=False, namespace=namespace)])
def test_plug_new(self):
# The purpose of test_plug_new in parent class(TestOVSInterfaceDriver)