Signed-off-by: Alessandro Boch <aboch@docker.com>
| ... | ... |
@@ -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 |
|