Skip to content

Commit 1c4efb6

Browse files
committed
Allow user to specify container's link-local addresses
Signed-off-by: Alessandro Boch <aboch@docker.com>
1 parent c913dd5 commit 1c4efb6

File tree

11 files changed

+107
-30
lines changed

11 files changed

+107
-30
lines changed

api/client/network/connect.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ import (
1212
)
1313

1414
type connectOptions struct {
15-
network string
16-
container string
17-
ipaddress string
18-
ipv6address string
19-
links opts.ListOpts
20-
aliases []string
15+
network string
16+
container string
17+
ipaddress string
18+
ipv6address string
19+
links opts.ListOpts
20+
aliases []string
21+
linklocalips []string
2122
}
2223

2324
func newConnectCommand(dockerCli *client.DockerCli) *cobra.Command {
@@ -41,6 +42,7 @@ func newConnectCommand(dockerCli *client.DockerCli) *cobra.Command {
4142
flags.StringVar(&opts.ipv6address, "ip6", "", "IPv6 Address")
4243
flags.Var(&opts.links, "link", "Add link to another container")
4344
flags.StringSliceVar(&opts.aliases, "alias", []string{}, "Add network-scoped alias for the container")
45+
flags.StringSliceVar(&opts.linklocalips, "link-local-ip", []string{}, "Add a link-local address for the container")
4446

4547
return cmd
4648
}
@@ -50,8 +52,9 @@ func runConnect(dockerCli *client.DockerCli, opts connectOptions) error {
5052

5153
epConfig := &network.EndpointSettings{
5254
IPAMConfig: &network.EndpointIPAMConfig{
53-
IPv4Address: opts.ipaddress,
54-
IPv6Address: opts.ipv6address,
55+
IPv4Address: opts.ipaddress,
56+
IPv6Address: opts.ipv6address,
57+
LinkLocalIPs: opts.linklocalips,
5558
},
5659
Links: opts.links.GetAll(),
5760
Aliases: opts.aliases,

container/container.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,9 +789,15 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC
789789

790790
if epConfig != nil {
791791
ipam := epConfig.IPAMConfig
792-
if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") {
792+
if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "" || len(ipam.LinkLocalIPs) > 0) {
793+
var ipList []net.IP
794+
for _, ips := range ipam.LinkLocalIPs {
795+
if ip := net.ParseIP(ips); ip != nil {
796+
ipList = append(ipList, ip)
797+
}
798+
}
793799
createOptions = append(createOptions,
794-
libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil, nil))
800+
libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), ipList, nil))
795801
}
796802

