8000 nm: Refactor NmActiveConnection and NmConnection search code by cathay4t · Pull Request #2903 · nmstate/nmstate · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

nm: Refactor NmActiveConnection and NmConnection search code #2903

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: base
Choose a base branch
from

Conversation

cathay4t
Copy link
Member
@cathay4t cathay4t commented May 26, 2025

Introducing NmConnectionMatcher to unify the effort on find the matching NmActiveConnection and NmConnection.

Resolves: https://issues.redhat.com/browse/RHEL-92916
Resolves: https://issues.redhat.com/browse/RHEL-86240

@kubevirt-bot
Copy link
Collaborator

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

Copy link

Congratulations! One of the builds has completed. 🍾

You can install the built RPMs by following these steps:

  • sudo yum install -y dnf-plugins-core on RHEL 8
  • sudo dnf install -y dnf-plugins-core on Fedora
  • dnf copr enable packit/nmstate-nmstate-2903
  • And now you can install the packages.

Please note that the RPMs should be used only in a testing environment.

@cathay4t cathay4t force-pushed the down_desc branch 2 times, most recently from 52fd5ae to e3faed6 Compare May 27, 2025 09:24
Comment on lines 9 to 19
// Using &str for UUID or name will complex the code due to ownership,
// Considering this duplication on UUID and name only created once at
// `Self::new()` stage, it is acceptable cost.
//
// Using NmIfaceType instead of &NmIfaceType in order to matching veth
// interface against ethernet NmConnection, we need to duplicate NmConnection
// both to Veth and Ethernet key.
//
// Using String instead of &str for interface name indexing because VLAN
// connection can have auto-generated `connection.interface-name` when it is
// empty.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove this comment, too low level detail for such a long comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote it in case you ask me why store cloned String instead of &str.

Comment on lines 24 to 40
10000
// UUID to NmActiveConnection
nm_acs: HashMap<String, Rc<NmActiveConnection>>,
// (name, nm_iface_type) to Rc<NmActiveConnection>
// Veth will also stored into `NmIfaceType::Ethernet`
nm_acs_index: HashMap<(String, NmIfaceType), Rc<NmActiveConnection>>,

// (name, nm_iface_type) to Rc<NmConnection>
// Veth will also stored into `NmIfaceType::Ethernet`
nm_applied_conns_index: HashMap<(String, NmIfaceType), Rc<NmConnection>>,

// (name, nm_iface_type) to Rc<NmConnection>
// Veth will also stored into `NmIfaceType::Ethernet`
nm_saved_conns_index: HashMap<(String, NmIfaceType), Vec<Rc<NmConnection>>>,

// (mac_upper_case, nm_iface_type) to Vec<Rc<NmConnection>> for mac
// identifier Veth will also stored into `NmIfaceType::Ethernet`
nm_saved_conns_mac: HashMap<(String, NmIfaceType), Vec<Rc<NmConnection>>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of these comments, better to explain the content in the field name itself. Example: active_conns_by_uuid instead of nm_acs, applied_cons_by_iface instead of nm_applied_conns_index, etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

Comment on lines 110 to 116
// For all applied NmConnection, it should have existing
// network interface defined, hence we ignore unexpected
// NmConnection
log::debug!(
"Ignoring applied NmConnection which cannot resolve its \
network interface {nm_conn:?}"
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's something that must not happen, better to return an error or panic via assertion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User might have existing NmConnection pointing to deleted NIC, it is valid environment, we should not raise any error or warning on this. Treat is debug log can be collected when failure happens.

.and_modify(|nm_conns| nm_conns.push(nm_conn.clone()))
.or_insert(vec![nm_conn.clone()]);
}
if nm_conn.iface_name().unwrap_or_default().is_empty() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to store by MAC only if interface name is empty? Doesn't make sense to store it anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When user have disconnected NIC, nmstate should support deleting its mac-identifier NmConnection.

self.nm_saved_conns_index
.entry((name.to_string(), NmIfaceType::Ethernet))
.and_modify(|nm_conns| nm_conns.push(nm_conn.clone()))
.or_insert(vec![nm_conn.clone()]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use or_insert_with to avoid eagerly evaluation of the argument. With or_insert you will always allocate a Vec and clone the Rc.
Alternatively, I think that .entry(...).or_insert_with(|| Vec::new()).push(nm_conn.clone()) would work too.
Same for the other 3 times in the function.

self.nm_acs.contains_key(uuid)
}

pub(crate) fn get_applied_by_name_type(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: get_applied_by_iface

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have get_applied() which takes BaseInterface, so this by_iface might be not fit here.

Comment on lines 325 to 343
if let Some(mac) = nm_conn
.wired
.as_ref()
.and_then(|s| s.mac_address.as_deref())
{
if let Some(name) = cur_state.interfaces.iter().find_map(|iface| {
if iface.base_iface().mac_address.as_deref() == Some(mac) {
Some(iface.name().to_string())
} else {
None
}
}) {
return Some(name);
}
}
None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to descri 8000 be this comment to others. Learn more.

For VLAN, MACVLAN and MACSEC, ethernet.mac-address is the MAC of the parent, not of the interface itself.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

cur_state: NetworkState,
}

