pass along physical_network to neutron from the baremetal port
When plugging a baremetal port in using the 'neutron' interface, send the 'physical_network' value of the baremetal port to Neutron as part of the binding_profile for the port. This can be useful for VXLAN underlay connected machines where the networks in Neutron are VXLAN networks which then have segments on them that are VLAN based segments which bind the VNI to a VLAN for attachment for the node to connect to the VNI. Ref: https://bugs.launchpad.net/ovn-bgp-agent/+bug/2017890 Ref: https://bugs.launchpad.net/neutron/+bug/2114451 Ref: https://review.opendev.org/c/openstack/neutron-specs/+/952166 Partial-Bug: #2105855 Assisted-by: Claude Code 2.0 Change-Id: I6e0185e203489676d530e6955929997f4871b8fa Signed-off-by: Doug Goldstein <cardoe@cardoe.com>
This commit is contained in:
@@ -371,6 +371,10 @@ def add_ports_to_network(task, network_uuid, security_groups=None):
|
||||
binding_profile['vtep-logical-switch'] = vtep_logical_switch
|
||||
binding_profile['vtep-physical-switch'] = vtep_physical_switch
|
||||
|
||||
# Include physical_network if available
|
||||
if ironic_port.physical_network:
|
||||
binding_profile['physical_network'] = ironic_port.physical_network
|
||||
|
||||
update_port_attrs['binding:profile'] = binding_profile
|
||||
|
||||
if not ironic_port.pxe_enabled:
|
||||
|
||||
@@ -272,6 +272,11 @@ def plug_port_to_tenant_network(task, port_like_obj, client=None):
|
||||
binding_profile = {'local_link_information': local_link_info}
|
||||
if local_group_info:
|
||||
binding_profile['local_group_information'] = local_group_info
|
||||
|
||||
# Include physical_network if available
|
||||
if port_like_obj.physical_network:
|
||||
binding_profile['physical_network'] = port_like_obj.physical_network
|
||||
|
||||
port_attrs['binding:profile'] = binding_profile
|
||||
|
||||
if client_id_opt:
|
||||
|
||||
@@ -329,6 +329,44 @@ class TestNeutronNetworkActions(db_base.DbTestCase):
|
||||
self._test_add_ports_to_network(is_client_id=False,
|
||||
security_groups=sg_ids)
|
||||
|
||||
@mock.patch.object(neutron, 'update_neutron_port', autospec=True)
|
||||
def test_add_ports_to_network_with_physical_network(self, update_mock):
|
||||
# Test that physical_network is included in binding:profile
|
||||
self.node.network_interface = 'neutron'
|
||||
self.node.save()
|
||||
port = self.ports[0]
|
||||
port.physical_network = 'physnet1'
|
||||
port.save()
|
||||
|
||||
expected_create_attrs = {
|
||||
'network_id': self.network_uuid,
|
||||
'admin_state_up': True,
|
||||
'binding:vnic_type': 'baremetal',
|
||||
'device_id': self.node.uuid
|
||||
}
|
||||
expected_update_attrs = {
|
||||
'device_owner': 'baremetal:none',
|
||||
'binding:host_id': self.node.uuid,
|
||||
'mac_address': port.address,
|
||||
'binding:profile': {
|
||||
'local_link_information': [port.local_link_connection],
|
||||
'physical_network': 'physnet1'
|
||||
}
|
||||
}
|
||||
|
||||
self.client_mock.create_port.return_value = self.neutron_port
|
||||
update_mock.return_value = self.neutron_port
|
||||
expected = {port.uuid: self.neutron_port['id']}
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
ports = neutron.add_ports_to_network(task, self.network_uuid)
|
||||
self.assertEqual(expected, ports)
|
||||
self.client_mock.create_port.assert_called_once_with(
|
||||
**expected_create_attrs)
|
||||
update_mock.assert_called_once_with(
|
||||
self.context, self.neutron_port['id'],
|
||||
expected_update_attrs)
|
||||
|
||||
@mock.patch.object(neutron, 'update_neutron_port', autospec=True)
|
||||
def test__add_ip_addresses_for_ipv6_stateful(self, mock_update):
|
||||
subnet_id = uuidutils.generate_uuid()
|
||||
|
||||
@@ -492,6 +492,76 @@ class TestCommonFunctions(db_base.DbTestCase):
|
||||
nclient, self.vif_id, 'ACTIVE', fail_on_binding_failure=True)
|
||||
self.assertTrue(mock_update.called)
|
||||
|
||||
@mock.patch.object(neutron_common, 'update_neutron_port', autospec=True)
|
||||
@mock.patch.object(neutron_common, 'wait_for_port_status', autospec=True)
|
||||
@mock.patch.object(neutron_common, 'get_client', autospec=True)
|
||||
def test_plug_port_to_tenant_network_with_physical_network(
|
||||
self, mock_gc, wait_mock_status, mock_update):
|
||||
# Test that physical_network is included in binding:profile for port
|
||||
nclient = mock.MagicMock()
|
||||
mock_gc.return_value = nclient
|
||||
self.port.internal_info = {common.TENANT_VIF_KEY: self.vif_id}
|
||||
self.port.physical_network = 'physnet1'
|
||||
self.port.save()
|
||||
|
||||
expected_attrs = {
|
||||
'binding:vnic_type': neutron_common.VNIC_BAREMETAL,
|
||||
'binding:host_id': self.node.uuid,
|
||||
'mac_address': self.port.address,
|
||||
'binding:profile': {
|
||||
'local_link_information': [self.port.local_link_connection],
|
||||
'physical_network': 'physnet1'
|
||||
}
|
||||
}
|
||||
|
||||
with task_manager.acquire(self.context, self.node.id) as task:
|
||||
common.plug_port_to_tenant_network(task, self.port)
|
||||
mock_update.assert_called_once_with(
|
||||
task.context, self.vif_id, expected_attrs)
|
||||
|
||||
@mock.patch.object(neutron_common, 'update_neutron_port', autospec=True)
|
||||
@mock.patch.object(neutron_common, 'wait_for_port_status', autospec=True)
|
||||
@mock.patch.object(neutron_common, 'get_client', autospec=True)
|
||||
def test_plug_portgroup_to_tenant_network_with_physical_network(
|
||||
self, mock_gc, wait_mock_status, mock_update):
|
||||
# Test that physical_network is included in binding:profile for
|
||||
# a portgroup
|
||||
nclient = mock.MagicMock()
|
||||
mock_gc.return_value = nclient
|
||||
pg = obj_utils.create_test_portgroup(
|
||||
self.context, node_id=self.node.id, address='00:54:00:cf:2d:01',
|
||||
physical_network='physnet1')
|
||||
port1 = obj_utils.create_test_port(
|
||||
self.context, node_id=self.node.id, address='52:54:00:cf:2d:01',
|
||||
portgroup_id=pg.id, uuid=uuidutils.generate_uuid())
|
||||
port2 = obj_utils.create_test_port(
|
||||
self.context, node_id=self.node.id, address='52:54:00:cf:2d:02',
|
||||
portgroup_id=pg.id, uuid=uuidutils.generate_uuid())
|
||||
pg.internal_info = {common.TENANT_VIF_KEY: self.vif_id}
|
||||
pg.save()
|
||||
|
||||
expected_attrs = {
|
||||
'binding:vnic_type': neutron_common.VNIC_BAREMETAL,
|
||||
'binding:host_id': self.node.uuid,
|
||||
'mac_address': pg.address,
|
||||
'binding:profile': {
|
||||
'local_link_information': [port1.local_link_connection,
|
||||
port2.local_link_connection],
|
||||
'local_group_information': {
|
||||
'id': pg.uuid,
|
||||
'name': pg.name,
|
||||
'bond_mode': pg.mode,
|
||||
'bond_properties': {}
|
||||
},
|
||||
'physical_network': 'physnet1'
|
||||
}
|
||||
}
|
||||
|
||||
with task_manager.acquire(self.context, self.node.id) as task:
|
||||
common.plug_port_to_tenant_network(task, pg)
|
||||
mock_update.assert_called_once_with(
|
||||
task.context, self.vif_id, expected_attrs)
|
||||
|
||||
|
||||
class TestVifPortIDMixin(db_base.DbTestCase):
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
When plugging a baremetal port in using the 'neutron' interface, send
|
||||
the 'physical_network' value of the baremetal port to Neutron as part of the
|
||||
binding_profile for the port.
|
||||
Reference in New Issue
Block a user