nm ovs: Do not delete OVS bond port still in use

When detaching 2 ports from a existing OVS 4 ports bond, nmstate NM
plugin will remove the OVS bond port connection via
`delete_orphan_ovs_ports()` which cause failure in follow up activation.

The fix is instruct `delete_orphan_ovs_ports()` do not delete profiles
been marked in `nm_conns_to_activate`.

Integration test case included.

Signed-off-by: Gris Ge <fge@redhat.com>
This commit is contained in:
Gris Ge 2023-01-12 16:36:15 +08:00 committed by Fernando Fernández Mancera
parent e079f1d9e7
commit e2b3ea72b9
3 changed files with 97 additions and 2 deletions

View File

@ -119,6 +119,7 @@ pub(crate) fn nm_apply(
&mut nm_api,
&merged_state.interfaces,
&exist_nm_conns,
&nm_conns_to_activate,
)?;
}

View File

@ -14,6 +14,7 @@ pub(crate) fn delete_orphan_ovs_ports(
nm_api: &mut NmApi,
merged_ifaces: &MergedInterfaces,
exist_nm_conns: &[NmConnection],
nm_conns_to_activate: &[NmConnection],
) -> Result<(), NmstateError> {
let mut orphans: Vec<&str> = Vec::new();
for iface in merged_ifaces
@ -46,9 +47,19 @@ pub(crate) fn delete_orphan_ovs_ports(
.and_then(|c| c.controller.as_ref())
{
// We only touch port profiles created by nmstate which
// is using UUID for parent
// reference.
// is using UUID for parent reference.
if uuid::Uuid::parse_str(parent).is_ok() {
// The OVS bond might still have ports even
// specified interface detached, this OVS bond will
// be included in `nm_conns_to_activate()`, we just
// do not remove connection pending for activation.
if nm_conns_to_activate
.iter()
.any(|nm_conn| nm_conn.uuid() == Some(parent))
{
continue;
}
log::info!(
"Deleting orphan OVS port connection {parent} \
as interface {}({}) detached from OVS bridge",

View File

@ -1562,3 +1562,86 @@ def ovs_service_off():
def test_global_ovsdb_with_ovs_service_off(ovs_service_off):
libnmstate.apply({OvsDB.KEY: {}})
@pytest.fixture
def ovs_br_with_4_dummy_ports_ovs_bond():
desired_state = yaml.load(
"""---
interfaces:
- name: br0
type: ovs-bridge
state: up
bridge:
port:
- name: ovs-bond0
link-aggregation:
mode: balance-slb
port:
- name: dummy4
- name: dummy1
- name: dummy3
- name: dummy2
- name: dummy1
type: dummy
state: up
- name: dummy2
type: dummy
state: up
- name: dummy3
type: dummy
state: up
- name: dummy4
type: dummy
state: up
""",
Loader=yaml.SafeLoader,
)
libnmstate.apply(desired_state)
yield
desired_state = yaml.load(
"""---
interfaces:
- name: br0
type: ovs-bridge
state: absent
- name: dummy1
type: dummy
state: absent
- name: dummy2
type: dummy
state: absent
- name: dummy3
type: dummy
state: absent
- name: dummy4
type: dummy
state: absent
""",
Loader=yaml.SafeLoader,
)
libnmstate.apply(desired_state)
def test_ovs_detach_2_ports_from_4_ports_ovs_bond(
ovs_br_with_4_dummy_ports_ovs_bond,
):
desired_state = yaml.load(
"""---
interfaces:
- name: br0
type: ovs-bridge
state: up
bridge:
port:
- name: ovs-bond0
link-aggregation:
mode: balance-slb
port:
- name: dummy2
- name: dummy4
""",
Loader=yaml.SafeLoader,
)
libnmstate.apply(desired_state)
assertlib.assert_state_match(desired_state)