Signed-off-by: Alessandro Boch <aboch@docker.com>
Alessandro Boch authored on 2016/06/10 07:10:59... | ... |
@@ -12,12 +12,13 @@ import ( |
12 | 12 |
) |
13 | 13 |
|
14 | 14 |
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 |
|
21 | 22 |
} |
22 | 23 |
|
23 | 24 |
func newConnectCommand(dockerCli *client.DockerCli) *cobra.Command { |
... | ... |
@@ -41,6 +42,7 @@ func newConnectCommand(dockerCli *client.DockerCli) *cobra.Command { |
41 | 41 |
flags.StringVar(&opts.ipv6address, "ip6", "", "IPv6 Address") |
42 | 42 |
flags.Var(&opts.links, "link", "Add link to another container") |
43 | 43 |
flags.StringSliceVar(&opts.aliases, "alias", []string{}, "Add network-scoped alias for the container") |
44 |
+ flags.StringSliceVar(&opts.linklocalips, "link-local-ip", []string{}, "Add a link-local address for the container") |
|
44 | 45 |
|
45 | 46 |
return cmd |
46 | 47 |
} |
... | ... |
@@ -50,8 +52,9 @@ func runConnect(dockerCli *client.DockerCli, opts connectOptions) error { |
50 | 50 |
|
51 | 51 |
epConfig := &network.EndpointSettings{ |
52 | 52 |
IPAMConfig: &network.EndpointIPAMConfig{ |
53 |
- IPv4Address: opts.ipaddress, |
|
54 |
- IPv6Address: opts.ipv6address, |
|
53 |
+ IPv4Address: opts.ipaddress, |
|
54 |
+ IPv6Address: opts.ipv6address, |
|
55 |
+ LinkLocalIPs: opts.linklocalips, |
|
55 | 56 |
}, |
56 | 57 |
Links: opts.links.GetAll(), |
57 | 58 |
Aliases: opts.aliases, |
... | ... |
@@ -789,9 +789,15 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC |
789 | 789 |
|
790 | 790 |
if epConfig != nil { |
791 | 791 |
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 |
+ } |
|
793 | 799 |
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)) |
|
795 | 801 |
} |
796 | 802 |
|
797 | 803 |
for _, alias := range epConfig.Aliases { |
... | ... |
@@ -339,7 +339,8 @@ Create a container |
339 | 339 |
"isolated_nw" : { |
340 | 340 |
"IPAMConfig": { |
341 | 341 |
"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"] |
|
343 | 344 |
}, |
344 | 345 |
"Links":["container_1", "container_2"], |
345 | 346 |
"Aliases":["server_x", "server_y"] |
... | ... |
@@ -54,6 +54,7 @@ Creates a new container. |
54 | 54 |
-l, --label=[] Set metadata on the container (e.g., --label=com.example.key=value) |
55 | 55 |
--label-file=[] Read in a line delimited file of labels |
56 | 56 |
--link=[] Add link to another container |
57 |
+ --link-local-ip=[] Container IPv4/IPv6 link-local addresses (e.g. 169.254.0.77, fe80::77) |
|
57 | 58 |
--log-driver="" Logging driver for container |
58 | 59 |
--log-opt=[] Log driver specific options |
59 | 60 |
-m, --memory="" Memory limit |
... | ... |
@@ -19,6 +19,7 @@ parent = "smn_cli" |
19 | 19 |
--ip IPv4 Address |
20 | 20 |
--ip6 IPv6 Address |
21 | 21 |
--link=[] Add a link to another container |
22 |
+ --link-local-ip=[] IPv4/IPv6 link-local addresses |
|
22 | 23 |
|
23 | 24 |
Connects a container to a network. You can connect a container by name |
24 | 25 |
or by ID. Once connected, the container can communicate with other containers in |
... | ... |
@@ -55,6 +55,7 @@ parent = "smn_cli" |
55 | 55 |
-l, --label=[] Set metadata on the container (e.g., --label=com.example.key=value) |
56 | 56 |
--label-file=[] Read in a file of labels (EOL delimited) |
57 | 57 |
--link=[] Add link to another container |
58 |
+ --link-local-ip=[] Container IPv4/IPv6 link-local addresses (e.g. 169.254.0.77, fe80::77) |
|
58 | 59 |
--log-driver="" Logging driver for container |
59 | 60 |
--log-opt=[] Log driver specific options |
60 | 61 |
-m, --memory="" Memory limit |
... | ... |
@@ -288,18 +288,19 @@ of the containers. |
288 | 288 |
|
289 | 289 |
## Network settings |
290 | 290 |
|
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 |
|
303 | 304 |
|
304 | 305 |
By default, all containers have networking enabled and they can make any |
305 | 306 |
outgoing connections. The operator can completely disable networking |
... | ... |
@@ -1336,6 +1336,53 @@ func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) { |
1336 | 1336 |
c.Assert(strings.TrimSpace(out), check.Equals, ipv6) |
1337 | 1337 |
} |
1338 | 1338 |
|
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 |
+ |
|
1339 | 1386 |
func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) { |
1340 | 1387 |
testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm) |
1341 | 1388 |
dockerCmd(c, "network", "create", "-d", "bridge", "foo1") |
... | ... |
@@ -43,6 +43,7 @@ docker-create - Create a new container |
43 | 43 |
[**-l**|**--label**[=*[]*]] |
44 | 44 |
[**--label-file**[=*[]*]] |
45 | 45 |
[**--link**[=*[]*]] |
46 |
+[**--link-local-ip**[=*[]*]] |
|
46 | 47 |
[**--log-driver**[=*[]*]] |
47 | 48 |
[**--log-opt**[=*[]*]] |
48 | 49 |
[**-m**|**--memory**[=*MEMORY*]] |
... | ... |
@@ -220,6 +221,9 @@ millions of trillions. |
220 | 220 |
Add link to another container in the form of <name or id>:alias or just |
221 | 221 |
<name or id> in which case the alias will match the name. |
222 | 222 |
|
223 |
+**--link-local-ip**=[] |
|
224 |
+ Add one or more link-local IPv4/IPv6 addresses to the container's interface |
|
225 |
+ |
|
223 | 226 |
**--log-driver**="*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*awslogs*|*splunk*|*etwlogs*|*gcplogs*|*none*" |
224 | 227 |
Logging driver for container. Default is defined by daemon `--log-driver` flag. |
225 | 228 |
**Warning**: the `docker logs` command works only for the `json-file` and |
... | ... |
@@ -45,6 +45,7 @@ docker-run - Run a command in a new container |
45 | 45 |
[**-l**|**--label**[=*[]*]] |
46 | 46 |
[**--label-file**[=*[]*]] |
47 | 47 |
[**--link**[=*[]*]] |
48 |
+[**--link-local-ip**[=*[]*]] |
|
48 | 49 |
[**--log-driver**[=*[]*]] |
49 | 50 |
[**--log-opt**[=*[]*]] |
50 | 51 |
[**-m**|**--memory**[=*MEMORY*]] |
... | ... |
@@ -326,6 +327,9 @@ container can access the exposed port via a private networking interface. Docker |
326 | 326 |
will set some environment variables in the client container to help indicate |
327 | 327 |
which interface and port to use. |
328 | 328 |
|
329 |
+**--link-local-ip**=[] |
|
330 |
+ Add one or more link-local IPv4/IPv6 addresses to the container's interface |
|
331 |
+ |
|
329 | 332 |
**--log-driver**="*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*awslogs*|*splunk*|*etwlogs*|*gcplogs*|*none*" |
330 | 333 |
Logging driver for container. Default is defined by daemon `--log-driver` flag. |
331 | 334 |
**Warning**: the `docker logs` command works only for the `json-file` and |
... | ... |
@@ -32,6 +32,7 @@ type ContainerOptions struct { |
32 | 32 |
flDeviceWriteBps ThrottledeviceOpt |
33 | 33 |
flLinks opts.ListOpts |
34 | 34 |
flAliases opts.ListOpts |
35 |
+ flLinkLocalIPs opts.ListOpts |
|
35 | 36 |
flDeviceReadIOps ThrottledeviceOpt |
36 | 37 |
flDeviceWriteIOps ThrottledeviceOpt |
37 | 38 |
flEnv opts.ListOpts |
... | ... |
@@ -117,6 +118,7 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions { |
117 | 117 |
flDeviceWriteBps: NewThrottledeviceOpt(ValidateThrottleBpsDevice), |
118 | 118 |
flLinks: opts.NewListOpts(ValidateLink), |
119 | 119 |
flAliases: opts.NewListOpts(nil), |
120 |
+ flLinkLocalIPs: opts.NewListOpts(nil), |
|
120 | 121 |
flDeviceReadIOps: NewThrottledeviceOpt(ValidateThrottleIOpsDevice), |
121 | 122 |
flDeviceWriteIOps: NewThrottledeviceOpt(ValidateThrottleIOpsDevice), |
122 | 123 |
flEnv: opts.NewListOpts(ValidateEnv), |
... | ... |
@@ -201,6 +203,7 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions { |
201 | 201 |
flags.Var(&copts.flTmpfs, "tmpfs", "Mount a tmpfs directory") |
202 | 202 |
flags.Var(&copts.flLinks, "link", "Add link to another container") |
203 | 203 |
flags.Var(&copts.flAliases, "net-alias", "Add network-scoped alias for the container") |
204 |
+ flags.Var(&copts.flLinkLocalIPs, "link-local-ip", "Container IPv4/IPv6 link-local addresses") |
|
204 | 205 |
flags.Var(&copts.flDevices, "device", "Add a host device to the container") |
205 | 206 |
flags.VarP(&copts.flLabels, "label", "l", "Set meta data on a container") |
206 | 207 |
flags.Var(&copts.flLabelsFile, "label-file", "Read in a line delimited file of labels") |
... | ... |
@@ -229,7 +232,6 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions { |
229 | 229 |
// a HostConfig and returns them with the specified command. |
230 | 230 |
// If the specified args are not valid, it will return an error. |
231 | 231 |
func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { |
232 |
- |
|
233 | 232 |
var ( |
234 | 233 |
attachStdin = copts.flAttach.Get("stdin") |
235 | 234 |
attachStdout = copts.flAttach.Get("stdout") |
... | ... |
@@ -575,12 +577,18 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c |
575 | 575 |
EndpointsConfig: make(map[string]*networktypes.EndpointSettings), |
576 | 576 |
} |
577 | 577 |
|
578 |
- if *copts.flIPv4Address != "" || *copts.flIPv6Address != "" { |
|
579 |
- networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = &networktypes.EndpointSettings{ |
|
580 |
- IPAMConfig: &networktypes.EndpointIPAMConfig{ |
|
581 |
- IPv4Address: *copts.flIPv4Address, |
|
582 |
- IPv6Address: *copts.flIPv6Address, |
|
583 |
- }, |
|
578 |
+ if *copts.flIPv4Address != "" || *copts.flIPv6Address != "" || copts.flLinkLocalIPs.Len() > 0 { |
|
579 |
+ epConfig := &networktypes.EndpointSettings{} |
|
580 |
+ networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = epConfig |
|
581 |
+ |
|
582 |
+ epConfig.IPAMConfig = &networktypes.EndpointIPAMConfig{ |
|
583 |
+ IPv4Address: *copts.flIPv4Address, |
|
584 |
+ IPv6Address: *copts.flIPv6Address, |
|
585 |
+ } |
|
586 |
+ |
|
587 |
+ if copts.flLinkLocalIPs.Len() > 0 { |
|
588 |
+ epConfig.IPAMConfig.LinkLocalIPs = make([]string, copts.flLinkLocalIPs.Len()) |
|
589 |
+ copy(epConfig.IPAMConfig.LinkLocalIPs, copts.flLinkLocalIPs.GetAll()) |
|
584 | 590 |
} |
585 | 591 |
} |
586 | 592 |
|