impl ProfileSearch {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: rename to NmConnectionMatcher.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

@ihuguet
Copy link
Member
ihuguet commented May 27, 2025

Please try to split in smaller logical commits for the final review.

@cathay4t cathay4t force-pushed the down_desc branch 2 times, most recently from 54e4ad2 to cdf8867 Compare May 28, 2025 11:55
@cathay4t
Copy link
Member Author

Please try to split in smaller logical commits for the final review.

I will split them into small parts once CI are all happy. Still coding.

cathay4t added 3 commits June 4, 2025 20:33
Previously, the `nm_dbus` was designed to be standalone crate without
dependency on nmstate, so `iface_type_to_nm()` is used to convert from
`InterfaceType` to `NmIfaceType`. But we don't have plan to release
`nm_dbus` crate anymore, so we should use From trait instead of function
for conversion between `InterfaceType` and `NmIfaceType`.

Signed-off-by: Gris Ge <fge@redhat.com>
Introducing `NmSettingConnection.autoconnect_priority`, it holds `i32` for
priority when multiple NmConnection is capable for activating the same
NmDevice, the bigger number is better.

This property will be use for choosing the correct NmConnection to
modify when `nmstatectl apply` with multiple connections in NM.

Signed-off-by: Gris Ge <fge@redhat.com>
Introducing `NmSettingConnection.timestamp` holding the last successful
activation time since EPOCH in seconds.

This property will be used for nmstate to choose the correct
NmConnection to modify when multiple NmConnection founds.

Signed-off-by: Gris Ge <fge@redhat.com>
@cathay4t cathay4t force-pushed the down_desc branch 2 times, most recently from 49f63cb to eedef40 Compare June 4, 2025 14:08
@cathay4t cathay4t changed the title WIP nm: Refactor profile searching code nm: Refactor NmActiveConnection and NmConnection search code Jun 4, 2025
@cathay4t cathay4t marked this pull request as ready for review June 4, 2025 14:24
@cathay4t cathay4t marked this pull request as draft June 4, 2025 14:33
cathay4t added 7 commits June 5, 2025 16:50
Creating struct `NmConnectionMatcher` to unify the effort on searching
NmConnection for querying and modification.

The `NmConnectionMatcher` will create indexes at initialization to speed
up follow up queries.

Signed-off-by: Gris Ge <fge@redhat.com>
Use `NmConnectionMatcher` for matching NmDevice with NmConnection during
`nmstatectl show`.

Signed-off-by: Gris Ge <fge@redhat.com>
Use `NmConnectionMatcher` to find the correct NmConnection to
modify/delete.

Resolves: https://issues.redhat.com/browse/RHEL-92916
Resolves: https://issues.redhat.com/browse/RHEL-86240

Signed-off-by: Gris Ge <fge@redhat.com>
Support handling HSR interface type when generating `BaseInterface` from
`NmDevice`.

This was not a problem because old patch ws using `NmConnection` to
build up `BaseInterface`. When we refactor the NmConnection search code,
we unified the effort by using NmDevice only for querying.

Existing HSR test cases are enough for testing this patch.

Signed-off-by: Gris Ge <fge@redhat.com>
With a dummy NM connection created by deactivated, applying desire state
like:

```
interfaces:
  - name: dummy1
    state: absent
```

will not delete the NM connection.

This is because `NmConnectionMatcher::get_saved()` is searching for
NmConnection with `NmIfaceType::Unknown`.

To fix that issue, when `get_saved()` got unknown interface, all
`NmConnection` matching specified name will be returned.

The integration test case `test_state_absent_can_remove_down_profiles`
can reproduce the issue and confirm fix.

Signed-off-by: Gris Ge <fge@redhat.com>
When modifying existing NmConnection with desired state:

```
---
interfaces:
- name: port1
  type: ethernet
  mac-address: 00:23:45:67:89:1a
  identifier: mac-address
```
The `NmConnectionMatcher::get_prefered_saved()` will return empty
None because name in this case is `port1` instead of the actual NIC
name.

Fixed by rename existing `NmConnectionMatcher::get_prefered_saved()` to
`get_prefered_saved_by_name_type()` and the new
`NmConnectionMatcher::get_prefered_saved()` is accepting
`BaseInterface`.

When got `InterfaceIdentifier::MacAddress`, we search the MAC address
and interface type instead of its profile name.

Signed-off-by: Gris Ge <fge@redhat.com>
Previously we are depending `NmApi::connection_reapply()` to find the
correct NmDevice to reapply. But `test_reapply_bond_port_ref_by_mac`
test case sometimes noticed it choose the wrong NmDevice which lead to
reapply failure.

The root cause is bond ports are holding the same MAC address after
attached to a bond. If we search NmDevice by interface type and MAC, we
might get the incorrect one.

To fix this issue:

 * Expanded `NmActiveConnection` to hold NmDevice object path.
 * Changed `activate_nm_profiles()` will use `NmConnectionMatcher` which
   holds pre-apply NmActiveConnection.
 * Changed `NmApi::connection_reapply()` to take object path of
   `NmDevice` explicitly instead of guessing.

Existing test case `test_reapply_bond_port_ref_by_mac` is enough to test
this patch.

Signed-off-by: Gris Ge <fge@redhat.com>
Given a interface is activated by multiconnect NmConnection, when
applying state like

```
interfaces:
- name: eth1
  state: up
```
, nmstate will modify the multiconnect interface which is not expected.

The fix is do not return multiconnect NmConnection when
`iface.is_up_exist_config()`.

This is work well before `NmConnectionMatcher` is because:

 * Old code does not prefer activated `NmConnection` as saved profile but
   only searching name and interface type
 * No `NmConnection` been found for `iface.is_up_exist_config()`.
 * Nmstate using current state to create new `NmConnection`.

Existing test case `test_preserve_ip_settings_from_multiconnect` is
enough to test this case.

Signed-off-by: Gris Ge <fge@redhat.com>
@cathay4t cathay4t marked this pull request as ready for review June 5, 2025 09:56
@cathay4t
Copy link
Member Author
cathay4t commented Jun 5, 2025

PR is ready for review.

@kubevirt-bot
Copy link
Collaborator

@cathay4t: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-nmstate-integ_tier1-k8s e98695a link false /test pull-nmstate-integ_tier1-k8s

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0