797803
for _, alias := range epConfig.Aliases {

docs/reference/api/docker_remote_api_v1.24.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ Create a container
339339
"isolated_nw" : {
340340
"IPAMConfig": {
341341
"IPv4Address":"172.20.30.33",
342-
"IPv6Address":"2001:db8:abcd::3033"
342+
"IPv6Address":"2001:db8:abcd::3033",
343+
"LinkLocalIPs:["169.254.34.68", "fe80::3468"]
343344
},
344345
"Links":["container_1", "container_2"],
345346
"Aliases":["server_x", "server_y"]

docs/reference/commandline/create.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Creates a new container.
5454
-l, --label=[] Set metadata on the container (e.g., --label=com.example.key=value)
5555
--label-file=[] Read in a line delimited file of labels
5656
--link=[] Add link to another container
57+
--link-local-ip=[] Container IPv4/IPv6 link-local addresses (e.g. 169.254.0.77, fe80::77)
5758
--log-driver="" Logging driver for container
5859
--log-opt=[] Log driver specific options
5960
-m, --memory="" Memory limit

docs/reference/commandline/network_connect.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ parent = "smn_cli"
1919
--ip IPv4 Address
2020
--ip6 IPv6 Address
2121
--link=[] Add a link to another container
22+
--link-local-ip=[] IPv4/IPv6 link-local addresses
2223

2324
Connects a container to a network. You can connect a container by name
2425
or by ID. Once connected, the container can communicate with other containers in

docs/reference/commandline/run.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ parent = "smn_cli"
5555
-l, --label=[] Set metadata on the container (e.g., --label=com.example.key=value)
5656
--label-file=[] Read in a file of labels (EOL delimited)
5757
--link=[] Add link to another container
58+
--link-local-ip=[] Container IPv4/IPv6 link-local addresses (e.g. 169.254.0.77, fe80::77)
5859
--log-driver="" Logging driver for container
5960
--log-opt=[] Log driver specific options
6061
-m, --memory="" Memory limit

docs/reference/run.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -288,18 +288,19 @@ of the containers.
288288

289289
## Network settings
290290

291-
--dns=[] : Set custom dns servers for the container
292-
--net="bridge" : Connect a container to a network
293-
'bridge': create a network stack on the default Docker bridge
294-
'none': no networking
295-
'container:<name|id>': reuse another container's network stack
296-
'host': use the Docker host network stack
297-
'<network-name>|<network-id>': connect to a user-defined network
298-
--net-alias=[] : Add network-scoped alias for the container
299-
--add-host="" : Add a line to /etc/hosts (host:IP)
300-
--mac-address="" : Sets the container's Ethernet device's MAC address
301-
--ip="" : Sets the container's Ethernet device's IPv4 address
302-
--ip6="" : Sets the container's Ethernet device's IPv6 address
291+
--dns=[] : Set custom dns servers for the container
292+
--net="bridge" : Connect a container to a network
293+
'bridge': create a network stack on the default Docker bridge
294+
'none': no networking
295+
'container:<name|id>': reuse another container's network stack
296+
'host': use the Docker host network stack
297+
'<network-name>|<network-id>': connect to a user-defined network
298+
--net-alias=[] : Add network-scoped alias for the container
299+
--add-host="" : Add a line to /etc/hosts (host:IP)
300+
--mac-address="" : Sets the container's Ethernet device's MAC address
301+
--ip="" : Sets the container's Ethernet device's IPv4 address
302+
--ip6="" : Sets the container's Ethernet device's IPv6 address
303+
--link-local-ip=[] : Sets one or more container's Ethernet device's link local IPv4/IPv6 addresses
303304

304305
By default, all containers have networking enabled and they can make any
305306
outgoing connections. The operator can completely disable networking

integration-cli/docker_cli_network_unix_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,53 @@ func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) {
13361336
c.Assert(strings.TrimSpace(out), check.Equals, ipv6)
13371337
}
13381338

1339+
func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *check.C) {
1340+
// create one test network
1341+
dockerCmd(c, "network", "create", "n0")
1342+
assertNwIsAvailable(c, "n0")
1343+
1344+
// run a container with incorrect link-local address
1345+
_, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "top")
1346+
c.Assert(err, check.NotNil)
1347+
_, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "top")
1348+
c.Assert(err, check.NotNil)
1349+
1350+
// run two containers with link-local ip on the test network
1351+
dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top")
1352+
c.Assert(waitRun("c0"), check.IsNil)
1353+
dockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top")
1354+
c.Assert(waitRun("c1"), check.IsNil)
1355+
1356+
// run a container on the default network and connect it to the test network specifying a link-local address
1357+
dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
1358+
c.Assert(waitRun("c2"), check.IsNil)
1359+
dockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2")
1360+
1361+
// verify the three containers can ping each other via the link-local addresses
1362+
_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
1363+
c.Assert(err, check.IsNil)
1364+
_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
1365+
c.Assert(err, check.IsNil)
1366+
_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
1367+
c.Assert(err, check.IsNil)
1368+
1369+
// Stop and restart the three containers
1370+
dockerCmd(c, "stop", "c0")
1371+
dockerCmd(c, "stop", "c1")
1372+
dockerCmd(c, "stop", "c2")
1373+
dockerCmd(c, "start", "c0")
1374+
dockerCmd(c, "start", "c1")
1375+
dockerCmd(c, "start", "c2")
1376+
1377+
// verify the ping again
1378+
_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
1379+
c.Assert(err, check.IsNil)
1380+
_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
1381+
c.Assert(err, check.IsNil)
1382+
_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
1383+
c.Assert(err, check.IsNil)
1384+
}
1385+
13391386
func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) {
13401387
testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
13411388
dockerCmd(c, "network", "create", "-d", "bridge", "foo1")

man/docker-create.1.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ docker-create - Create a new container
4343
[**-l**|**--label**[=*[]*]]
4444
[**--label-file**[=*[]*]]
4545
[**--link**[=*[]*]]
46+
[**--link-local-ip**[=*[]*]]
4647
[**--log-driver**[=*[]*]]
4748
[**--log-opt**[=*[]*]]
4849
[**-m**|**--memory**[=*MEMORY*]]
@@ -220,6 +221,9 @@ millions of trillions.
220221
Add link to another container in the form of <name or id>:alias or just
221222
<name or id> in which case the alias will match the name.
222223

224+
**--link-local-ip**=[]
225+
Add one or more link-local IPv4/IPv6 addresses to the container's interface
226+
223227
**--log-driver**="*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*awslogs*|*splunk*|*etwlogs*|*gcplogs*|*none*"
224228
Logging driver for container. Default is defined by daemon `--log-driver` flag.
225229
**Warning**: the `docker logs` command works only for the `json-file` and

man/docker-run.1.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ docker-run - Run a command in a new container
4545
[**-l**|**--label**[=*[]*]]
4646
[**--label-file**[=*[]*]]
4747
[**--link**[=*[]*]]
48+
[**--link-local-ip**[=*[]*]]
4849
[**--log-driver**[=*[]*]]
4950
[**--log-opt**[=*[]*]]
5051
[**-m**|**--memory**[=*MEMORY*]]
@@ -326,6 +327,9 @@ container can access the exposed port via a private networking interface. Docker
326327
will set some environment variables in the client container to help indicate
327328
which interface and port to use.
328329

330+
**--link-local-ip**=[]
331+
Add one or more link-local IPv4/IPv6 addresses to the container's interface
332+
329333
**--log-driver**="*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*awslogs*|*splunk*|*etwlogs*|*gcplogs*|*none*"
330334
Logging driver for container. Default is defined by daemon `--log-driver` flag.
331335
**Warning**: the `docker logs` command works only for the `json-file` and

0 commit comments

Comments
 (0)