Skip to content

Commit

Permalink
Merge pull request moby#48271 from robmry/v6only/add_option_enable_ipv4
Browse files Browse the repository at this point in the history
IPv6 only: add API option enable/disable IPv4
  • Loading branch information
robmry authored Jul 31, 2024
2 parents 376a699 + 1f542d5 commit a43ed47
Show file tree
Hide file tree
Showing 14 changed files with 110 additions and 11 deletions.
2 changes: 1 addition & 1 deletion api/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api"
// Common constants for daemon and client.
const (
// DefaultVersion of the current REST API.
DefaultVersion = "1.46"
DefaultVersion = "1.47"

// MinSupportedAPIVersion is the minimum API version that can be supported
// by the API server, specified as "major.minor". Note that the daemon
Expand Down
7 changes: 7 additions & 0 deletions api/server/router/network/network_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,13 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
return libnetwork.NetworkNameError(create.Name)
}

version := httputils.VersionFromContext(ctx)

// EnableIPv4 was introduced in API 1.47.
if versions.LessThan(version, "1.47") {
create.EnableIPv4 = nil
}

// For a Swarm-scoped network, this call to backend.CreateNetwork is used to
// validate the configuration. The network will not be created but, if the
// configuration is valid, ManagerRedirectError will be returned and handled
Expand Down
22 changes: 18 additions & 4 deletions api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ produces:
consumes:
- "application/json"
- "text/plain"
basePath: "/v1.46"
basePath: "/v1.47"
info:
title: "Docker Engine API"
version: "1.46"
version: "1.47"
x-logo:
url: "https://docs.docker.com/assets/images/logo-docker-main.png"
description: |
Expand Down Expand Up @@ -55,8 +55,8 @@ info:
the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
is returned.
If you omit the version-prefix, the current version of the API (v1.46) is used.
For example, calling `/info` is the same as calling `/v1.46/info`. Using the
If you omit the version-prefix, the current version of the API (v1.47) is used.
For example, calling `/info` is the same as calling `/v1.47/info`. Using the
API without a version-prefix is deprecated and will be removed in a future release.
Engine releases in the near future should support this version of the API,
Expand Down Expand Up @@ -2484,6 +2484,11 @@ definitions:
`overlay`).
type: "string"
example: "overlay"
EnableIPv4:
description: |
Whether the network was created with IPv4 enabled.
type: "boolean"
example: true
EnableIPv6:
description: |
Whether the network was created with IPv6 enabled.
Expand Down Expand Up @@ -10377,6 +10382,7 @@ paths:
Created: "2016-10-19T06:21:00.416543526Z"
Scope: "local"
Driver: "bridge"
EnableIPv4: true
EnableIPv6: false
Internal: false
Attachable: false
Expand All @@ -10398,6 +10404,7 @@ paths:
Created: "0001-01-01T00:00:00Z"
Scope: "local"
Driver: "null"
EnableIPv4: false
EnableIPv6: false
Internal: false
Attachable: false
Expand All @@ -10412,6 +10419,7 @@ paths:
Created: "0001-01-01T00:00:00Z"
Scope: "local"
Driver: "host"
EnableIPv4: false
EnableIPv6: false
Internal: false
Attachable: false
Expand Down Expand Up @@ -10597,6 +10605,12 @@ paths:
IPAM:
description: "Optional custom IP scheme for the network."
$ref: "#/definitions/IPAM"
EnableIPv4:
description: |
Enable IPv4 on the network.
To disable IPv4, the daemon must be started with experimental features enabled.
type: "boolean"
example: true
EnableIPv6:
description: "Enable IPv6 on the network."
type: "boolean"
Expand Down
4 changes: 3 additions & 1 deletion api/types/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type CreateRequest struct {
type CreateOptions struct {
Driver string // Driver is the driver-name used to create the network (e.g. `bridge`, `overlay`)
Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level).
EnableIPv4 *bool `json:",omitempty"` // EnableIPv4 represents whether to enable IPv4.
EnableIPv6 *bool `json:",omitempty"` // EnableIPv6 represents whether to enable IPv6.
IPAM *IPAM // IPAM is the network's IP Address Management.
Internal bool // Internal represents if the network is used internal only.
Expand Down Expand Up @@ -76,7 +77,8 @@ type Inspect struct {
Created time.Time // Created is the time the network created
Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level)
Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`)
EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6
EnableIPv4 bool // EnableIPv4 represents whether IPv4 is enabled
EnableIPv6 bool // EnableIPv6 represents whether IPv6 is enabled
IPAM IPAM // IPAM is the network's IP Address Management
Internal bool // Internal represents if the network is used internal only
Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode.
Expand Down
2 changes: 2 additions & 0 deletions daemon/cluster/executor/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -626,13 +626,15 @@ func (c *containerConfig) networkCreateRequest(name string) (clustertypes.Networ
return clustertypes.NetworkCreateRequest{}, errors.New("container: unknown network referenced")
}

ipv4Enabled := true
ipv6Enabled := na.Network.Spec.Ipv6Enabled
options := network.CreateOptions{
// ID: na.Network.ID,
Labels: na.Network.Spec.Annotations.Labels,
Internal: na.Network.Spec.Internal,
Attachable: na.Network.Spec.Attachable,
Ingress: convert.IsIngressNetwork(na.Network),
EnableIPv4: &ipv4Enabled,
EnableIPv6: &ipv6Enabled,
Scope: scope.Swarm,
}
Expand Down
1 change: 1 addition & 0 deletions daemon/daemon_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,7 @@ func initBridgeDriver(controller *libnetwork.Controller, cfg config.BridgeConfig
}
// Initialize default network on "bridge" with the same name
_, err = controller.NewNetwork("bridge", network.NetworkBridge, "",
libnetwork.NetworkOptionEnableIPv4(true),
libnetwork.NetworkOptionEnableIPv6(cfg.EnableIPv6),
libnetwork.NetworkOptionDriverOpts(netOption),
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
Expand Down
2 changes: 2 additions & 0 deletions daemon/daemon_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ func (daemon *Daemon) initNetworkController(daemonCfg *config.Config, activeSand
_, err := daemon.netController.NewNetwork(strings.ToLower(v.Type), name, nid,
libnetwork.NetworkOptionGeneric(options.Generic{
netlabel.GenericData: netOption,
netlabel.EnableIPv4: true,
}),
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
)
Expand Down Expand Up @@ -430,6 +431,7 @@ func initBridgeDriver(controller *libnetwork.Controller, config config.BridgeCon
_, err := controller.NewNetwork(network.DefaultNetwork, network.DefaultNetwork, "",
libnetwork.NetworkOptionGeneric(options.Generic{
netlabel.GenericData: netOption,
netlabel.EnableIPv4: true,
}),
ipamOption,
)
Expand Down
22 changes: 19 additions & 3 deletions daemon/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,18 +316,33 @@ func (daemon *Daemon) createNetwork(cfg *config.Config, create networktypes.Crea
}
}

enableIPv4 := create.ConfigFrom == nil
if create.EnableIPv4 != nil {
enableIPv4 = *create.EnableIPv4
} else if v, ok := networkOptions[netlabel.EnableIPv4]; ok {
var err error
if enableIPv4, err = strconv.ParseBool(v); err != nil {
return nil, errdefs.InvalidParameter(fmt.Errorf("driver-opt %q is not a valid bool", netlabel.EnableIPv4))
}
}
if !enableIPv4 && !daemon.config().Experimental && create.ConfigFrom == nil {
return nil, errdefs.InvalidParameter(
errors.New("IPv4 can only be disabled if experimental features are enabled"),
)
}

var enableIPv6 bool
if create.EnableIPv6 != nil {
enableIPv6 = *create.EnableIPv6
} else {
} else if v, ok := networkOptions[netlabel.EnableIPv6]; ok {
var err error
v, ok := networkOptions[netlabel.EnableIPv6]
if enableIPv6, err = strconv.ParseBool(v); ok && err != nil {
if enableIPv6, err = strconv.ParseBool(v); err != nil {
return nil, errdefs.InvalidParameter(fmt.Errorf("driver-opt %q is not a valid bool", netlabel.EnableIPv6))
}
}

nwOptions := []libnetwork.NetworkOption{
libnetwork.NetworkOptionEnableIPv4(enableIPv4),
libnetwork.NetworkOptionEnableIPv6(enableIPv6),
libnetwork.NetworkOptionDriverOpts(networkOptions),
libnetwork.NetworkOptionLabels(create.Labels),
Expand Down Expand Up @@ -620,6 +635,7 @@ func buildNetworkResource(nw *libnetwork.Network) networktypes.Inspect {
Created: nw.Created(),
Scope: nw.Scope(),
Driver: nw.Type(),
EnableIPv4: nw.IPv4Enabled(),
EnableIPv6: nw.IPv6Enabled(),
IPAM: buildIPAMResources(nw),
Internal: nw.Internal(),
Expand Down
11 changes: 11 additions & 0 deletions docs/api/version-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ keywords: "API, Docker, rcli, REST, documentation"
will be rejected.
-->

## v1.47 API changes

[Docker Engine API v1.47](https://docs.docker.com/engine/api/v1.47/) documentation

* `Sysctls` in `HostConfig` (top level `--sysctl` settings) for `eth0` are no
longer migrated to `DriverOpts`, as described in the changes for v1.46.
* `POST /networks/create` now has an `EnableIPv4` field. Setting it to `false`
disables IPv4 IPAM for the network. It can only be set to `false` if the
daemon has experimental features enabled.
* `GET /networks/{id}` now returns an `EnableIPv4` field showing whether the
network has IPv4 IPAM enabled.

## v1.46 API changes

Expand Down
8 changes: 8 additions & 0 deletions integration/internal/network/ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ func WithDriver(driver string) func(*network.CreateOptions) {
}
}

// WithIPv4 enables/disables IPv4 on the network
func WithIPv4(enable bool) func(*network.CreateOptions) {
return func(n *network.CreateOptions) {
enableIPv4 := enable
n.EnableIPv4 = &enableIPv4
}
}

// WithIPv6 Enables IPv6 on the network
func WithIPv6() func(*network.CreateOptions) {
return func(n *network.CreateOptions) {
Expand Down
1 change: 1 addition & 0 deletions libnetwork/default_gateway_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func (c *Controller) createGWNetwork() (*Network, error) {
bridge.EnableICC: strconv.FormatBool(false),
bridge.EnableIPMasquerade: strconv.FormatBool(true),
}),
NetworkOptionEnableIPv4(true),
NetworkOptionEnableIPv6(false),
)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion libnetwork/libnetwork_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestNetworkMarshalling(t *testing.T) {
ipamType: "default",
addrSpace: "viola",
networkType: "bridge",
enableIPv4: true,
enableIPv6: true,
persist: true,
configOnly: true,
Expand Down Expand Up @@ -138,7 +139,7 @@ func TestNetworkMarshalling(t *testing.T) {
}

if n.name != nn.name || n.id != nn.id || n.networkType != nn.networkType || n.ipamType != nn.ipamType ||
n.addrSpace != nn.addrSpace || n.enableIPv6 != nn.enableIPv6 ||
n.addrSpace != nn.addrSpace || n.enableIPv4 != nn.enableIPv4 || n.enableIPv6 != nn.enableIPv6 ||
n.persist != nn.persist || !compareIpamConfList(n.ipamV4Config, nn.ipamV4Config) ||
!compareIpamInfoList(n.ipamV4Info, nn.ipamV4Info) || !compareIpamConfList(n.ipamV6Config, nn.ipamV6Config) ||
!compareIpamInfoList(n.ipamV6Info, nn.ipamV6Info) ||
Expand Down
3 changes: 3 additions & 0 deletions libnetwork/netlabel/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const (
// where the interface name is represented by the string "IFNAME".
EndpointSysctls = Prefix + ".endpoint.sysctls"

// EnableIPv4 constant represents enabling IPV4 at network level
EnableIPv4 = Prefix + ".enable_ipv4"

// EnableIPv6 constant represents enabling IPV6 at network level
EnableIPv6 = Prefix + ".enable_ipv6"

Expand Down
33 changes: 32 additions & 1 deletion libnetwork/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ type Network struct {
ipamV6Config []*IpamConf
ipamV4Info []*IpamInfo
ipamV6Info []*IpamInfo
enableIPv4 bool
enableIPv6 bool
postIPv6 bool
epCnt *endpointCnt
Expand Down Expand Up @@ -368,7 +369,7 @@ func (n *Network) validateConfiguration() error {
}
if n.ipamType != "" &&
n.ipamType != defaultIpamForNetworkType(n.networkType) ||
n.enableIPv6 ||
n.enableIPv4 || n.enableIPv6 ||
len(n.labels) > 0 || len(n.ipamOptions) > 0 ||
len(n.ipamV4Config) > 0 || len(n.ipamV6Config) > 0 {
return types.ForbiddenErrorf("user specified configurations are not supported if the network depends on a configuration network")
Expand Down Expand Up @@ -401,6 +402,7 @@ func (n *Network) validateConfiguration() error {

// applyConfigurationTo applies network specific configurations.
func (n *Network) applyConfigurationTo(to *Network) error {
to.enableIPv4 = n.enableIPv4
to.enableIPv6 = n.enableIPv6
if len(n.labels) > 0 {
to.labels = make(map[string]string, len(n.labels))
Expand Down Expand Up @@ -450,6 +452,7 @@ func (n *Network) CopyTo(o datastore.KVObject) error {
dstN.scope = n.scope
dstN.dynamic = n.dynamic
dstN.ipamType = n.ipamType
dstN.enableIPv4 = n.enableIPv4
dstN.enableIPv6 = n.enableIPv6
dstN.persist = n.persist
dstN.postIPv6 = n.postIPv6
Expand Down Expand Up @@ -539,6 +542,7 @@ func (n *Network) MarshalJSON() ([]byte, error) {
netMap["ipamType"] = n.ipamType
netMap["ipamOptions"] = n.ipamOptions
netMap["addrSpace"] = n.addrSpace
netMap["enableIPv4"] = n.enableIPv4
netMap["enableIPv6"] = n.enableIPv6
if n.generic != nil {
netMap["generic"] = n.generic
Expand Down Expand Up @@ -601,6 +605,12 @@ func (n *Network) UnmarshalJSON(b []byte) (err error) {
}
}
n.networkType = netMap["networkType"].(string)
if v, ok := netMap["enableIPv4"]; ok {
n.enableIPv4 = v.(bool)
} else {
// Set enableIPv4 for IPv4 networks created before the option was added.
n.enableIPv4 = len(n.ipamV4Info) > 0
}
n.enableIPv6 = netMap["enableIPv6"].(bool)

// if we weren't unmarshaling to netMap we could simply set n.labels
Expand Down Expand Up @@ -713,6 +723,9 @@ func NetworkOptionGeneric(generic map[string]interface{}) NetworkOption {
if n.generic == nil {
n.generic = make(map[string]interface{})
}
if val, ok := generic[netlabel.EnableIPv4]; ok {
n.enableIPv4 = val.(bool)
}
if val, ok := generic[netlabel.EnableIPv6]; ok {
n.enableIPv6 = val.(bool)
}
Expand Down Expand Up @@ -740,6 +753,17 @@ func NetworkOptionPersist(persist bool) NetworkOption {
}
}

// NetworkOptionEnableIPv4 returns an option setter to explicitly configure IPv4
func NetworkOptionEnableIPv4(enableIPv4 bool) NetworkOption {
return func(n *Network) {
if n.generic == nil {
n.generic = make(map[string]interface{})
}
n.enableIPv4 = enableIPv4
n.generic[netlabel.EnableIPv4] = enableIPv4
}
}

// NetworkOptionEnableIPv6 returns an option setter to explicitly configure IPv6
func NetworkOptionEnableIPv6(enableIPv6 bool) NetworkOption {
return func(n *Network) {
Expand Down Expand Up @@ -1842,6 +1866,13 @@ func (n *Network) Dynamic() bool {
return n.dynamic
}

func (n *Network) IPv4Enabled() bool {
n.mu.Lock()
defer n.mu.Unlock()

return n.enableIPv4
}

func (n *Network) IPv6Enabled() bool {
n.mu.Lock()
defer n.mu.Unlock()
Expand Down

0 comments on commit a43ed47

Please sign in to comment.