Add support for native OVS binding
Currently we use ovs-vsctl command execution to bind pod infra container to the ovs bridge. As a follow-up work, it should be changed to use ovs-lib (as in [1]). [1] https://github.com/openstack/neutron/blob/master/neutron/agent/common/ovs_lib.py Change-Id: Ic50797c96f477ee6e71712ee2ab6b09dd721f558 Partially-Implements: blueprint kuryr-k8s-integration
This commit is contained in:
parent
7c03b7f290
commit
2c354b3cd0
|
@ -16,12 +16,12 @@
|
|||
import os
|
||||
|
||||
from kuryr_kubernetes.cni.binding import base as b_base
|
||||
from kuryr_kubernetes import linux_net_utils as net_utils
|
||||
|
||||
|
||||
class BridgeDriver(object):
|
||||
class BaseBridgeDriver(object):
|
||||
def connect(self, vif, ifname, netns):
|
||||
host_ifname = vif.vif_name
|
||||
bridge_name = vif.bridge_name
|
||||
|
||||
c_ipdb = b_base.get_ipdb(netns)
|
||||
h_ipdb = b_base.get_ipdb()
|
||||
|
@ -40,6 +40,18 @@ class BridgeDriver(object):
|
|||
h_iface.mtu = vif.network.mtu
|
||||
h_iface.up()
|
||||
|
||||
def disconnect(self, vif, ifname, netns):
|
||||
pass
|
||||
|
||||
|
||||
class BridgeDriver(BaseBridgeDriver):
|
||||
def connect(self, vif, ifname, netns):
|
||||
super(BridgeDriver, self).connect(vif, ifname, netns)
|
||||
host_ifname = vif.vif_name
|
||||
bridge_name = vif.bridge_name
|
||||
|
||||
h_ipdb = b_base.get_ipdb()
|
||||
|
||||
with h_ipdb.interfaces[bridge_name] as h_br:
|
||||
h_br.add_port(host_ifname)
|
||||
|
||||
|
@ -47,3 +59,17 @@ class BridgeDriver(object):
|
|||
# NOTE(ivc): veth pair is destroyed automatically along with the
|
||||
# container namespace
|
||||
pass
|
||||
|
||||
|
||||
class VIFOpenVSwitchDriver(BaseBridgeDriver):
|
||||
def connect(self, vif, ifname, netns):
|
||||
super(VIFOpenVSwitchDriver, self).connect(vif, ifname, netns)
|
||||
#FIXME(irenab) use pod_id (neutron port device_id)
|
||||
instance_id = 'kuryr'
|
||||
net_utils.create_ovs_vif_port(vif.bridge_name, vif.vif_name,
|
||||
vif.port_profile.interface_id,
|
||||
vif.address, instance_id)
|
||||
|
||||
def disconnect(self, vif, ifname, netns):
|
||||
super(VIFOpenVSwitchDriver, self).disconnect(vif, ifname, netns)
|
||||
net_utils.delete_ovs_vif_port(vif.bridge_name, vif.vif_name)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# Derived from nova/network/linux_net.py
|
||||
#
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# 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.
|
||||
|
||||
""" Implements linux net utils"""
|
||||
|
||||
from kuryr.lib._i18n import _LE
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _ovs_vsctl(args, timeout=None):
|
||||
full_args = ['ovs-vsctl']
|
||||
if timeout is not None:
|
||||
full_args += ['--timeout=%s' % timeout]
|
||||
full_args += args
|
||||
try:
|
||||
return processutils.execute(*full_args, run_as_root=True)
|
||||
except Exception as e:
|
||||
LOG.error(_LE("Unable to execute %(cmd)s. Exception: %(exception)s"),
|
||||
{'cmd': full_args, 'exception': e})
|
||||
raise
|
||||
|
||||
|
||||
def _create_ovs_vif_cmd(bridge, dev, iface_id, mac, instance_id):
|
||||
cmd = ['--', '--if-exists', 'del-port', dev, '--',
|
||||
'add-port', bridge, dev,
|
||||
'--', 'set', 'Interface', dev,
|
||||
'external-ids:iface-id=%s' % iface_id,
|
||||
'external-ids:iface-status=active',
|
||||
'external-ids:attached-mac=%s' % mac,
|
||||
'external-ids:vm-uuid=%s' % instance_id]
|
||||
return cmd
|
||||
|
||||
|
||||
def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id):
|
||||
_ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id, mac, instance_id))
|
||||
|
||||
|
||||
def delete_ovs_vif_port(bridge, dev):
|
||||
_ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev])
|
|
@ -239,8 +239,17 @@ def neutron_to_osvif_vif_ovs(vif_plugin, neutron_port, subnets):
|
|||
vif_name=_get_vif_name(neutron_port),
|
||||
bridge_name=_get_ovs_hybrid_bridge_name(neutron_port))
|
||||
else:
|
||||
raise NotImplementedError(_LE(
|
||||
"Non-hybrid OVS VIF is not supported yet"))
|
||||
vif = osv_vif.VIFOpenVSwitch(
|
||||
id=neutron_port['id'],
|
||||
address=neutron_port['mac_address'],
|
||||
network=network,
|
||||
has_traffic_filtering=details.get('port_filter', False),
|
||||
preserve_on_delete=False,
|
||||
active=_is_port_active(neutron_port),
|
||||
port_profile=profile,
|
||||
plugin=vif_plugin,
|
||||
vif_name=_get_vif_name(neutron_port),
|
||||
bridge_name=network.bridge)
|
||||
|
||||
return vif
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
# 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.
|
||||
|
||||
import mock
|
||||
from oslo_concurrency import processutils as utils
|
||||
|
||||
from kuryr_kubernetes import linux_net_utils as linux_net
|
||||
from kuryr_kubernetes.tests import base as test_base
|
||||
|
||||
|
||||
class LinuxNetworkUtilsTestCase(test_base.TestCase):
|
||||
|
||||
def test_ovs_vif_port_cmd(self):
|
||||
expected = ['--', '--if-exists',
|
||||
'del-port', 'fake-dev', '--', 'add-port',
|
||||
'fake-bridge', 'fake-dev',
|
||||
'--', 'set', 'Interface', 'fake-dev',
|
||||
'external-ids:iface-id=fake-iface-id',
|
||||
'external-ids:iface-status=active',
|
||||
'external-ids:attached-mac=fake-mac',
|
||||
'external-ids:vm-uuid=fake-instance-uuid']
|
||||
cmd = linux_net._create_ovs_vif_cmd('fake-bridge', 'fake-dev',
|
||||
'fake-iface-id', 'fake-mac',
|
||||
'fake-instance-uuid')
|
||||
|
||||
self.assertEqual(expected, cmd)
|
||||
|
||||
def test_create_ovs_vif_port(self):
|
||||
calls = [
|
||||
mock.call('ovs-vsctl', '--', '--if-exists',
|
||||
'del-port', 'fake-dev', '--', 'add-port',
|
||||
'fake-bridge', 'fake-dev',
|
||||
'--', 'set', 'Interface', 'fake-dev',
|
||||
'external-ids:iface-id=fake-iface-id',
|
||||
'external-ids:iface-status=active',
|
||||
'external-ids:attached-mac=fake-mac',
|
||||
'external-ids:vm-uuid=fake-instance-uuid',
|
||||
run_as_root=True)]
|
||||
with mock.patch.object(utils, 'execute', return_value=('', '')) as ex:
|
||||
linux_net.create_ovs_vif_port('fake-bridge', 'fake-dev',
|
||||
'fake-iface-id', 'fake-mac',
|
||||
'fake-instance-uuid')
|
||||
ex.assert_has_calls(calls)
|
||||
|
||||
def test_delete_ovs_vif_port(self):
|
||||
calls = [
|
||||
mock.call('ovs-vsctl', '--', '--if-exists',
|
||||
'del-port', 'fake-bridge', 'fake-dev',
|
||||
run_as_root=True)]
|
||||
with mock.patch.object(utils, 'execute', return_value=('', '')) as ex:
|
||||
linux_net.delete_ovs_vif_port('fake-bridge', 'fake-dev')
|
||||
ex.assert_has_calls(calls)
|
|
@ -215,16 +215,34 @@ class TestOSVIFUtils(test_base.TestCase):
|
|||
vif_name=vif_name,
|
||||
bridge_name=hybrid_bridge)
|
||||
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._get_vif_name')
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._is_port_active')
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._make_vif_network')
|
||||
@mock.patch('os_vif.objects.vif.VIFOpenVSwitch')
|
||||
@mock.patch('os_vif.objects.vif.VIFPortProfileOpenVSwitch')
|
||||
def test_neutron_to_osvif_vif_ovs_native(self,
|
||||
m_mk_profile,
|
||||
m_make_vif_network):
|
||||
m_mk_vif,
|
||||
m_make_vif_network,
|
||||
m_is_port_active,
|
||||
m_get_vif_name):
|
||||
vif_plugin = 'ovs'
|
||||
port_id = mock.sentinel.port_id
|
||||
mac_address = mock.sentinel.mac_address
|
||||
ovs_bridge = mock.sentinel.ovs_bridge
|
||||
subnets = mock.sentinel.subnets
|
||||
port_profile = mock.sentinel.port_profile
|
||||
network = mock.sentinel.network
|
||||
port_active = mock.sentinel.port_active
|
||||
vif_name = mock.sentinel.vif_name
|
||||
vif = mock.sentinel.vif
|
||||
|
||||
m_mk_profile.return_value = port_profile
|
||||
m_make_vif_network.return_value = network
|
||||
m_is_port_active.return_value = port_active
|
||||
m_get_vif_name.return_value = vif_name
|
||||
m_mk_vif.return_value = vif
|
||||
|
||||
port = {'id': port_id,
|
||||
'mac_address': mac_address,
|
||||
'binding:vif_details': {
|
||||
|
@ -232,9 +250,13 @@ class TestOSVIFUtils(test_base.TestCase):
|
|||
'bridge_name': ovs_bridge},
|
||||
}
|
||||
|
||||
# TODO(ivc): implement proper tests once ovs-native VIFs are supported
|
||||
self.assertRaises(NotImplementedError, ovu.neutron_to_osvif_vif_ovs,
|
||||
vif_plugin, port, subnets)
|
||||
self.assertEqual(vif, ovu.neutron_to_osvif_vif_ovs(vif_plugin, port,
|
||||
subnets))
|
||||
m_mk_profile.assert_called_once_with(interface_id=port_id)
|
||||
m_make_vif_network.assert_called_once_with(port, subnets)
|
||||
m_is_port_active.assert_called_once_with(port)
|
||||
m_get_vif_name.assert_called_once_with(port)
|
||||
self.assertEqual(ovs_bridge, network.bridge)
|
||||
|
||||
def test_neutron_to_osvif_vif_ovs_no_bridge(self):
|
||||
vif_plugin = 'ovs'
|
||||
|
|
|
@ -32,6 +32,7 @@ kuryr_kubernetes.vif_translators =
|
|||
|
||||
kuryr_kubernetes.cni.binding =
|
||||
VIFBridge = kuryr_kubernetes.cni.binding.bridge:BridgeDriver
|
||||
VIFOpenVSwitch = kuryr_kubernetes.cni.binding.bridge:VIFOpenVSwitchDriver
|
||||
|
||||
kuryr_kubernetes.controller.drivers.pod_project =
|
||||
default = kuryr_kubernetes.controller.drivers.default_project:DefaultPodProjectDriver
|
||||
|
|
Loading…
Reference in New Issue