-
Notifications
You must be signed in to change notification settings - Fork 85
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
network: bridge: add support for unmanaged mode #1126
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is something I did not thought about. What does it mean to be a internal network with l2? There seems to be fair bit of overlap between internal l3 and l2 (except for a few sysctls and the delete the bridge thing).
My understanding is that routing would not be able to blocked without using the firewall in the l2 case normally you would have your l2 ethX interface connected to the bridge and your LAN so there is no ip routing happing on the host system as all the packages will be send to the routed normally vie the LAN.
I guess there is no good reason to support this but I wonder if we should make podman (rather c/common) error out if internal and l2 is used
src/network/bridge.rs
Outdated
L2, | ||
L3, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add comments to the types what they do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/network/bridge.rs
Outdated
setup_ipv4_fw_sysctl()?; | ||
if data.ipam.ipv6_enabled { | ||
setup_ipv6_fw_sysctl()?; | ||
if let BridgeMode::L3 = data.mode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mhh using if let means it will not fail to compile if we add a new enum variant, right?
If we ever were to add a third mode I think it would be cleaner to fail so we have to make a explicit decision
Also now that I look at this we should really not set the global sysctl for internal networks here (feel free to fix this in a second commit or I put it on my list)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If podman passed an unsupported mode it would fail in get_bridge_mode_from_string
. In case you mean "in case we add support for the new mode, but forget to handle it in all places", we need to use match
everywhere. It might make some conditions more complicated but it would cause compile-errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes I meant we forget to handle it. However if we go unmanaged/managed for now I think it is safe enough that we do not add new modes often enough. And if we do we need to check what mode should do what anyway so let's keep the readable form.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense.
Also now that I look at this we should really not set the global sysctl for internal networks here (feel free to fix this in a second commit or I put it on my list)
done
src/network/bridge.rs
Outdated
@@ -225,7 +237,7 @@ impl driver::NetworkDriver for Bridge<'_> { | |||
}; | |||
|
|||
// if the network is internal block routing and do not setup firewall rules | |||
if self.info.network.internal { | |||
if self.info.network.internal && data.mode == BridgeMode::L3 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we wrap this entire part in if let BridgeMode::L3 = data.mode {
up until the setup_firewall call we would only need to match once
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea, done
src/network/bridge.rs
Outdated
error_list.push(err); | ||
} | ||
}; | ||
if let BridgeMode::L3 = mode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we simplify this together with the self.info.network.internal condition into one and then remove the early return from internal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea, done
src/network/bridge.rs
Outdated
if let BridgeMode::L2 = data.mode { | ||
return Err(err).wrap("l2 bridge interface not found"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if user will be running into 730e1bf if we do not create the bridge. There seems to be bad things going on while/adding removing new interfaces.
I think the error here should say l2 requires the bridge to already exist on the host
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but for an unmanaged bridge I'd let netavark move that responsibility to the creator of the bridge. The workaround is not needed if you manually set a mac address on the bridge, because it'll then keep that address forever.
core_utils::CoreUtils::apply_sysctl_value(disable_dad_in_container, "0")?; | ||
} | ||
let enable_arp_notify = format!( | ||
"/proc/sys/net/ipv4/conf/{}/arp_notify", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we may want to keep arp_notify even on l2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know, all of these can actually be useful for both managed and unmanaged mode. The question is just if we want to enforce our own defaults or rely on the linux kernel defaults. If we want to make this decision differently for each sysctl, we have to document why.
It may just be me, but I always had trouble understanding what
No matter if podman "manages" the bridge or not, having podman configure addresses and routes can be useful. You can compare that with static IPs and routes inside the network-config of a physical host. Also, podmans firewall is currently external to the container, so it can be compared to a managed l3 switch with an integrated firewall. That is definitely needed for both managed and external bridges, the question is just if there is a need to have podman setup the firewall for external bridges. My guess is: no. Either way, podman currently does not have an option to disable the firewall for a single network, that's why I disabled it for L2 in this PR.
Without a firewall, the only way to block traffic going out the bridge to a different interface is by setting the forwarding sysctls to Also, there doesn't always have to be a physical port on an external bridge. For example, you could simply want to put both containers and libvirt VMs on the same bridge so they can communicate directly, but you don't want them to access the internet or the physical local network. Or your containers are running on the router itself and you have to forward packets to the wan interface instead of l2-switching them through the bridge to a different port. Given my arguments above, implementing the external bridge feature as l2 vs l3 mode might be confusing. In the end it's an API choice and will not affect the functionality, but you might want to reconsider it.
|
Yeah I am to sure about the naming either. My think was l3 is routed while 2 is local LAN but l2 is just whatever the user configured so you are right that that naming does not really reflect what is going on. Would something |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code seems good, two minor nits on the test then LGTM
test/620-bridge-mode.bats
Outdated
assert "$output" "==" 'Device "podman0" does not exist.' | ||
} | ||
|
||
@test bridge - l2 mode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test need to be changed to unmanged
test/620-bridge-mode.bats
Outdated
|
||
run_netavark --file ${TESTSDIR}/testfiles/bridge-unmanaged.json teardown $(get_container_netns_path) | ||
|
||
# check if the interface gets removed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a bit confusion, it should say that we ensure the bridge is not removed.
While Linux doesn't support modes on bridges, we use this concept to let the user tell us if they want podman/netavark to own the bridge or not. Managed behaves the same way as before this commit. Unmanaged requires the bridge to exist already, will not setup any sysctls or firewall rules on the host and will not delete the bridge once all containers left. Fixes containers#1090 Signed-off-by: Michael Zimmermann <[email protected]>
That's simplfy not neccessary, because the whole point of internal networks is to not have any forwardings or firewall rules. Signed-off-by: Michael Zimmermann <[email protected]>
thanks, fixed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Luap99, M1cha The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@mheon PTAL |
/lgtm |
While Linux doesn't support modes on bridges, we use this concept to let the user tell us if they want podman/netavark to own the bridge or not. L3 behaves the same way as before this commit. L2 requires the bridge to exist already, will not setup any sysctls or firewall rules on the host and will not delete the bridge once all containers left.
Fixes #1090
Related: containers/common#2247