Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions neutron/agent/ovn/metadata/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,13 +309,33 @@ def _load_config(self):
LOG.debug("Loaded chassis name %s (UUID: %s) and ovn bridge %s.",
self.chassis, self.chassis_id, self.ovn_bridge)

def _update_chassis_config(self):
"""Update the Chassis register information

This method should be called once the Metadata Agent has been
registered (method ``register_metadata_agent`` has been called) and
the corresponding Chasis or Chassis_Private register has been
created/updated. The Chassis table is used in an event when OVN does
not have the Chassis_Private.
"""
external_ids = {ovn_const.OVN_AGENT_OVN_BRIDGE: self.ovn_bridge}
if self.has_chassis_private:
self.sb_idl.db_set(
'Chassis_Private', self.chassis,
('external_ids', external_ids)).execute(check_error=True)
else:
self.sb_idl.db_set(
'Chassis', self.chassis,
('external_ids', external_ids)).execute(check_error=True)

@_sync_lock
def resync(self):
"""Resync the agent.

Reload the configuration and sync the agent again.
"""
self._load_config()
self._update_chassis_config()
self.sync()

def start(self):
Expand Down Expand Up @@ -361,6 +381,7 @@ def start(self):

# Register the agent with its corresponding Chassis
self.register_metadata_agent()
self._update_chassis_config()

self._proxy.wait()

Expand Down
1 change: 1 addition & 0 deletions neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ def _after_router_interface_deleted(self, resource, event, trigger,
port = payload.metadata.get('port')
self._notify_agents(payload.context, 'port_delete_end',
{'port_id': port['id'],
'fixed_ips': port['fixed_ips'],
'network_id': port['network_id']},
port['network_id'])

Expand Down
3 changes: 3 additions & 0 deletions neutron/common/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,6 @@

# Neutron-lib defines this with a /64 but it should be /128
METADATA_V6_CIDR = constants.METADATA_V6_IP + '/128'

# TODO(ralonsoh): move this constant to neutron_lib.plugins.ml2.ovs_constants
DEFAULT_BR_INT = 'br-int'
3 changes: 3 additions & 0 deletions neutron/common/ovn/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
OVN_NAME_PREFIX = 'neutron-'
OVN_HA_CH_GROUP_EXTPORT_PREFIX = 'neutron-extport-'

OVN_DATAPATH_TYPE = 'datapath-type'

# TODO(froyo): Move this to neutron-lib as soon as possible, and when a new
# release is created and pointed to in the requirements remove this code
OVN_LB_HM_PORT_DISTRIBUTED = 'ovn-lb-hm:distributed'
Expand All @@ -83,6 +85,7 @@
OVN_AGENT_NEUTRON_SB_CFG_KEY = 'neutron:ovn-neutron-agent-sb-cfg'
OVN_AGENT_NEUTRON_DESC_KEY = 'neutron:description-neutron-agent'
OVN_AGENT_NEUTRON_ID_KEY = 'neutron:ovn-neutron-agent-id'
OVN_AGENT_OVN_BRIDGE = 'neutron:ovn-bridge'
OVN_CONTROLLER_AGENT = 'OVN Controller agent'
OVN_CONTROLLER_GW_AGENT = 'OVN Controller Gateway agent'
OVN_METADATA_AGENT = 'OVN Metadata agent'
Expand Down
29 changes: 28 additions & 1 deletion neutron/common/ovn/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import tenacity

from neutron._i18n import _
from neutron.common import _constants as n_const
from neutron.common.ovn import constants
from neutron.common.ovn import exceptions as ovn_exc
from neutron.common import utils as common_utils
Expand Down Expand Up @@ -367,7 +368,7 @@ def validate_and_get_data_from_binding_profile(port):
if (constants.OVN_PORT_BINDING_PROFILE not in port or
not validators.is_attr_set(
port[constants.OVN_PORT_BINDING_PROFILE])):
BPInfo({}, None, [])
return BPInfo({}, None, [])
param_set = {}
param_dict = {}
vnic_type = port.get(portbindings.VNIC_TYPE, portbindings.VNIC_NORMAL)
Expand Down Expand Up @@ -718,6 +719,32 @@ def get_ovn_cms_options(chassis):
constants.OVN_CMS_OPTIONS, '').split(',')]


def get_ovn_bridge_from_chassis(chassis):
"""Return the OVN bridge used by the local OVN controller

This information is stored in the Chassis or Chassis_Private register by
the OVN Metadata agent. The default value returned, if not present, is
"br-int".
NOTE: the default value is not reading the local ``OVS.integration_bridge``
configuration knob, that could be different.
"""
return (chassis.external_ids.get(constants.OVN_AGENT_OVN_BRIDGE) or
n_const.DEFAULT_BR_INT)


