Skip to content
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

Add a network option to disable default gateway #778

Merged
merged 1 commit into from
Dec 3, 2015
Merged

Add a network option to disable default gateway #778

merged 1 commit into from
Dec 3, 2015

Conversation

chenchun
Copy link
Contributor

Signed-off-by: Chun Chen ramichen@tencent.com

Fixes #759 #775

@@ -521,6 +527,13 @@ func NetworkOptionDeferIPv6Alloc(enable bool) NetworkOption {
}
}

// NetworkOptionDefaultGW returns an option setter to set if a network needs default gateway
func NetworkOptionDefaultGW(defaultGW bool) NetworkOption {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we call it something like NetworkOptionIsolatedNetwork

As a network property, we do not need to talk about default gw network, that is an implementation detail.
I think I read it somewhere people asking for this feature to refer to it as isolated network.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think I may have mentioned it a few times at DockerCon EU 😀
And +1 on calling it "Isolated"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, updated

@chenchun
Copy link
Contributor Author

@sanimej @aboch updated

@@ -347,6 +347,7 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
ctrlr: c,
persist: true,
drvOnce: &sync.Once{},
isolated: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

Default behavior is that the network has or will be provided outside connectivity.
This line can be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the mistake.

@aboch
Copy link
Contributor

aboch commented Nov 26, 2015

@chenchun I think the PR needs more code changes.

If we now allow UI to specify a network to be isolated, I am assuming drivers which naturally provide external connectivity (like bridge) need more changes to block the external connectivity if flag is set, or to reject the network creation if they cannot guarantee no external connectivity

@chenchun
Copy link
Contributor Author

@aboch Should we add an SupportIsolation() bool func to Driver interface or simply do it as my latest update?

@@ -35,6 +35,17 @@ func (ind ErrInvalidNetworkDriver) Error() string {
// BadRequest denotes the type of this error
func (ind ErrInvalidNetworkDriver) BadRequest() {}

// ErrNetworkNotSupportIsolation is returned if attempts to create an isolated
// network, but the driver of that cannot guarantee no external connectivity.
type ErrNetworkNotSupportIsolation string
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's not define new errors.
Please see #269

@chenchun
Copy link
Contributor Author

Then there is a requirement for not adding the default gw network along to remote driver network
Covering the second requirement via isolated network may not be the cleanest way.

How about adding an Isolation bool to driverapi.Capability? This way, remote/bridge drivers can declare that they don't support isolation at registration time. And we can throw ErrNotImplemented if attempts to create a isolated network for those drivers in NewNetwork. And NetworkOptionIsolatedNetwork continues to be useful for overlay drivers. No driver code needs to be changed any more.

@sanimej
Copy link

sanimej commented Nov 27, 2015

@chenchun @aboch The change being discussed in this PR is required if someone wants to isolate the containers on a overlay network because overlay driver by default doesn't set the ep's Gateway thus triggering libnetwork to provide an endpoint in the default gateway network. But I am not sure if this the right fix for #775. I left a comment for @jc-m to try setting the Gateway in the JoinResponse

@aboch
Copy link
Contributor

aboch commented Nov 27, 2015

@sanimej My understanding from #775 example is that remote driver may not want to use the default gateway, if it is applying static routes instead.

@aboch
Copy link
Contributor

aboch commented Nov 27, 2015

@chenchun, @sanimej

I can see the current libnetwork default behavior/expectation: By default any libnetwork network provides its containers with external connectivity. Either natively (ex. bridge network), or with the help of libnetwork default gw network (for ex. overlay network).

NetworkOptionIsolatedNetwork is a per network option, not a driver option.
For ex., User may want to create one isolated bridge network and one non-isolated (regular) bridge network.

As of now, libnetwork infer whether or not to connect the container to the default gw network from whether the network driver set or does not set the default gateway in the Join JoinInfo interface.
But this is not completely correct as a remote driver might use different means like static routes to provide external connectivity to containers.

Libnetwork could be changed to also check for static route set in JoinInfo when deciding whether to plug the container to the default gw network.

But I don't know if that is enough for any sort of remote drivers.

If not, then we may need the network driver to tell libnetwork if it needs libnetwork's support to provide external connectivity to the containers on its networks.

If the requireExternalConnectivitySupport capability is not set, libnetwork will not bother to connect the container to the default gw network if no default gw (or static route) was set in the JoinInfo interface.

@dave-tucker
Copy link
Contributor

@aboch @sanimej

Consider this...

A plugin that is doing VLAN only (plain linux bridge) and uses a noop IPAM driver.
IP addresses are to be assigned automatically via DHCP running inside the container.
This feels to me like a valid use case.

So IMO, we need both:

  1. A way for a user to specify, "don't allow this network access to the internet"
    This property should also be sent to the driver so it also knows how to handle this
    i.e this PR

  2. A way for a driver to specify, "hey libnetwork, this is a special type of network that doesn't need a default gateway.. so i'm not providing one"

@jc-m
Copy link

jc-m commented Nov 28, 2015

In addition to point 2, I would argue that all networking setup should be delegated to the remote driver, and perhaps provide it with enough information to completely setup the network connectivity. This in my mind is the most flexible way and should enable most use cases. Is there a specific use case to have this partial delegation without full control ?

@chenchun
Copy link
Contributor Author

Updated PR to add ExternalConnectivity capability

@jc-m
Copy link

jc-m commented Nov 30, 2015

I am not sure that have a flag name ExternalConnectivity reflects what is being done. Why not simply name it "NeedGateway" ? I'm sure that external connectivity would require more than just a default gateway.

@@ -97,11 +97,14 @@ func (sb *sandbox) needDefaultGW() bool {
var needGW bool

for _, ep := range sb.getConnectedEndpoints() {
if !ep.getNetwork().ctrlr.drivers[ep.getNetwork().Type()].capability.ExternalConnectivity {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use
ep.getNetwork().driver().capability.ExternalConnectivity instead

@aboch
Copy link
Contributor

aboch commented Nov 30, 2015

@jc-m Sure we can think of better names for the flag.
I am actually thinking it should not be a flag, rather a string with some const values (a C enum), so that in future the same field can convey more modes. Like it is done today for the DataScope capability.

@aboch
Copy link
Contributor

aboch commented Nov 30, 2015

@chenchun
Discussed offline with @mrjana and @sanimej, we agreed on:

  1. Split this in two PRs: one for the isolated network option (this is an enhancement, lower priority) and one to fix Proposal: Add an option to disable default gateway added by libnetwork #759 needDefaultGW should not return true for remote drivers #775.

  2. In the second PR, we need to fix 2 things:

a) Libnetwork fix for (#775): Libnetwork should not connect the container to the default gw network when the network driver has added the default static route (0.0.0.0/0) in the JoinInfo

b) Network driver does not want default gateway network for its container (#759): Libnetwork will not connect the container to the default gw network when the network driver sets 0.0.0.0 as default gateway in the JoinInfo

2.b) is preferable to the driver capability option because fits in the current protocol and allows a per-container granularity option.

@jc-m
Copy link

jc-m commented Nov 30, 2015

With regard to the capability to have a per container choice, I agree this is a good call. However, it seems that deriving the intent from returned values is likely less optimal. Why not have options for network drivers like there is for storage drivers and have this be an option (label) passed to the driver at run time ? It would give more flexibility to the user and the driver without having side effect being implemented by the daemon.
This would also help solve other issues like passing IP addresses (see moby/moby#6743)

@aboch
Copy link
Contributor

aboch commented Nov 30, 2015

@jc-m

This behavior cannot be left to driver specific options. There is a protocol the network driver has to adhere to during container Join. Libnetwork defines and control this protocol in order to provide the same user experience regardless of the network driver in use.

Per container IP allocation is a first class configuration that will be provided via IPAM configuration during endpoint creation (See #707).

@jc-m
Copy link

jc-m commented Dec 1, 2015

@aboch I don't understand how this is breaking the protocol. Are you saying that you cannot have per driver options ? I did not see anywhere the specification/documentation that libnetwork will create a default route or a an interface and route on bridged network in addition to what is specified in the response. Can you point out where this is documented as I don't see it here.

In addition, leaving the ip allocation to the IPAM driver is fine, but there is no way using the IPAM driver to accept or deny an IP address requested by at container creation time. IP allocation is not always dynamic, and not always initiated by a host at the time of instantiation, but maybe implemented by a scheduler requesting the launch of a container allocating the address based on global state.

@jc-m
Copy link

jc-m commented Dec 1, 2015

@aboch with regard to the IP allocation, your text confused me and I'll have to look a bit more closely at #707. It's not clear to me yet how it will be provided to libnetwork.

@chenchun
Copy link
Contributor Author

chenchun commented Dec 1, 2015

b) Network driver does not want default gateway network for its container (#759): Libnetwork will not connect the container to the default gw network when the network driver sets 0.0.0.0 as default gateway in the JoinInfo

2.b) is preferable to the driver capability option because fits in the current protocol and allows a per-container granularity option.

@aboch I'm confused. Currently needDefaultGW func already did this by

if len(ep.Gateway()) > 0 {
    return false
}

And how can it be a per-container granularity option? How did drivers know which container needs to set 0.0.0.0 gateway? Does it indicates that docker network connect need to support the gateway flag?

@sanimej
Copy link

sanimej commented Dec 1, 2015

@chenchun

And how can it be a per-container granularity option? How did drivers know which container needs to set 0.0.0.0 gateway? Does it indicates that docker network connect need to support the gateway flag?

Yes, the driver can't set a valid gateway for some containers and set 0.0.0.0 for some other containers on a given network. But during the network create one can pass an option using -opt to tell the driver if Default GW should be provided by libnetwork for containers on that network. So using on the Join response gives the driver granularity at a per network level than the capability exchange, which is fixed.

@sanimej
Copy link

sanimej commented Dec 1, 2015

@jc-m

With regard to the capability to have a per container choice, I agree this is a good call. However, it seems that deriving the intent from returned values is likely less optimal. Why not have options for network drivers like there is for storage drivers and have this be an option (label) passed to the driver at run time ? It would give more flexibility to the user and the driver without having side effect being implemented by the daemon.

Network create has the provision to pass driver specific options using -opt. But its not interpreted or used by libnetwork all. That is why the protocol between libnetwork and driver has to be used to decide when libnetwork should provide Default GW for the container. Please see my previous reply to @chenchun on this.

Instead of using the Gateway IP 0.0.0.0 in the Join response we can add a new boolean (something like NeedDefaultGW) if that makes the interaction more explicit/clear.

@chenchun
Copy link
Contributor Author

chenchun commented Dec 1, 2015

Instead of using the Gateway IP 0.0.0.0 in the Join response we can add a new boolean (something like NeedDefaultGW) if that makes the interaction more explicit/clear

I agree with this. setting gateway ip as 0.0.0.0 is very confusing. Actually, I googled it and it means _that the network is locally connected on that interface and no more hops are needed to get to it_. http://unix.stackexchange.com/questions/94018/what-is-the-meaning-of-0-0-0-0-as-a-gateway

@sanimej
Copy link

sanimej commented Dec 1, 2015

The suggestion was to use 0.0.0.0 in the Joininfo only as an indication to libnetwork that the driver isn't providing a valid Gateway IP and libnetwork has to provide the Default gw.

I think its probably better to add a new boolean. @aboch WDYT ?

@mavenugo
Copy link
Contributor

mavenugo commented Dec 2, 2015

@aboch @chenchun @jc-m @sanimej I agree that having an explicit flag makes it cleaner and easier for drivers to make a more explicit request. But, the flag must be backward compatible to make sure any existing drivers (that may not even use this flag) should work unaffected. Hence, the flag should be named and behave something like : DisableGatewayService which will make libnetwork not to provide the Gateway Service implicitly.

Also, I agree with @aboch & @mrjana that we should pull another PR to address the case of user controlling the functionality. There are more things to consider & we dont this PR to be blocked because of unrelated issues.

@mavenugo
Copy link
Contributor

mavenugo commented Dec 2, 2015

@chenchun i just observed that you already have 2 commits for that :) just split them into 2 different PRs. Also, if you agree with my suggestion of the flag name as DisableGatewayService (and ofcourse move it from a capability to join specific flag), then you can remove the changes from bridge and overlay drivers. I would infact prefer that so that we guarantee no compatibility issues to other plugins that were written in 1.9.0 without any additional changes required.

Also, any changes to the driver api needs a doc update for the remote drivers.

@chenchun
Copy link
Contributor Author

chenchun commented Dec 3, 2015

Yes, I'll update PR shortly.

@@ -92,6 +92,8 @@ func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int,
return nil
}

func (ep *endpoint) DisableGatewayService(diableGatewayService bool) {}
Copy link
Contributor

Choose a reason for hiding this comment

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

minor spell check nit : diableGatewayService

… to disable default gateway

Signed-off-by: Chun Chen <ramichen@tencent.com>
@mavenugo
Copy link
Contributor

mavenugo commented Dec 3, 2015

Thanks @chenchun for making all the changes.

LGTM

@chenchun
Copy link
Contributor Author

chenchun commented Dec 3, 2015

Docs needs to be changed. I'll update docs after #796 getting merged.

@@ -103,6 +103,9 @@ func (sb *sandbox) needDefaultGW() bool {
if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
continue
}
if ep.joinInfo.disableGatewayService {
return false
}
Copy link

Choose a reason for hiding this comment

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

If a container has endpoints on two networks with one driver setting disableGatewayService to true and the other one setting to false (default case) what should be the behavior ? If we want to provide the default gateway service in that case it has to be a 'continue' here to loop through the other endpoints.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

disableGatewayService is more like a per sandbox property. If you enable such service during joining one of its endpoints, others will be infected. Since disableGatewayService is false by default and it becomes true if drivers explicitly setting it to true, I suggest we return false here.

Copy link
Contributor

Choose a reason for hiding this comment

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

When a driver sets disableGatewayService, i assume that the driver is capable of providing the default route for that container. Hence even if 1 endpoint suggests it can provide the default route for the sandbox, then this function must return false as it is implemented now.
Hence, the current change of returning false looks appropriate.

Copy link

Choose a reason for hiding this comment

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

When a driver sets disableGatewayService, i assume that the driver is capable of providing the default route for that container.

Not necessarily. Earlier this assumption was ok because the check was specifically for Gateway IP. Now a driver can set disableGatewayService and doesn't provide gateway IP or static default route.

I am not against this change. But want to make sure there is agreement on the behavior with this change.

@aboch
Copy link
Contributor

aboch commented Dec 3, 2015

@sanimej @chenchun
I think both of you are right.

The disable flag does not fit in the needDefaultGw() function logic: being a endpoint property, it should cause a continue.
But this is because the flag is in fact a sandbox property, like @chenchun said.
If the flag is set, we should not even get into the endpoint loop.

@chenchun @jc-m If you agree this is a sandbox property, if that was the original intent, WDYT about moving the flag to sandbox structure ? Does it make sense ?

Not as part of this PR, this one can go in as is to me. It would be an incremental change.

@aboch
Copy link
Contributor

aboch commented Dec 3, 2015

LGTM

aboch added a commit that referenced this pull request Dec 3, 2015
Add a network option to disable default gateway
@aboch aboch merged commit f942c0e into moby:master Dec 3, 2015
@chenchun chenchun deleted the disable-default-gateway branch December 4, 2015 01:32
openstack-mirroring pushed a commit to openstack/openstack that referenced this pull request Jun 26, 2020
* Update kuryr-libnetwork from branch 'master'
  - Merge "Handle subnet without gateway"
  - Handle subnet without gateway
    
    * When libnetwork requests the IP address of the gateway
      (via /IpamDriver.RequestAddress) and the neutron subnet has gateway
      as None, return '0.0.0.0/0' as a placeholder.
    * Disable default docker gateway via the 'DisableGatewayService' flag
      (see moby/libnetwork#778).
    
    Change-Id: I3033d28eb268a01de8cf038b1ed20110ca9a31ea
    Closes-Bug: #1881910
openstack-mirroring pushed a commit to openstack/kuryr-libnetwork that referenced this pull request Jun 26, 2020
* When libnetwork requests the IP address of the gateway
  (via /IpamDriver.RequestAddress) and the neutron subnet has gateway
  as None, return '0.0.0.0/0' as a placeholder.
* Disable default docker gateway via the 'DisableGatewayService' flag
  (see moby/libnetwork#778).

Change-Id: I3033d28eb268a01de8cf038b1ed20110ca9a31ea
Closes-Bug: #1881910
openstack-mirroring pushed a commit to openstack/kuryr-libnetwork that referenced this pull request Jun 29, 2020
* When libnetwork requests the IP address of the gateway
  (via /IpamDriver.RequestAddress) and the neutron subnet has gateway
  as None, return '0.0.0.0/0' as a placeholder.
* Disable default docker gateway via the 'DisableGatewayService' flag
  (see moby/libnetwork#778).

Change-Id: I3033d28eb268a01de8cf038b1ed20110ca9a31ea
Closes-Bug: #1881910
(cherry picked from commit 9609936)
openstack-mirroring pushed a commit to openstack/kuryr-libnetwork that referenced this pull request Jul 1, 2020
* When libnetwork requests the IP address of the gateway
  (via /IpamDriver.RequestAddress) and the neutron subnet has gateway
  as None, return '0.0.0.0/0' as a placeholder.
* Disable default docker gateway via the 'DisableGatewayService' flag
  (see moby/libnetwork#778).

Change-Id: I3033d28eb268a01de8cf038b1ed20110ca9a31ea
Closes-Bug: #1881910
(cherry picked from commit 9609936)
openstack-mirroring pushed a commit to openstack/kuryr-libnetwork that referenced this pull request Jul 3, 2020
* When libnetwork requests the IP address of the gateway
  (via /IpamDriver.RequestAddress) and the neutron subnet has gateway
  as None, return '0.0.0.0/0' as a placeholder.
* Disable default docker gateway via the 'DisableGatewayService' flag
  (see moby/libnetwork#778).

Change-Id: I3033d28eb268a01de8cf038b1ed20110ca9a31ea
Closes-Bug: #1881910
(cherry picked from commit 9609936)
openstack-mirroring pushed a commit to openstack/kuryr-libnetwork that referenced this pull request Jul 5, 2020
* When libnetwork requests the IP address of the gateway
  (via /IpamDriver.RequestAddress) and the neutron subnet has gateway
  as None, return '0.0.0.0/0' as a placeholder.
* Disable default docker gateway via the 'DisableGatewayService' flag
  (see moby/libnetwork#778).

Change-Id: I3033d28eb268a01de8cf038b1ed20110ca9a31ea
Closes-Bug: #1881910
(cherry picked from commit 9609936)
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.

6 participants