libnetwork/osl: stop tracking neighbor entries#50088
Conversation
func (*Namespace) AddNeighbor is only ever called with the force parameter set to false. Remove the parameter and eliminate dead code. Signed-off-by: Cory Snider <csnider@mirantis.com>
Scope local variables as narrowly as possible. Signed-off-by: Cory Snider <csnider@mirantis.com>
The isDefault and nlHandle fields are immutable once the Namespace is constructed. Signed-off-by: Cory Snider <csnider@mirantis.com>
The Namespace keeps some state for each inserted neighbor-table entry which is used to delete the entry (and any related entries) given only the IP and MAC address of the entry to delete. This state is not strictly required as the retained data is a pure function of the parameters passed to AddNeighbor(), and the kernel can inform us whether an attempt to add a neighbor entry would conflict with an existing entry. Get rid of the neighbor state in Namespace. It's just one more piece of state that can cause lots of grief if it falls out of sync with ground truth. Require callers to call DeleteNeighbor() with the same aguments as they had passed to AddNeighbor(). Push the responsibility for detecting attempts to insert conflicting entries into the neighbor table onto the kernel by using (*netlink.Handle).NeighAdd() instead of NeighSet(). Modernize the error messages and logging in DeleteNeighbor() and AddNeighbor(). Signed-off-by: Cory Snider <csnider@mirantis.com>
There was a problem hiding this comment.
Pull Request Overview
This pull request removes the in-memory tracking of neighbor entries in the namespace and pushes neighbor management entirely to the kernel. Key changes include:
- Refactoring AddNeighbor and DeleteNeighbor to remove state management and instead rely on netlink operations.
- Eliminating the neighbors slice from the Namespace struct.
- Updating callers in the overlay driver to match the new function signatures.
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| libnetwork/osl/neigh_linux.go | Refactored neighbor add/delete functions and error messaging. |
| libnetwork/osl/namespace_linux.go | Removed neighbor state field from the Namespace struct. |
| libnetwork/osl/interface_linux.go | Simplified interface removal by directly using n.nlHandle. |
| libnetwork/drivers/overlay/peerdb.go | Updated neighbor API calls to match the new function signatures. |
Comments suppressed due to low confidence (2)
libnetwork/osl/neigh_linux.go:89
- [nitpick] Consider renaming the variable 'nlnh' to a more descriptive name (e.g., 'neighEntry') to better reflect its content and improve code clarity.
nlnh, linkName, err := n.nlNeigh(dstIP, dstMac, options...)
libnetwork/osl/interface_linux.go:831
- Confirm that accessing 'n.isDefault' without a lock remains safe; if 'n.isDefault' is mutable and accessed concurrently, consider using synchronization or atomic variables.
} else if !n.isDefault {
e0d5d62 to
0d6e7cd
Compare
| func (n NeighborSearchError) Error() string { | ||
| var b strings.Builder | ||
| b.WriteString("neighbor entry ") | ||
| if n.present { |
There was a problem hiding this comment.
This was the only part I had a comment on in the other PR. Non-blocking (from my perspective), but reposting here for others; #50081 (comment)
Not a blocker, but was mostly looking here for trade-offs between performance-optimisation (strings.Builder) and discoverability (being able to grep for the (partial) error message); wasn't sure how much this error is in a "hot path".
There was a problem hiding this comment.
I actually used the strings.Builder approach for readability rather than optimization. Note that there are two branches. To achieve something similar with fmt.Sprintf is not much more greppable. E.g.:
s := fmt.Sprintf("neighbor entry %s for IP %v, mac %v", map[bool]string{true: "already exists", false: "not found"}, n.ip, n.mac)
if n.linkName != "" {
s += fmt.Sprintf(", link %v", n.linkname)
}
return sThere was a problem hiding this comment.
Fair point. I guess I was comparing to the old;
return fmt.Sprintf("Search neighbor failed for IP %v, mac %v, present in db:%t", n.ip, n.mac, n.present)grepping for neighbor entry gave me many results, but perhaps there's no good option for that.
- What I did
The Namespace keeps some state for each inserted neighbor-table entry which is used to delete the entry (and any related entries) given only the IP and MAC address of the entry to delete. This state is not strictly required as the retained data is a pure function of the parameters passed to AddNeighbor(), and the kernel can inform us whether an attempt to add a neighbor entry would conflict with an existing entry. Get rid of the neighbor state in Namespace. It's just one more piece of state that can cause lots of grief if it falls out of sync with ground truth.
- How I did it
Require callers to call DeleteNeighbor() with the same aguments as they had passed to AddNeighbor(). Push the responsibility for detecting attempts to insert conflicting entries into the neighbor table onto the kernel by using (*netlink.Handle).NeighAdd() instead of
NeighSet().
- How to verify it
The overlay network driver is the only consumer of the AddNeighbor/DeleteNeighbor API so to verify it, test that overlay networks are still capable of forwarding traffic between containers on different nodes.
docker service create --mode global -p 80:8080 nginxdemos/hello:plain-text- Human readable description for the release notes
- A picture of a cute animal (not mandatory but encouraged)