Skip to content

re-implement #654 onto latest main#698

Merged
internet-diglett merged 4 commits intomainfrom
levon/make-bgp-dispatch-listen-configurable-v2
Apr 10, 2026
Merged

re-implement #654 onto latest main#698
internet-diglett merged 4 commits intomainfrom
levon/make-bgp-dispatch-listen-configurable-v2

Conversation

@internet-diglett
Copy link
Copy Markdown
Contributor

Re-implements #654 because it was kinda hairy solving the merge conflicts

Comment on lines -385 to +393
// Use bind_addr from LogicalRouter if specified, otherwise use listen_addr
// Use bind_addr IP from LogicalRouter (port 0 so OS picks ephemeral),
// otherwise use listen_addr IP. The source port for outbound connections
// must not conflict with the dispatcher's listen port.
let bind_addr = logical_router
.bind_addr
.unwrap_or(logical_router.listen_addr);
.map(|addr| SocketAddr::new(addr.ip(), 0))
.unwrap_or_else(|| {
SocketAddr::new(logical_router.listen_addr.ip(), 0)
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

note: hard-coding of source port to 0

Do you anticipate the src_port ever being pinned up in tests for your uses of this?

Copy link
Copy Markdown
Contributor Author

@internet-diglett internet-diglett Apr 6, 2026

Choose a reason for hiding this comment

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

Do you anticipate the src_port ever being pinned up in tests for your uses of this?

At this point, I don't know. If we were good at anticipating what we'd need in our test suite I wouldn't be writing this PR 😂

A lot of the work that I've done in maghemite over the past few months is adding more flexibility so that it can be used upstream in omicron for testing, so exposing the reality that we're using a SocketAddr here to omicron so it can tweak it as necessary in tests seemed like a reasonable thing to do.

mgd/src/admin.rs Outdated
) -> Result<HttpResponseUpdatedNoContent, HttpError> {
bgp_admin::create_neighbor(ctx, request.map(Into::into)).await
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems like most of these could be impls provided in the trait definition, i.e. filling in the body in mg-api/src/lib.rs. Not a big deal, but I think would help keep things a little cleaner

Comment on lines +927 to +930
// new stuff after v6 (VERSION_BGP_SRC_ADDR)
/// Source IP address to bind when establishing outbound TCP connections.
/// None means the system selects the source address.
pub src_addr: Option<IpAddr>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you add some address-family validation for this into Neighbor.validate_address_families()? That's a nice centralized spot where we can return an error if src_addr isn't the same IP version as Neighbor.host.ip()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If you're feeling really ambitious, you could add the same validation method to struct UnnumberedNeighbor too, as I noticed we don't have the same validation in place there (I think I have a commit addressing this in #648, but that will likely take a while to get merged).

pub src_addr: Option<IpAddr>,
/// Source TCP port to bind when establishing outbound TCP connections.
#[serde(default)]
pub src_port: Option<u16>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would this be better suited as an Option<NonZeroU16>? i.e. what's the difference between None and Some(0)?

Copy link
Copy Markdown
Contributor Author

@internet-diglett internet-diglett Apr 6, 2026

Choose a reason for hiding this comment

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

Maybe. It could be reasonable to consider both None and Some(0) as semantically correct:

  • If you are creating a SocketAddr and don't specify a port, it is generally understood that the system will try to pick a random port
  • If you are creating a SocketAddr and specify port 0, it is generally understood that the system will try to pick a random port
  • If you are creating a SocketAddr and specify something other than port 0, it is understood that they system should try to bind to the requested port

On the other hand, is there an actual unsafe or unpredictable condition that we avoid by forcing the port to be NonZero if provided?

As the code sits, a caller could just yank whatever ip_address and port that was provided to them and pass it over and get the expected behavior.

If they don't have a port, they can pass None and get the expected behavior.

If we force NonZero, now the caller has to do an additional check before sending over the value, just to get the same outcome as if they passed Some(variable_that_had_zero_as_its_value). In maghemite's code we'd still have to set the port to 0 somewhere in the event that they provide None, so I don't know if we gain anything by forcing the extra check.

Ultimately this is all because we're splitting up the parameters to what is ultimately a SocketAddr under the hood and then exposing those parameters in the API. If we really wanted to simplify it, we could probably have the caller provide a SocketAddr as the src_addr.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was mainly pointing this out to show that we would get semantically equivalent outcomes with Option<NonZeroU16> and u16 -- both providing values that equate to 0 -- whereas Option<u16> provides two different values that equate to 0 (Some(0) and None being semantically equivalent).

I don't have super strong opinions here, so I'm happy to accept whatever you think makes the most sense

@internet-diglett internet-diglett marked this pull request as ready for review April 6, 2026 22:50
Comment on lines +2055 to +2058
// Validate that at least one AF is enabled
rq.validate_address_families()
.map_err(Error::InvalidRequest)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, thanks!

Copy link
Copy Markdown
Contributor

@taspelund taspelund left a comment

Choose a reason for hiding this comment

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

Thanks for the last few changes levon, ship it!

@internet-diglett internet-diglett merged commit 0dae867 into main Apr 10, 2026
15 checks passed
@internet-diglett internet-diglett deleted the levon/make-bgp-dispatch-listen-configurable-v2 branch April 10, 2026 03:37
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.

2 participants