def get_datapath_type(hostname, sb_idl):
"""Return the local OVS integration bridge datapath type

If the datapath type is not stored in the ``Chassis`` register or
the register is still not created, the default value returned is "".
"""
chassis = sb_idl.db_find(
'Chassis', ('hostname', '=', hostname)).execute(check_error=True)
return (
chassis[0].get('other_config', {}).get(constants.OVN_DATAPATH_TYPE, '')
if chassis else '')


def is_gateway_chassis(chassis):
"""Check if the given chassis is a gateway chassis"""
return constants.CMS_OPT_CHASSIS_AS_GW in get_ovn_cms_options(chassis)
Expand Down
2 changes: 1 addition & 1 deletion neutron/db/models_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ class SubnetPool(standard_attr.HasStandardAttributes, model_base.BASEV2,
lazy='subquery')
rbac_entries = sa.orm.relationship(rbac_db_models.SubnetPoolRBAC,
backref='subnetpools',
lazy='joined',
lazy='selectin',
cascade='all, delete, delete-orphan')
api_collections = [subnetpool_def.COLLECTION_NAME]
collection_resource_map = {subnetpool_def.COLLECTION_NAME:
Expand Down
42 changes: 32 additions & 10 deletions neutron/plugins/ml2/drivers/mech_sriov/agent/sriov_nic_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,39 @@ def network_update(self, context, **kwargs):
def binding_activate(self, context, **kwargs):
if kwargs.get('host') != self.agent.conf.host:
return
LOG.debug("binding activate for port %s", kwargs.get('port_id'))
device_details = self.agent.get_device_details_from_port_id(
kwargs.get('port_id'))
mac = device_details.get('mac_address')
binding_profile = device_details.get('profile')
if binding_profile:
pci_slot = binding_profile.get('pci_slot')
self.agent.activated_bindings.add((mac, pci_slot))

port_id = kwargs.get('port_id')

def _is_port_id_in_network(network_port, port_id):
for network_id, ports in network_port.items():
for port in ports:
if port['port_id'] == port_id:
return True
return False

is_port_id_sriov = _is_port_id_in_network(
self.agent.network_ports, port_id
)

if is_port_id_sriov:
LOG.debug("binding activate for port %s", port_id)
device_details = self.agent.get_device_details_from_port_id(
port_id)
mac = device_details.get('mac_address')
binding_profile = device_details.get('profile')
if binding_profile:
pci_slot = binding_profile.get('pci_slot')
self.agent.activated_bindings.add((mac, pci_slot))
else:
LOG.warning(
"binding_profile not found for port %s.",
port_id
)
else:
LOG.warning("binding_profile not found for port %s.",
kwargs.get('port_id'))
LOG.warning(
"This port is not SRIOV, skip binding for port %s.",
port_id
)

def binding_deactivate(self, context, **kwargs):
if kwargs.get('host') != self.agent.conf.host:
Expand Down
26 changes: 14 additions & 12 deletions neutron/plugins/ml2/drivers/ovn/db_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# 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 copy

from neutron_lib.api.definitions import portbindings as pb_api
from neutron_lib import context as n_context
Expand All @@ -20,6 +21,7 @@
from oslo_log import log as logging
from sqlalchemy.orm import exc as sqla_exc

from neutron.common import _constants as n_const
from neutron.db.models.plugins.ml2 import geneveallocation
from neutron.db.models.plugins.ml2 import vxlanallocation
from neutron.objects import network as network_obj
Expand All @@ -29,10 +31,6 @@

LOG = logging.getLogger(__name__)

VIF_DETAILS_TO_REMOVE = (
pb_api.VIF_DETAILS_BRIDGE_NAME,
)


def migrate_neutron_database_to_ovn():
"""Change DB content from OVS to OVN mech driver.
Expand Down Expand Up @@ -74,18 +72,22 @@ def migrate_neutron_database_to_ovn():
with db_api.CONTEXT_WRITER.using(ctx):
pb = port_obj.PortBinding.get_object(ctx, port_id=port_id,
host=host)
if not pb or not pb.vif_details:
if not pb:
continue

vif_details = pb.vif_details.copy()
for detail in VIF_DETAILS_TO_REMOVE:
try:
del vif_details[detail]
except KeyError:
pass
if vif_details == pb.vif_details:
# Update the OVS bridge name in the VIF details: now all
# port are directly connected to the integration bridge.
# Because the name of each host integration bridge is not
# know by the Neutron API at this point, the default value
# "br-int" will be used.
# The OVS datapath type is unchanged.
vif_details = copy.deepcopy(pb.vif_details) or {}
if (vif_details.get(pb_api.VIF_DETAILS_BRIDGE_NAME) ==
n_const.DEFAULT_BR_INT):
continue

vif_details[pb_api.VIF_DETAILS_BRIDGE_NAME] = (
n_const.DEFAULT_BR_INT)
pb.vif_details = vif_details
pb.update()
except (exceptions.ObjectNotFound,
Expand Down
20 changes: 16 additions & 4 deletions neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def get_supported_vif_types(self):
vif_types = set()
for ch in self.sb_ovn.chassis_list().execute(check_error=True):
other_config = ovn_utils.get_ovn_chassis_other_config(ch)
dp_type = other_config.get('datapath-type', '')
dp_type = other_config.get(ovn_const.OVN_DATAPATH_TYPE, '')
if dp_type == ovn_const.CHASSIS_DATAPATH_NETDEV:
vif_types.add(portbindings.VIF_TYPE_VHOST_USER)
else:
Expand Down Expand Up @@ -989,7 +989,7 @@ def bind_port(self, context):
return
chassis = agent.chassis
other_config = ovn_utils.get_ovn_chassis_other_config(chassis)
datapath_type = other_config.get('datapath-type', '')
datapath_type = other_config.get(ovn_const.OVN_DATAPATH_TYPE, '')
iface_types = other_config.get('iface-types', '')
iface_types = iface_types.split(',') if iface_types else []
chassis_physnets = self.sb_ovn._get_chassis_physnets(chassis)
Expand Down Expand Up @@ -1036,13 +1036,25 @@ def bind_port(self, context):
vif_type = portbindings.VIF_TYPE_VHOST_USER
port[portbindings.VIF_DETAILS].update({
portbindings.VHOST_USER_SOCKET: vhost_user_socket})
vif_details = dict(self.vif_details[vif_type])
vif_details = copy.deepcopy(self.vif_details[vif_type])
vif_details[portbindings.VHOST_USER_SOCKET] = (
vhost_user_socket)
else:
vif_type = portbindings.VIF_TYPE_OVS
vif_details = self.vif_details[vif_type]
vif_details = copy.deepcopy(self.vif_details[vif_type])

if self.agent_chassis_table == 'Chassis_Private':
chassis_to_retrieve = agent.chassis_private
else:
chassis_to_retrieve = agent.chassis
ovn_bridge = ovn_utils.get_ovn_bridge_from_chassis(
chassis_to_retrieve)

dp_type = ovn_utils.get_datapath_type(bind_host, self.sb_ovn)
vif_details.update({
portbindings.VIF_DETAILS_BRIDGE_NAME: ovn_bridge,
portbindings.OVS_DATAPATH_TYPE: dp_type,
})
context.set_binding(segment_to_bind[api.ID], vif_type,
vif_details)
break
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ def _start_metadata_agent(self):
with mock.patch.object(metadata_server.UnixDomainMetadataProxy,
'wait'):
agt.start()
external_ids = agt.sb_idl.db_get(
'Chassis_Private', agt.chassis, 'external_ids').execute(
check_error=True)
self.assertEqual(external_ids[ovn_const.OVN_AGENT_OVN_BRIDGE],
self.OVN_BRIDGE)

# Metadata agent will open connections to OVS and SB databases.
# Close connections to them when the test ends,
Expand Down
8 changes: 6 additions & 2 deletions neutron/tests/functional/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,12 @@ def stop(self):
if self.maintenance_worker:
self.mech_driver.nb_synchronizer.stop()
self.mech_driver.sb_synchronizer.stop()
self.mech_driver.nb_ovn.ovsdb_connection.stop()
self.mech_driver.sb_ovn.ovsdb_connection.stop()
for ovn_conn in (self.mech_driver.nb_ovn.ovsdb_connection,
self.mech_driver.sb_ovn.ovsdb_connection):
try:
ovn_conn.stop(timeout=10)
except Exception: # pylint:disable=bare-except
pass

def restart(self):
self.stop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def test_get_all_devices(self):
try:
common_utils.wait_until_true(
lambda: {macvtap.link.address} == self.mgr.get_all_devices(),
timeout=5)
timeout=10)
except common_utils.WaitTimeout:
msg = 'MacVTap address: %s, read devices: %s\n' % (
macvtap.link.address, self.mgr.get_all_devices())
Expand Down
Loading