Remove networking out of core and into a driver
| ... | ... |
@@ -5,6 +5,11 @@ import ( |
| 5 | 5 |
"net" |
| 6 | 6 |
) |
| 7 | 7 |
|
| 8 |
+const ( |
|
| 9 |
+ DefaultNetworkMtu = 1500 |
|
| 10 |
+ DisableNetworkBridge = "none" |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 8 | 13 |
// FIXME: separate runtime configuration from http api configuration |
| 9 | 14 |
type DaemonConfig struct {
|
| 10 | 15 |
Pidfile string |
| ... | ... |
@@ -13,12 +18,13 @@ type DaemonConfig struct {
|
| 13 | 13 |
Dns []string |
| 14 | 14 |
EnableIptables bool |
| 15 | 15 |
EnableIpForward bool |
| 16 |
- BridgeIface string |
|
| 17 |
- BridgeIp string |
|
| 18 | 16 |
DefaultIp net.IP |
| 17 |
+ BridgeIface string |
|
| 18 |
+ BridgeIP string |
|
| 19 | 19 |
InterContainerCommunication bool |
| 20 | 20 |
GraphDriver string |
| 21 | 21 |
Mtu int |
| 22 |
+ DisableNetwork bool |
|
| 22 | 23 |
} |
| 23 | 24 |
|
| 24 | 25 |
// ConfigFromJob creates and returns a new DaemonConfig object |
| ... | ... |
@@ -30,7 +36,7 @@ func DaemonConfigFromJob(job *engine.Job) *DaemonConfig {
|
| 30 | 30 |
AutoRestart: job.GetenvBool("AutoRestart"),
|
| 31 | 31 |
EnableIptables: job.GetenvBool("EnableIptables"),
|
| 32 | 32 |
EnableIpForward: job.GetenvBool("EnableIpForward"),
|
| 33 |
- BridgeIp: job.Getenv("BridgeIp"),
|
|
| 33 |
+ BridgeIP: job.Getenv("BridgeIP"),
|
|
| 34 | 34 |
DefaultIp: net.ParseIP(job.Getenv("DefaultIp")),
|
| 35 | 35 |
InterContainerCommunication: job.GetenvBool("InterContainerCommunication"),
|
| 36 | 36 |
GraphDriver: job.Getenv("GraphDriver"),
|
| ... | ... |
@@ -38,16 +44,12 @@ func DaemonConfigFromJob(job *engine.Job) *DaemonConfig {
|
| 38 | 38 |
if dns := job.GetenvList("Dns"); dns != nil {
|
| 39 | 39 |
config.Dns = dns |
| 40 | 40 |
} |
| 41 |
- if br := job.Getenv("BridgeIface"); br != "" {
|
|
| 42 |
- config.BridgeIface = br |
|
| 43 |
- } else {
|
|
| 44 |
- config.BridgeIface = DefaultNetworkBridge |
|
| 45 |
- } |
|
| 46 | 41 |
if mtu := job.GetenvInt("Mtu"); mtu != 0 {
|
| 47 | 42 |
config.Mtu = mtu |
| 48 | 43 |
} else {
|
| 49 | 44 |
config.Mtu = DefaultNetworkMtu |
| 50 | 45 |
} |
| 46 |
+ config.DisableNetwork = job.Getenv("BridgeIface") == DisableNetworkBridge
|
|
| 51 | 47 |
|
| 52 | 48 |
return config |
| 53 | 49 |
} |
| ... | ... |
@@ -8,7 +8,6 @@ import ( |
| 8 | 8 |
"github.com/dotcloud/docker/engine" |
| 9 | 9 |
"github.com/dotcloud/docker/execdriver" |
| 10 | 10 |
"github.com/dotcloud/docker/graphdriver" |
| 11 |
- "github.com/dotcloud/docker/networkdriver/ipallocator" |
|
| 12 | 11 |
"github.com/dotcloud/docker/pkg/mount" |
| 13 | 12 |
"github.com/dotcloud/docker/pkg/term" |
| 14 | 13 |
"github.com/dotcloud/docker/utils" |
| ... | ... |
@@ -16,7 +15,6 @@ import ( |
| 16 | 16 |
"io" |
| 17 | 17 |
"io/ioutil" |
| 18 | 18 |
"log" |
| 19 |
- "net" |
|
| 20 | 19 |
"os" |
| 21 | 20 |
"path" |
| 22 | 21 |
"path/filepath" |
| ... | ... |
@@ -47,7 +45,6 @@ type Container struct {
|
| 47 | 47 |
State State |
| 48 | 48 |
Image string |
| 49 | 49 |
|
| 50 |
- network *NetworkInterface |
|
| 51 | 50 |
NetworkSettings *NetworkSettings |
| 52 | 51 |
|
| 53 | 52 |
ResolvConfPath string |
| ... | ... |
@@ -558,6 +555,7 @@ func populateCommand(c *Container) {
|
| 558 | 558 |
en *execdriver.Network |
| 559 | 559 |
driverConfig []string |
| 560 | 560 |
) |
| 561 |
+ |
|
| 561 | 562 |
if !c.Config.NetworkDisabled {
|
| 562 | 563 |
network := c.NetworkSettings |
| 563 | 564 |
en = &execdriver.Network{
|
| ... | ... |
@@ -603,15 +601,18 @@ func (container *Container) Start() (err error) {
|
| 603 | 603 |
if container.State.IsRunning() {
|
| 604 | 604 |
return fmt.Errorf("The container %s is already running.", container.ID)
|
| 605 | 605 |
} |
| 606 |
+ |
|
| 606 | 607 |
defer func() {
|
| 607 | 608 |
if err != nil {
|
| 608 | 609 |
container.cleanup() |
| 609 | 610 |
} |
| 610 | 611 |
}() |
| 612 |
+ |
|
| 611 | 613 |
if err := container.Mount(); err != nil {
|
| 612 | 614 |
return err |
| 613 | 615 |
} |
| 614 |
- if container.runtime.networkManager.disabled {
|
|
| 616 |
+ |
|
| 617 |
+ if container.runtime.config.DisableNetwork {
|
|
| 615 | 618 |
container.Config.NetworkDisabled = true |
| 616 | 619 |
container.buildHostnameAndHostsFiles("127.0.1.1")
|
| 617 | 620 |
} else {
|
| ... | ... |
@@ -681,7 +682,7 @@ func (container *Container) Start() (err error) {
|
| 681 | 681 |
} |
| 682 | 682 |
|
| 683 | 683 |
for p, child := range children {
|
| 684 |
- link, err := NewLink(container, child, p, runtime.networkManager.bridgeIface) |
|
| 684 |
+ link, err := NewLink(container, child, p, runtime.eng) |
|
| 685 | 685 |
if err != nil {
|
| 686 | 686 |
rollback() |
| 687 | 687 |
return err |
| ... | ... |
@@ -1102,34 +1103,40 @@ func (container *Container) allocateNetwork() error {
|
| 1102 | 1102 |
} |
| 1103 | 1103 |
|
| 1104 | 1104 |
var ( |
| 1105 |
- iface *NetworkInterface |
|
| 1106 |
- err error |
|
| 1105 |
+ env *engine.Env |
|
| 1106 |
+ err error |
|
| 1107 |
+ eng = container.runtime.eng |
|
| 1107 | 1108 |
) |
| 1109 |
+ |
|
| 1108 | 1110 |
if container.State.IsGhost() {
|
| 1109 |
- if manager := container.runtime.networkManager; manager.disabled {
|
|
| 1110 |
- iface = &NetworkInterface{disabled: true}
|
|
| 1111 |
+ if container.runtime.config.DisableNetwork {
|
|
| 1112 |
+ env = &engine.Env{}
|
|
| 1111 | 1113 |
} else {
|
| 1112 |
- iface = &NetworkInterface{
|
|
| 1113 |
- IPNet: net.IPNet{IP: net.ParseIP(container.NetworkSettings.IPAddress), Mask: manager.bridgeNetwork.Mask},
|
|
| 1114 |
- Gateway: manager.bridgeNetwork.IP, |
|
| 1115 |
- manager: manager, |
|
| 1114 |
+ currentIP := container.NetworkSettings.IPAddress |
|
| 1115 |
+ |
|
| 1116 |
+ job := eng.Job("allocate_interface", container.ID)
|
|
| 1117 |
+ if currentIP != "" {
|
|
| 1118 |
+ job.Setenv("RequestIP", currentIP)
|
|
| 1116 | 1119 |
} |
| 1117 |
- if iface != nil && iface.IPNet.IP != nil {
|
|
| 1118 |
- if _, err := ipallocator.RequestIP(manager.bridgeNetwork, &iface.IPNet.IP); err != nil {
|
|
| 1119 |
- return err |
|
| 1120 |
- } |
|
| 1121 |
- } else {
|
|
| 1122 |
- iface, err = container.runtime.networkManager.Allocate() |
|
| 1123 |
- if err != nil {
|
|
| 1124 |
- return err |
|
| 1125 |
- } |
|
| 1120 |
+ |
|
| 1121 |
+ env, err = job.Stdout.AddEnv() |
|
| 1122 |
+ if err != nil {
|
|
| 1123 |
+ return err |
|
| 1124 |
+ } |
|
| 1125 |
+ |
|
| 1126 |
+ if err := job.Run(); err != nil {
|
|
| 1127 |
+ return err |
|
| 1126 | 1128 |
} |
| 1127 | 1129 |
} |
| 1128 | 1130 |
} else {
|
| 1129 |
- iface, err = container.runtime.networkManager.Allocate() |
|
| 1131 |
+ job := eng.Job("allocate_interface", container.ID)
|
|
| 1132 |
+ env, err = job.Stdout.AddEnv() |
|
| 1130 | 1133 |
if err != nil {
|
| 1131 | 1134 |
return err |
| 1132 | 1135 |
} |
| 1136 |
+ if err := job.Run(); err != nil {
|
|
| 1137 |
+ return err |
|
| 1138 |
+ } |
|
| 1133 | 1139 |
} |
| 1134 | 1140 |
|
| 1135 | 1141 |
if container.Config.PortSpecs != nil {
|
| ... | ... |
@@ -1171,37 +1178,50 @@ func (container *Container) allocateNetwork() error {
|
| 1171 | 1171 |
if container.hostConfig.PublishAllPorts && len(binding) == 0 {
|
| 1172 | 1172 |
binding = append(binding, PortBinding{})
|
| 1173 | 1173 |
} |
| 1174 |
+ |
|
| 1174 | 1175 |
for i := 0; i < len(binding); i++ {
|
| 1175 | 1176 |
b := binding[i] |
| 1176 |
- nat, err := iface.AllocatePort(port, b) |
|
| 1177 |
+ |
|
| 1178 |
+ portJob := eng.Job("allocate_port", container.ID)
|
|
| 1179 |
+ portJob.Setenv("HostIP", b.HostIp)
|
|
| 1180 |
+ portJob.Setenv("HostPort", b.HostPort)
|
|
| 1181 |
+ portJob.Setenv("Proto", port.Proto())
|
|
| 1182 |
+ portJob.Setenv("ContainerPort", port.Port())
|
|
| 1183 |
+ |
|
| 1184 |
+ portEnv, err := portJob.Stdout.AddEnv() |
|
| 1177 | 1185 |
if err != nil {
|
| 1178 |
- iface.Release() |
|
| 1179 | 1186 |
return err |
| 1180 | 1187 |
} |
| 1181 |
- utils.Debugf("Allocate port: %s:%s->%s", nat.Binding.HostIp, port, nat.Binding.HostPort)
|
|
| 1182 |
- binding[i] = nat.Binding |
|
| 1188 |
+ if err := portJob.Run(); err != nil {
|
|
| 1189 |
+ eng.Job("release_interface", container.ID).Run()
|
|
| 1190 |
+ return err |
|
| 1191 |
+ } |
|
| 1192 |
+ b.HostIp = portEnv.Get("HostIP")
|
|
| 1193 |
+ b.HostPort = portEnv.Get("HostPort")
|
|
| 1194 |
+ |
|
| 1195 |
+ binding[i] = b |
|
| 1183 | 1196 |
} |
| 1184 | 1197 |
bindings[port] = binding |
| 1185 | 1198 |
} |
| 1186 | 1199 |
container.writeHostConfig() |
| 1187 | 1200 |
|
| 1188 | 1201 |
container.NetworkSettings.Ports = bindings |
| 1189 |
- container.network = iface |
|
| 1190 | 1202 |
|
| 1191 |
- container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface |
|
| 1192 |
- container.NetworkSettings.IPAddress = iface.IPNet.IP.String() |
|
| 1193 |
- container.NetworkSettings.IPPrefixLen, _ = iface.IPNet.Mask.Size() |
|
| 1194 |
- container.NetworkSettings.Gateway = iface.Gateway.String() |
|
| 1203 |
+ container.NetworkSettings.Bridge = env.Get("Bridge")
|
|
| 1204 |
+ container.NetworkSettings.IPAddress = env.Get("IP")
|
|
| 1205 |
+ container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
|
|
| 1206 |
+ container.NetworkSettings.Gateway = env.Get("Gateway")
|
|
| 1195 | 1207 |
|
| 1196 | 1208 |
return nil |
| 1197 | 1209 |
} |
| 1198 | 1210 |
|
| 1199 | 1211 |
func (container *Container) releaseNetwork() {
|
| 1200 |
- if container.Config.NetworkDisabled || container.network == nil {
|
|
| 1212 |
+ if container.Config.NetworkDisabled {
|
|
| 1201 | 1213 |
return |
| 1202 | 1214 |
} |
| 1203 |
- container.network.Release() |
|
| 1204 |
- container.network = nil |
|
| 1215 |
+ eng := container.runtime.eng |
|
| 1216 |
+ |
|
| 1217 |
+ eng.Job("release_interface", container.ID).Run()
|
|
| 1205 | 1218 |
container.NetworkSettings = &NetworkSettings{}
|
| 1206 | 1219 |
} |
| 1207 | 1220 |
|
| ... | ... |
@@ -91,7 +91,7 @@ func main() {
|
| 91 | 91 |
job.SetenvBool("EnableIptables", *flEnableIptables)
|
| 92 | 92 |
job.SetenvBool("EnableIpForward", *flEnableIpForward)
|
| 93 | 93 |
job.Setenv("BridgeIface", *bridgeName)
|
| 94 |
- job.Setenv("BridgeIp", *bridgeIp)
|
|
| 94 |
+ job.Setenv("BridgeIP", *bridgeIp)
|
|
| 95 | 95 |
job.Setenv("DefaultIp", *flDefaultIp)
|
| 96 | 96 |
job.SetenvBool("InterContainerCommunication", *flInterContainerComm)
|
| 97 | 97 |
job.Setenv("GraphDriver", *flGraphDriver)
|
| ... | ... |
@@ -34,7 +34,13 @@ func mkRuntime(f utils.Fataler) *docker.Runtime {
|
| 34 | 34 |
AutoRestart: false, |
| 35 | 35 |
Mtu: docker.DefaultNetworkMtu, |
| 36 | 36 |
} |
| 37 |
- r, err := docker.NewRuntimeFromDirectory(config) |
|
| 37 |
+ |
|
| 38 |
+ eng, err := engine.New(root) |
|
| 39 |
+ if err != nil {
|
|
| 40 |
+ f.Fatal(err) |
|
| 41 |
+ } |
|
| 42 |
+ |
|
| 43 |
+ r, err := docker.NewRuntimeFromDirectory(config, eng) |
|
| 38 | 44 |
if err != nil {
|
| 39 | 45 |
f.Fatal(err) |
| 40 | 46 |
} |
| ... | ... |
@@ -2,7 +2,7 @@ package docker |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
- "github.com/dotcloud/docker/pkg/iptables" |
|
| 5 |
+ "github.com/dotcloud/docker/engine" |
|
| 6 | 6 |
"path" |
| 7 | 7 |
"strings" |
| 8 | 8 |
) |
| ... | ... |
@@ -11,13 +11,13 @@ type Link struct {
|
| 11 | 11 |
ParentIP string |
| 12 | 12 |
ChildIP string |
| 13 | 13 |
Name string |
| 14 |
- BridgeInterface string |
|
| 15 | 14 |
ChildEnvironment []string |
| 16 | 15 |
Ports []Port |
| 17 | 16 |
IsEnabled bool |
| 17 |
+ eng *engine.Engine |
|
| 18 | 18 |
} |
| 19 | 19 |
|
| 20 |
-func NewLink(parent, child *Container, name, bridgeInterface string) (*Link, error) {
|
|
| 20 |
+func NewLink(parent, child *Container, name string, eng *engine.Engine) (*Link, error) {
|
|
| 21 | 21 |
if parent.ID == child.ID {
|
| 22 | 22 |
return nil, fmt.Errorf("Cannot link to self: %s == %s", parent.ID, child.ID)
|
| 23 | 23 |
} |
| ... | ... |
@@ -33,12 +33,12 @@ func NewLink(parent, child *Container, name, bridgeInterface string) (*Link, err |
| 33 | 33 |
} |
| 34 | 34 |
|
| 35 | 35 |
l := &Link{
|
| 36 |
- BridgeInterface: bridgeInterface, |
|
| 37 | 36 |
Name: name, |
| 38 | 37 |
ChildIP: child.NetworkSettings.IPAddress, |
| 39 | 38 |
ParentIP: parent.NetworkSettings.IPAddress, |
| 40 | 39 |
ChildEnvironment: child.Config.Env, |
| 41 | 40 |
Ports: ports, |
| 41 |
+ eng: eng, |
|
| 42 | 42 |
} |
| 43 | 43 |
return l, nil |
| 44 | 44 |
|
| ... | ... |
@@ -119,18 +119,21 @@ func (l *Link) Disable() {
|
| 119 | 119 |
} |
| 120 | 120 |
|
| 121 | 121 |
func (l *Link) toggle(action string, ignoreErrors bool) error {
|
| 122 |
- for _, p := range l.Ports {
|
|
| 123 |
- if output, err := iptables.Raw(action, "FORWARD", |
|
| 124 |
- "-i", l.BridgeInterface, "-o", l.BridgeInterface, |
|
| 125 |
- "-p", p.Proto(), |
|
| 126 |
- "-s", l.ParentIP, |
|
| 127 |
- "--dport", p.Port(), |
|
| 128 |
- "-d", l.ChildIP, |
|
| 129 |
- "-j", "ACCEPT"); !ignoreErrors && err != nil {
|
|
| 130 |
- return err |
|
| 131 |
- } else if len(output) != 0 {
|
|
| 132 |
- return fmt.Errorf("Error toggle iptables forward: %s", output)
|
|
| 133 |
- } |
|
| 122 |
+ job := l.eng.Job("link", action)
|
|
| 123 |
+ |
|
| 124 |
+ job.Setenv("ParentIP", l.ParentIP)
|
|
| 125 |
+ job.Setenv("ChildIP", l.ChildIP)
|
|
| 126 |
+ job.SetenvBool("IgnoreErrors", ignoreErrors)
|
|
| 127 |
+ |
|
| 128 |
+ out := make([]string, len(l.Ports)) |
|
| 129 |
+ for i, p := range l.Ports {
|
|
| 130 |
+ out[i] = fmt.Sprintf("%s/%s", p.Port(), p.Proto())
|
|
| 131 |
+ } |
|
| 132 |
+ job.SetenvList("Ports", out)
|
|
| 133 |
+ |
|
| 134 |
+ if err := job.Run(); err != nil {
|
|
| 135 |
+ // TODO: get ouput from job |
|
| 136 |
+ return err |
|
| 134 | 137 |
} |
| 135 | 138 |
return nil |
| 136 | 139 |
} |
| ... | ... |
@@ -30,7 +30,7 @@ func TestLinkNew(t *testing.T) {
|
| 30 | 30 |
|
| 31 | 31 |
to := newMockLinkContainer(toID, "172.0.17.3") |
| 32 | 32 |
|
| 33 |
- link, err := NewLink(to, from, "/db/docker", "172.0.17.1") |
|
| 33 |
+ link, err := NewLink(to, from, "/db/docker", nil) |
|
| 34 | 34 |
if err != nil {
|
| 35 | 35 |
t.Fatal(err) |
| 36 | 36 |
} |
| ... | ... |
@@ -50,9 +50,6 @@ func TestLinkNew(t *testing.T) {
|
| 50 | 50 |
if link.ChildIP != "172.0.17.2" {
|
| 51 | 51 |
t.Fail() |
| 52 | 52 |
} |
| 53 |
- if link.BridgeInterface != "172.0.17.1" {
|
|
| 54 |
- t.Fail() |
|
| 55 |
- } |
|
| 56 | 53 |
for _, p := range link.Ports {
|
| 57 | 54 |
if p != Port("6379/tcp") {
|
| 58 | 55 |
t.Fail() |
| ... | ... |
@@ -75,7 +72,7 @@ func TestLinkEnv(t *testing.T) {
|
| 75 | 75 |
|
| 76 | 76 |
to := newMockLinkContainer(toID, "172.0.17.3") |
| 77 | 77 |
|
| 78 |
- link, err := NewLink(to, from, "/db/docker", "172.0.17.1") |
|
| 78 |
+ link, err := NewLink(to, from, "/db/docker", nil) |
|
| 79 | 79 |
if err != nil {
|
| 80 | 80 |
t.Fatal(err) |
| 81 | 81 |
} |
| 82 | 82 |
deleted file mode 100644 |
| ... | ... |
@@ -1,413 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- "github.com/dotcloud/docker/networkdriver" |
|
| 6 |
- "github.com/dotcloud/docker/networkdriver/ipallocator" |
|
| 7 |
- "github.com/dotcloud/docker/networkdriver/portallocator" |
|
| 8 |
- "github.com/dotcloud/docker/networkdriver/portmapper" |
|
| 9 |
- "github.com/dotcloud/docker/pkg/iptables" |
|
| 10 |
- "github.com/dotcloud/docker/pkg/netlink" |
|
| 11 |
- "github.com/dotcloud/docker/utils" |
|
| 12 |
- "io/ioutil" |
|
| 13 |
- "log" |
|
| 14 |
- "net" |
|
| 15 |
- "strconv" |
|
| 16 |
- "syscall" |
|
| 17 |
- "unsafe" |
|
| 18 |
-) |
|
| 19 |
- |
|
| 20 |
-const ( |
|
| 21 |
- DefaultNetworkBridge = "docker0" |
|
| 22 |
- DisableNetworkBridge = "none" |
|
| 23 |
- DefaultNetworkMtu = 1500 |
|
| 24 |
- siocBRADDBR = 0x89a0 |
|
| 25 |
-) |
|
| 26 |
- |
|
| 27 |
-// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`, |
|
| 28 |
-// and attempts to configure it with an address which doesn't conflict with any other interface on the host. |
|
| 29 |
-// If it can't find an address which doesn't conflict, it will return an error. |
|
| 30 |
-func CreateBridgeIface(config *DaemonConfig) error {
|
|
| 31 |
- addrs := []string{
|
|
| 32 |
- // Here we don't follow the convention of using the 1st IP of the range for the gateway. |
|
| 33 |
- // This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges. |
|
| 34 |
- // In theory this shouldn't matter - in practice there's bound to be a few scripts relying |
|
| 35 |
- // on the internal addressing or other stupid things like that. |
|
| 36 |
- // The shouldn't, but hey, let's not break them unless we really have to. |
|
| 37 |
- "172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23 |
|
| 38 |
- "10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive |
|
| 39 |
- "10.1.42.1/16", |
|
| 40 |
- "10.42.42.1/16", |
|
| 41 |
- "172.16.42.1/24", |
|
| 42 |
- "172.16.43.1/24", |
|
| 43 |
- "172.16.44.1/24", |
|
| 44 |
- "10.0.42.1/24", |
|
| 45 |
- "10.0.43.1/24", |
|
| 46 |
- "192.168.42.1/24", |
|
| 47 |
- "192.168.43.1/24", |
|
| 48 |
- "192.168.44.1/24", |
|
| 49 |
- } |
|
| 50 |
- |
|
| 51 |
- nameservers := []string{}
|
|
| 52 |
- resolvConf, _ := utils.GetResolvConf() |
|
| 53 |
- // we don't check for an error here, because we don't really care |
|
| 54 |
- // if we can't read /etc/resolv.conf. So instead we skip the append |
|
| 55 |
- // if resolvConf is nil. It either doesn't exist, or we can't read it |
|
| 56 |
- // for some reason. |
|
| 57 |
- if resolvConf != nil {
|
|
| 58 |
- nameservers = append(nameservers, utils.GetNameserversAsCIDR(resolvConf)...) |
|
| 59 |
- } |
|
| 60 |
- |
|
| 61 |
- var ifaceAddr string |
|
| 62 |
- if len(config.BridgeIp) != 0 {
|
|
| 63 |
- _, _, err := net.ParseCIDR(config.BridgeIp) |
|
| 64 |
- if err != nil {
|
|
| 65 |
- return err |
|
| 66 |
- } |
|
| 67 |
- ifaceAddr = config.BridgeIp |
|
| 68 |
- } else {
|
|
| 69 |
- for _, addr := range addrs {
|
|
| 70 |
- _, dockerNetwork, err := net.ParseCIDR(addr) |
|
| 71 |
- if err != nil {
|
|
| 72 |
- return err |
|
| 73 |
- } |
|
| 74 |
- if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
|
|
| 75 |
- if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
|
|
| 76 |
- ifaceAddr = addr |
|
| 77 |
- break |
|
| 78 |
- } else {
|
|
| 79 |
- utils.Debugf("%s %s", addr, err)
|
|
| 80 |
- } |
|
| 81 |
- } |
|
| 82 |
- } |
|
| 83 |
- } |
|
| 84 |
- |
|
| 85 |
- if ifaceAddr == "" {
|
|
| 86 |
- return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", config.BridgeIface, config.BridgeIface)
|
|
| 87 |
- } |
|
| 88 |
- utils.Debugf("Creating bridge %s with network %s", config.BridgeIface, ifaceAddr)
|
|
| 89 |
- |
|
| 90 |
- if err := createBridgeIface(config.BridgeIface); err != nil {
|
|
| 91 |
- return err |
|
| 92 |
- } |
|
| 93 |
- iface, err := net.InterfaceByName(config.BridgeIface) |
|
| 94 |
- if err != nil {
|
|
| 95 |
- return err |
|
| 96 |
- } |
|
| 97 |
- ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr) |
|
| 98 |
- if err != nil {
|
|
| 99 |
- return err |
|
| 100 |
- } |
|
| 101 |
- if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
|
|
| 102 |
- return fmt.Errorf("Unable to add private network: %s", err)
|
|
| 103 |
- } |
|
| 104 |
- if err := netlink.NetworkLinkUp(iface); err != nil {
|
|
| 105 |
- return fmt.Errorf("Unable to start network bridge: %s", err)
|
|
| 106 |
- } |
|
| 107 |
- |
|
| 108 |
- return nil |
|
| 109 |
-} |
|
| 110 |
- |
|
| 111 |
-// Create the actual bridge device. This is more backward-compatible than |
|
| 112 |
-// netlink.NetworkLinkAdd and works on RHEL 6. |
|
| 113 |
-func createBridgeIface(name string) error {
|
|
| 114 |
- s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP) |
|
| 115 |
- if err != nil {
|
|
| 116 |
- utils.Debugf("Bridge socket creation failed IPv6 probably not enabled: %v", err)
|
|
| 117 |
- s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP) |
|
| 118 |
- if err != nil {
|
|
| 119 |
- return fmt.Errorf("Error creating bridge creation socket: %s", err)
|
|
| 120 |
- } |
|
| 121 |
- } |
|
| 122 |
- defer syscall.Close(s) |
|
| 123 |
- |
|
| 124 |
- nameBytePtr, err := syscall.BytePtrFromString(name) |
|
| 125 |
- if err != nil {
|
|
| 126 |
- return fmt.Errorf("Error converting bridge name %s to byte array: %s", name, err)
|
|
| 127 |
- } |
|
| 128 |
- |
|
| 129 |
- if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), siocBRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
|
|
| 130 |
- return fmt.Errorf("Error creating bridge: %s", err)
|
|
| 131 |
- } |
|
| 132 |
- return nil |
|
| 133 |
-} |
|
| 134 |
- |
|
| 135 |
-// Return the IPv4 address of a network interface |
|
| 136 |
-func getIfaceAddr(name string) (net.Addr, error) {
|
|
| 137 |
- iface, err := net.InterfaceByName(name) |
|
| 138 |
- if err != nil {
|
|
| 139 |
- return nil, err |
|
| 140 |
- } |
|
| 141 |
- addrs, err := iface.Addrs() |
|
| 142 |
- if err != nil {
|
|
| 143 |
- return nil, err |
|
| 144 |
- } |
|
| 145 |
- var addrs4 []net.Addr |
|
| 146 |
- for _, addr := range addrs {
|
|
| 147 |
- ip := (addr.(*net.IPNet)).IP |
|
| 148 |
- if ip4 := ip.To4(); len(ip4) == net.IPv4len {
|
|
| 149 |
- addrs4 = append(addrs4, addr) |
|
| 150 |
- } |
|
| 151 |
- } |
|
| 152 |
- switch {
|
|
| 153 |
- case len(addrs4) == 0: |
|
| 154 |
- return nil, fmt.Errorf("Interface %v has no IP addresses", name)
|
|
| 155 |
- case len(addrs4) > 1: |
|
| 156 |
- fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
|
|
| 157 |
- name, (addrs4[0].(*net.IPNet)).IP) |
|
| 158 |
- } |
|
| 159 |
- return addrs4[0], nil |
|
| 160 |
-} |
|
| 161 |
- |
|
| 162 |
-// Network interface represents the networking stack of a container |
|
| 163 |
-type NetworkInterface struct {
|
|
| 164 |
- IPNet net.IPNet |
|
| 165 |
- Gateway net.IP |
|
| 166 |
- |
|
| 167 |
- manager *NetworkManager |
|
| 168 |
- extPorts []*Nat |
|
| 169 |
- disabled bool |
|
| 170 |
-} |
|
| 171 |
- |
|
| 172 |
-// Allocate an external port and map it to the interface |
|
| 173 |
-func (iface *NetworkInterface) AllocatePort(port Port, binding PortBinding) (*Nat, error) {
|
|
| 174 |
- |
|
| 175 |
- if iface.disabled {
|
|
| 176 |
- return nil, fmt.Errorf("Trying to allocate port for interface %v, which is disabled", iface) // FIXME
|
|
| 177 |
- } |
|
| 178 |
- |
|
| 179 |
- ip := iface.manager.defaultBindingIP |
|
| 180 |
- |
|
| 181 |
- if binding.HostIp != "" {
|
|
| 182 |
- ip = net.ParseIP(binding.HostIp) |
|
| 183 |
- } else {
|
|
| 184 |
- binding.HostIp = ip.String() |
|
| 185 |
- } |
|
| 186 |
- |
|
| 187 |
- nat := &Nat{
|
|
| 188 |
- Port: port, |
|
| 189 |
- Binding: binding, |
|
| 190 |
- } |
|
| 191 |
- |
|
| 192 |
- containerPort, err := parsePort(port.Port()) |
|
| 193 |
- if err != nil {
|
|
| 194 |
- return nil, err |
|
| 195 |
- } |
|
| 196 |
- |
|
| 197 |
- hostPort, _ := parsePort(nat.Binding.HostPort) |
|
| 198 |
- |
|
| 199 |
- extPort, err := portallocator.RequestPort(ip, nat.Port.Proto(), hostPort) |
|
| 200 |
- if err != nil {
|
|
| 201 |
- return nil, err |
|
| 202 |
- } |
|
| 203 |
- |
|
| 204 |
- var backend net.Addr |
|
| 205 |
- if nat.Port.Proto() == "tcp" {
|
|
| 206 |
- backend = &net.TCPAddr{IP: iface.IPNet.IP, Port: containerPort}
|
|
| 207 |
- } else {
|
|
| 208 |
- backend = &net.UDPAddr{IP: iface.IPNet.IP, Port: containerPort}
|
|
| 209 |
- } |
|
| 210 |
- |
|
| 211 |
- if err := portmapper.Map(backend, ip, extPort); err != nil {
|
|
| 212 |
- portallocator.ReleasePort(ip, nat.Port.Proto(), extPort) |
|
| 213 |
- return nil, err |
|
| 214 |
- } |
|
| 215 |
- |
|
| 216 |
- nat.Binding.HostPort = strconv.Itoa(extPort) |
|
| 217 |
- iface.extPorts = append(iface.extPorts, nat) |
|
| 218 |
- |
|
| 219 |
- return nat, nil |
|
| 220 |
-} |
|
| 221 |
- |
|
| 222 |
-type Nat struct {
|
|
| 223 |
- Port Port |
|
| 224 |
- Binding PortBinding |
|
| 225 |
-} |
|
| 226 |
- |
|
| 227 |
-func (n *Nat) String() string {
|
|
| 228 |
- return fmt.Sprintf("%s:%s:%s/%s", n.Binding.HostIp, n.Binding.HostPort, n.Port.Port(), n.Port.Proto())
|
|
| 229 |
-} |
|
| 230 |
- |
|
| 231 |
-// Release: Network cleanup - release all resources |
|
| 232 |
-func (iface *NetworkInterface) Release() {
|
|
| 233 |
- if iface.disabled {
|
|
| 234 |
- return |
|
| 235 |
- } |
|
| 236 |
- |
|
| 237 |
- for _, nat := range iface.extPorts {
|
|
| 238 |
- hostPort, err := parsePort(nat.Binding.HostPort) |
|
| 239 |
- if err != nil {
|
|
| 240 |
- log.Printf("Unable to get host port: %s", err)
|
|
| 241 |
- continue |
|
| 242 |
- } |
|
| 243 |
- ip := net.ParseIP(nat.Binding.HostIp) |
|
| 244 |
- utils.Debugf("Unmaping %s/%s:%s", nat.Port.Proto, ip.String(), nat.Binding.HostPort)
|
|
| 245 |
- |
|
| 246 |
- var host net.Addr |
|
| 247 |
- if nat.Port.Proto() == "tcp" {
|
|
| 248 |
- host = &net.TCPAddr{IP: ip, Port: hostPort}
|
|
| 249 |
- } else {
|
|
| 250 |
- host = &net.UDPAddr{IP: ip, Port: hostPort}
|
|
| 251 |
- } |
|
| 252 |
- |
|
| 253 |
- if err := portmapper.Unmap(host); err != nil {
|
|
| 254 |
- log.Printf("Unable to unmap port %s: %s", nat, err)
|
|
| 255 |
- } |
|
| 256 |
- |
|
| 257 |
- if err := portallocator.ReleasePort(ip, nat.Port.Proto(), hostPort); err != nil {
|
|
| 258 |
- log.Printf("Unable to release port %s", nat)
|
|
| 259 |
- } |
|
| 260 |
- } |
|
| 261 |
- |
|
| 262 |
- if err := ipallocator.ReleaseIP(iface.manager.bridgeNetwork, &iface.IPNet.IP); err != nil {
|
|
| 263 |
- log.Printf("Unable to release ip %s\n", err)
|
|
| 264 |
- } |
|
| 265 |
-} |
|
| 266 |
- |
|
| 267 |
-// Network Manager manages a set of network interfaces |
|
| 268 |
-// Only *one* manager per host machine should be used |
|
| 269 |
-type NetworkManager struct {
|
|
| 270 |
- bridgeIface string |
|
| 271 |
- bridgeNetwork *net.IPNet |
|
| 272 |
- defaultBindingIP net.IP |
|
| 273 |
- disabled bool |
|
| 274 |
-} |
|
| 275 |
- |
|
| 276 |
-// Allocate a network interface |
|
| 277 |
-func (manager *NetworkManager) Allocate() (*NetworkInterface, error) {
|
|
| 278 |
- |
|
| 279 |
- if manager.disabled {
|
|
| 280 |
- return &NetworkInterface{disabled: true}, nil
|
|
| 281 |
- } |
|
| 282 |
- |
|
| 283 |
- var ip *net.IP |
|
| 284 |
- var err error |
|
| 285 |
- |
|
| 286 |
- ip, err = ipallocator.RequestIP(manager.bridgeNetwork, nil) |
|
| 287 |
- if err != nil {
|
|
| 288 |
- return nil, err |
|
| 289 |
- } |
|
| 290 |
- |
|
| 291 |
- iface := &NetworkInterface{
|
|
| 292 |
- IPNet: net.IPNet{IP: *ip, Mask: manager.bridgeNetwork.Mask},
|
|
| 293 |
- Gateway: manager.bridgeNetwork.IP, |
|
| 294 |
- manager: manager, |
|
| 295 |
- } |
|
| 296 |
- return iface, nil |
|
| 297 |
-} |
|
| 298 |
- |
|
| 299 |
-func newNetworkManager(config *DaemonConfig) (*NetworkManager, error) {
|
|
| 300 |
- if config.BridgeIface == DisableNetworkBridge {
|
|
| 301 |
- manager := &NetworkManager{
|
|
| 302 |
- disabled: true, |
|
| 303 |
- } |
|
| 304 |
- return manager, nil |
|
| 305 |
- } |
|
| 306 |
- |
|
| 307 |
- var network *net.IPNet |
|
| 308 |
- addr, err := getIfaceAddr(config.BridgeIface) |
|
| 309 |
- if err != nil {
|
|
| 310 |
- // If the iface is not found, try to create it |
|
| 311 |
- if err := CreateBridgeIface(config); err != nil {
|
|
| 312 |
- return nil, err |
|
| 313 |
- } |
|
| 314 |
- addr, err = getIfaceAddr(config.BridgeIface) |
|
| 315 |
- if err != nil {
|
|
| 316 |
- return nil, err |
|
| 317 |
- } |
|
| 318 |
- network = addr.(*net.IPNet) |
|
| 319 |
- } else {
|
|
| 320 |
- network = addr.(*net.IPNet) |
|
| 321 |
- } |
|
| 322 |
- |
|
| 323 |
- // Configure iptables for link support |
|
| 324 |
- if config.EnableIptables {
|
|
| 325 |
- |
|
| 326 |
- // Enable NAT |
|
| 327 |
- natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-d", addr.String(), "-j", "MASQUERADE"}
|
|
| 328 |
- |
|
| 329 |
- if !iptables.Exists(natArgs...) {
|
|
| 330 |
- if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
|
|
| 331 |
- return nil, fmt.Errorf("Unable to enable network bridge NAT: %s", err)
|
|
| 332 |
- } else if len(output) != 0 {
|
|
| 333 |
- return nil, fmt.Errorf("Error iptables postrouting: %s", output)
|
|
| 334 |
- } |
|
| 335 |
- } |
|
| 336 |
- |
|
| 337 |
- args := []string{"FORWARD", "-i", config.BridgeIface, "-o", config.BridgeIface, "-j"}
|
|
| 338 |
- acceptArgs := append(args, "ACCEPT") |
|
| 339 |
- dropArgs := append(args, "DROP") |
|
| 340 |
- |
|
| 341 |
- if !config.InterContainerCommunication {
|
|
| 342 |
- iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
|
|
| 343 |
- if !iptables.Exists(dropArgs...) {
|
|
| 344 |
- utils.Debugf("Disable inter-container communication")
|
|
| 345 |
- if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
|
|
| 346 |
- return nil, fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
|
|
| 347 |
- } else if len(output) != 0 {
|
|
| 348 |
- return nil, fmt.Errorf("Error disabling intercontainer communication: %s", output)
|
|
| 349 |
- } |
|
| 350 |
- } |
|
| 351 |
- } else {
|
|
| 352 |
- iptables.Raw(append([]string{"-D"}, dropArgs...)...)
|
|
| 353 |
- if !iptables.Exists(acceptArgs...) {
|
|
| 354 |
- utils.Debugf("Enable inter-container communication")
|
|
| 355 |
- if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
|
|
| 356 |
- return nil, fmt.Errorf("Unable to allow intercontainer communication: %s", err)
|
|
| 357 |
- } else if len(output) != 0 {
|
|
| 358 |
- return nil, fmt.Errorf("Error enabling intercontainer communication: %s", output)
|
|
| 359 |
- } |
|
| 360 |
- } |
|
| 361 |
- } |
|
| 362 |
- |
|
| 363 |
- // Accept all non-intercontainer outgoing packets |
|
| 364 |
- outgoingArgs := []string{"FORWARD", "-i", config.BridgeIface, "!", "-o", config.BridgeIface, "-j", "ACCEPT"}
|
|
| 365 |
- |
|
| 366 |
- if !iptables.Exists(outgoingArgs...) {
|
|
| 367 |
- if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
|
|
| 368 |
- return nil, fmt.Errorf("Unable to allow outgoing packets: %s", err)
|
|
| 369 |
- } else if len(output) != 0 {
|
|
| 370 |
- return nil, fmt.Errorf("Error iptables allow outgoing: %s", output)
|
|
| 371 |
- } |
|
| 372 |
- } |
|
| 373 |
- |
|
| 374 |
- // Accept incoming packets for existing connections |
|
| 375 |
- existingArgs := []string{"FORWARD", "-o", config.BridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
|
|
| 376 |
- |
|
| 377 |
- if !iptables.Exists(existingArgs...) {
|
|
| 378 |
- if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
|
|
| 379 |
- return nil, fmt.Errorf("Unable to allow incoming packets: %s", err)
|
|
| 380 |
- } else if len(output) != 0 {
|
|
| 381 |
- return nil, fmt.Errorf("Error iptables allow incoming: %s", output)
|
|
| 382 |
- } |
|
| 383 |
- } |
|
| 384 |
- |
|
| 385 |
- } |
|
| 386 |
- |
|
| 387 |
- if config.EnableIpForward {
|
|
| 388 |
- // Enable IPv4 forwarding |
|
| 389 |
- if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
|
|
| 390 |
- log.Printf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
|
|
| 391 |
- } |
|
| 392 |
- } |
|
| 393 |
- |
|
| 394 |
- // We can always try removing the iptables |
|
| 395 |
- if err := iptables.RemoveExistingChain("DOCKER"); err != nil {
|
|
| 396 |
- return nil, err |
|
| 397 |
- } |
|
| 398 |
- |
|
| 399 |
- if config.EnableIptables {
|
|
| 400 |
- chain, err := iptables.NewChain("DOCKER", config.BridgeIface)
|
|
| 401 |
- if err != nil {
|
|
| 402 |
- return nil, err |
|
| 403 |
- } |
|
| 404 |
- portmapper.SetIptablesChain(chain) |
|
| 405 |
- } |
|
| 406 |
- |
|
| 407 |
- manager := &NetworkManager{
|
|
| 408 |
- bridgeIface: config.BridgeIface, |
|
| 409 |
- bridgeNetwork: network, |
|
| 410 |
- defaultBindingIP: config.DefaultIp, |
|
| 411 |
- } |
|
| 412 |
- return manager, nil |
|
| 413 |
-} |
| 414 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,471 @@ |
| 0 |
+package lxc |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "github.com/dotcloud/docker/engine" |
|
| 5 |
+ "github.com/dotcloud/docker/networkdriver" |
|
| 6 |
+ "github.com/dotcloud/docker/networkdriver/ipallocator" |
|
| 7 |
+ "github.com/dotcloud/docker/networkdriver/portallocator" |
|
| 8 |
+ "github.com/dotcloud/docker/networkdriver/portmapper" |
|
| 9 |
+ "github.com/dotcloud/docker/pkg/iptables" |
|
| 10 |
+ "github.com/dotcloud/docker/pkg/netlink" |
|
| 11 |
+ "github.com/dotcloud/docker/utils" |
|
| 12 |
+ "io/ioutil" |
|
| 13 |
+ "log" |
|
| 14 |
+ "net" |
|
| 15 |
+ "strings" |
|
| 16 |
+ "syscall" |
|
| 17 |
+ "unsafe" |
|
| 18 |
+) |
|
| 19 |
+ |
|
| 20 |
+const ( |
|
| 21 |
+ DefaultNetworkBridge = "docker0" |
|
| 22 |
+ siocBRADDBR = 0x89a0 |
|
| 23 |
+) |
|
| 24 |
+ |
|
| 25 |
+// Network interface represents the networking stack of a container |
|
| 26 |
+type networkInterface struct {
|
|
| 27 |
+ IP net.IP |
|
| 28 |
+ PortMappings []net.Addr // there are mappings to the host interfaces |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+var ( |
|
| 32 |
+ addrs = []string{
|
|
| 33 |
+ // Here we don't follow the convention of using the 1st IP of the range for the gateway. |
|
| 34 |
+ // This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges. |
|
| 35 |
+ // In theory this shouldn't matter - in practice there's bound to be a few scripts relying |
|
| 36 |
+ // on the internal addressing or other stupid things like that. |
|
| 37 |
+ // The shouldn't, but hey, let's not break them unless we really have to. |
|
| 38 |
+ "172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23 |
|
| 39 |
+ "10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive |
|
| 40 |
+ "10.1.42.1/16", |
|
| 41 |
+ "10.42.42.1/16", |
|
| 42 |
+ "172.16.42.1/24", |
|
| 43 |
+ "172.16.43.1/24", |
|
| 44 |
+ "172.16.44.1/24", |
|
| 45 |
+ "10.0.42.1/24", |
|
| 46 |
+ "10.0.43.1/24", |
|
| 47 |
+ "192.168.42.1/24", |
|
| 48 |
+ "192.168.43.1/24", |
|
| 49 |
+ "192.168.44.1/24", |
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 52 |
+ bridgeIface string |
|
| 53 |
+ bridgeNetwork *net.IPNet |
|
| 54 |
+ |
|
| 55 |
+ defaultBindingIP = net.ParseIP("0.0.0.0")
|
|
| 56 |
+ currentInterfaces = make(map[string]*networkInterface) |
|
| 57 |
+) |
|
| 58 |
+ |
|
| 59 |
+func init() {
|
|
| 60 |
+ if err := engine.Register("init_networkdriver", InitDriver); err != nil {
|
|
| 61 |
+ panic(err) |
|
| 62 |
+ } |
|
| 63 |
+} |
|
| 64 |
+ |
|
| 65 |
+func InitDriver(job *engine.Job) engine.Status {
|
|
| 66 |
+ var ( |
|
| 67 |
+ network *net.IPNet |
|
| 68 |
+ enableIPTables = job.GetenvBool("EnableIptables")
|
|
| 69 |
+ icc = job.GetenvBool("InterContainerCommunication")
|
|
| 70 |
+ ipForward = job.GetenvBool("EnableIpForward")
|
|
| 71 |
+ bridgeIP = job.Getenv("BridgeIP")
|
|
| 72 |
+ ) |
|
| 73 |
+ |
|
| 74 |
+ if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
|
|
| 75 |
+ defaultBindingIP = net.ParseIP(defaultIP) |
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ bridgeIface = job.Getenv("BridgeIface")
|
|
| 79 |
+ if bridgeIface == "" {
|
|
| 80 |
+ bridgeIface = DefaultNetworkBridge |
|
| 81 |
+ } |
|
| 82 |
+ |
|
| 83 |
+ addr, err := networkdriver.GetIfaceAddr(bridgeIface) |
|
| 84 |
+ if err != nil {
|
|
| 85 |
+ // If the iface is not found, try to create it |
|
| 86 |
+ job.Logf("creating new bridge for %s", bridgeIface)
|
|
| 87 |
+ if err := createBridge(bridgeIP); err != nil {
|
|
| 88 |
+ job.Error(err) |
|
| 89 |
+ return engine.StatusErr |
|
| 90 |
+ } |
|
| 91 |
+ |
|
| 92 |
+ job.Logf("getting iface addr")
|
|
| 93 |
+ addr, err = networkdriver.GetIfaceAddr(bridgeIface) |
|
| 94 |
+ if err != nil {
|
|
| 95 |
+ job.Error(err) |
|
| 96 |
+ return engine.StatusErr |
|
| 97 |
+ } |
|
| 98 |
+ network = addr.(*net.IPNet) |
|
| 99 |
+ } else {
|
|
| 100 |
+ network = addr.(*net.IPNet) |
|
| 101 |
+ } |
|
| 102 |
+ |
|
| 103 |
+ // Configure iptables for link support |
|
| 104 |
+ if enableIPTables {
|
|
| 105 |
+ if err := setupIPTables(addr, icc); err != nil {
|
|
| 106 |
+ job.Error(err) |
|
| 107 |
+ return engine.StatusErr |
|
| 108 |
+ } |
|
| 109 |
+ } |
|
| 110 |
+ |
|
| 111 |
+ if ipForward {
|
|
| 112 |
+ // Enable IPv4 forwarding |
|
| 113 |
+ if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
|
|
| 114 |
+ job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
|
|
| 115 |
+ } |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 118 |
+ // We can always try removing the iptables |
|
| 119 |
+ if err := iptables.RemoveExistingChain("DOCKER"); err != nil {
|
|
| 120 |
+ job.Error(err) |
|
| 121 |
+ return engine.StatusErr |
|
| 122 |
+ } |
|
| 123 |
+ |
|
| 124 |
+ if enableIPTables {
|
|
| 125 |
+ chain, err := iptables.NewChain("DOCKER", bridgeIface)
|
|
| 126 |
+ if err != nil {
|
|
| 127 |
+ job.Error(err) |
|
| 128 |
+ return engine.StatusErr |
|
| 129 |
+ } |
|
| 130 |
+ portmapper.SetIptablesChain(chain) |
|
| 131 |
+ } |
|
| 132 |
+ |
|
| 133 |
+ bridgeNetwork = network |
|
| 134 |
+ |
|
| 135 |
+ // https://github.com/dotcloud/docker/issues/2768 |
|
| 136 |
+ job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeNetwork.IP)
|
|
| 137 |
+ |
|
| 138 |
+ for name, f := range map[string]engine.Handler{
|
|
| 139 |
+ "allocate_interface": Allocate, |
|
| 140 |
+ "release_interface": Release, |
|
| 141 |
+ "allocate_port": AllocatePort, |
|
| 142 |
+ "link": LinkContainers, |
|
| 143 |
+ } {
|
|
| 144 |
+ if err := job.Eng.Register(name, f); err != nil {
|
|
| 145 |
+ job.Error(err) |
|
| 146 |
+ return engine.StatusErr |
|
| 147 |
+ } |
|
| 148 |
+ } |
|
| 149 |
+ return engine.StatusOK |
|
| 150 |
+} |
|
| 151 |
+ |
|
| 152 |
+func setupIPTables(addr net.Addr, icc bool) error {
|
|
| 153 |
+ // Enable NAT |
|
| 154 |
+ natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-d", addr.String(), "-j", "MASQUERADE"}
|
|
| 155 |
+ |
|
| 156 |
+ if !iptables.Exists(natArgs...) {
|
|
| 157 |
+ if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
|
|
| 158 |
+ return fmt.Errorf("Unable to enable network bridge NAT: %s", err)
|
|
| 159 |
+ } else if len(output) != 0 {
|
|
| 160 |
+ return fmt.Errorf("Error iptables postrouting: %s", output)
|
|
| 161 |
+ } |
|
| 162 |
+ } |
|
| 163 |
+ |
|
| 164 |
+ var ( |
|
| 165 |
+ args = []string{"FORWARD", "-i", bridgeIface, "-o", bridgeIface, "-j"}
|
|
| 166 |
+ acceptArgs = append(args, "ACCEPT") |
|
| 167 |
+ dropArgs = append(args, "DROP") |
|
| 168 |
+ ) |
|
| 169 |
+ |
|
| 170 |
+ if !icc {
|
|
| 171 |
+ iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
|
|
| 172 |
+ |
|
| 173 |
+ if !iptables.Exists(dropArgs...) {
|
|
| 174 |
+ |
|
| 175 |
+ utils.Debugf("Disable inter-container communication")
|
|
| 176 |
+ if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
|
|
| 177 |
+ return fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
|
|
| 178 |
+ } else if len(output) != 0 {
|
|
| 179 |
+ return fmt.Errorf("Error disabling intercontainer communication: %s", output)
|
|
| 180 |
+ } |
|
| 181 |
+ } |
|
| 182 |
+ } else {
|
|
| 183 |
+ iptables.Raw(append([]string{"-D"}, dropArgs...)...)
|
|
| 184 |
+ |
|
| 185 |
+ if !iptables.Exists(acceptArgs...) {
|
|
| 186 |
+ utils.Debugf("Enable inter-container communication")
|
|
| 187 |
+ if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
|
|
| 188 |
+ return fmt.Errorf("Unable to allow intercontainer communication: %s", err)
|
|
| 189 |
+ } else if len(output) != 0 {
|
|
| 190 |
+ return fmt.Errorf("Error enabling intercontainer communication: %s", output)
|
|
| 191 |
+ } |
|
| 192 |
+ } |
|
| 193 |
+ } |
|
| 194 |
+ |
|
| 195 |
+ // Accept all non-intercontainer outgoing packets |
|
| 196 |
+ outgoingArgs := []string{"FORWARD", "-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}
|
|
| 197 |
+ if !iptables.Exists(outgoingArgs...) {
|
|
| 198 |
+ if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
|
|
| 199 |
+ return fmt.Errorf("Unable to allow outgoing packets: %s", err)
|
|
| 200 |
+ } else if len(output) != 0 {
|
|
| 201 |
+ return fmt.Errorf("Error iptables allow outgoing: %s", output)
|
|
| 202 |
+ } |
|
| 203 |
+ } |
|
| 204 |
+ |
|
| 205 |
+ // Accept incoming packets for existing connections |
|
| 206 |
+ existingArgs := []string{"FORWARD", "-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
|
|
| 207 |
+ |
|
| 208 |
+ if !iptables.Exists(existingArgs...) {
|
|
| 209 |
+ if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
|
|
| 210 |
+ return fmt.Errorf("Unable to allow incoming packets: %s", err)
|
|
| 211 |
+ } else if len(output) != 0 {
|
|
| 212 |
+ return fmt.Errorf("Error iptables allow incoming: %s", output)
|
|
| 213 |
+ } |
|
| 214 |
+ } |
|
| 215 |
+ return nil |
|
| 216 |
+} |
|
| 217 |
+ |
|
| 218 |
+// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`, |
|
| 219 |
+// and attempts to configure it with an address which doesn't conflict with any other interface on the host. |
|
| 220 |
+// If it can't find an address which doesn't conflict, it will return an error. |
|
| 221 |
+func createBridge(bridgeIP string) error {
|
|
| 222 |
+ nameservers := []string{}
|
|
| 223 |
+ resolvConf, _ := utils.GetResolvConf() |
|
| 224 |
+ // we don't check for an error here, because we don't really care |
|
| 225 |
+ // if we can't read /etc/resolv.conf. So instead we skip the append |
|
| 226 |
+ // if resolvConf is nil. It either doesn't exist, or we can't read it |
|
| 227 |
+ // for some reason. |
|
| 228 |
+ if resolvConf != nil {
|
|
| 229 |
+ nameservers = append(nameservers, utils.GetNameserversAsCIDR(resolvConf)...) |
|
| 230 |
+ } |
|
| 231 |
+ |
|
| 232 |
+ var ifaceAddr string |
|
| 233 |
+ if len(bridgeIP) != 0 {
|
|
| 234 |
+ _, _, err := net.ParseCIDR(bridgeIP) |
|
| 235 |
+ if err != nil {
|
|
| 236 |
+ return err |
|
| 237 |
+ } |
|
| 238 |
+ ifaceAddr = bridgeIP |
|
| 239 |
+ } else {
|
|
| 240 |
+ for _, addr := range addrs {
|
|
| 241 |
+ _, dockerNetwork, err := net.ParseCIDR(addr) |
|
| 242 |
+ if err != nil {
|
|
| 243 |
+ return err |
|
| 244 |
+ } |
|
| 245 |
+ if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
|
|
| 246 |
+ if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
|
|
| 247 |
+ ifaceAddr = addr |
|
| 248 |
+ break |
|
| 249 |
+ } else {
|
|
| 250 |
+ utils.Debugf("%s %s", addr, err)
|
|
| 251 |
+ } |
|
| 252 |
+ } |
|
| 253 |
+ } |
|
| 254 |
+ } |
|
| 255 |
+ |
|
| 256 |
+ if ifaceAddr == "" {
|
|
| 257 |
+ return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", bridgeIface, bridgeIface)
|
|
| 258 |
+ } |
|
| 259 |
+ utils.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr)
|
|
| 260 |
+ |
|
| 261 |
+ if err := createBridgeIface(bridgeIface); err != nil {
|
|
| 262 |
+ return err |
|
| 263 |
+ } |
|
| 264 |
+ |
|
| 265 |
+ iface, err := net.InterfaceByName(bridgeIface) |
|
| 266 |
+ if err != nil {
|
|
| 267 |
+ return err |
|
| 268 |
+ } |
|
| 269 |
+ |
|
| 270 |
+ ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr) |
|
| 271 |
+ if err != nil {
|
|
| 272 |
+ return err |
|
| 273 |
+ } |
|
| 274 |
+ |
|
| 275 |
+ if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
|
|
| 276 |
+ return fmt.Errorf("Unable to add private network: %s", err)
|
|
| 277 |
+ } |
|
| 278 |
+ if err := netlink.NetworkLinkUp(iface); err != nil {
|
|
| 279 |
+ return fmt.Errorf("Unable to start network bridge: %s", err)
|
|
| 280 |
+ } |
|
| 281 |
+ return nil |
|
| 282 |
+} |
|
| 283 |
+ |
|
| 284 |
+// Create the actual bridge device. This is more backward-compatible than |
|
| 285 |
+// netlink.NetworkLinkAdd and works on RHEL 6. |
|
| 286 |
+func createBridgeIface(name string) error {
|
|
| 287 |
+ s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP) |
|
| 288 |
+ if err != nil {
|
|
| 289 |
+ utils.Debugf("Bridge socket creation failed IPv6 probably not enabled: %v", err)
|
|
| 290 |
+ s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP) |
|
| 291 |
+ if err != nil {
|
|
| 292 |
+ return fmt.Errorf("Error creating bridge creation socket: %s", err)
|
|
| 293 |
+ } |
|
| 294 |
+ } |
|
| 295 |
+ defer syscall.Close(s) |
|
| 296 |
+ |
|
| 297 |
+ nameBytePtr, err := syscall.BytePtrFromString(name) |
|
| 298 |
+ if err != nil {
|
|
| 299 |
+ return fmt.Errorf("Error converting bridge name %s to byte array: %s", name, err)
|
|
| 300 |
+ } |
|
| 301 |
+ |
|
| 302 |
+ if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), siocBRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
|
|
| 303 |
+ return fmt.Errorf("Error creating bridge: %s", err)
|
|
| 304 |
+ } |
|
| 305 |
+ return nil |
|
| 306 |
+} |
|
| 307 |
+ |
|
| 308 |
+// Allocate a network interface |
|
| 309 |
+func Allocate(job *engine.Job) engine.Status {
|
|
| 310 |
+ var ( |
|
| 311 |
+ ip *net.IP |
|
| 312 |
+ err error |
|
| 313 |
+ id = job.Args[0] |
|
| 314 |
+ requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
|
|
| 315 |
+ ) |
|
| 316 |
+ |
|
| 317 |
+ if requestedIP != nil {
|
|
| 318 |
+ ip, err = ipallocator.RequestIP(bridgeNetwork, &requestedIP) |
|
| 319 |
+ } else {
|
|
| 320 |
+ ip, err = ipallocator.RequestIP(bridgeNetwork, nil) |
|
| 321 |
+ } |
|
| 322 |
+ if err != nil {
|
|
| 323 |
+ job.Error(err) |
|
| 324 |
+ return engine.StatusErr |
|
| 325 |
+ } |
|
| 326 |
+ |
|
| 327 |
+ out := engine.Env{}
|
|
| 328 |
+ out.Set("IP", ip.String())
|
|
| 329 |
+ out.Set("Mask", bridgeNetwork.Mask.String())
|
|
| 330 |
+ out.Set("Gateway", bridgeNetwork.IP.String())
|
|
| 331 |
+ out.Set("Bridge", bridgeIface)
|
|
| 332 |
+ |
|
| 333 |
+ size, _ := bridgeNetwork.Mask.Size() |
|
| 334 |
+ out.SetInt("IPPrefixLen", size)
|
|
| 335 |
+ |
|
| 336 |
+ currentInterfaces[id] = &networkInterface{
|
|
| 337 |
+ IP: *ip, |
|
| 338 |
+ } |
|
| 339 |
+ |
|
| 340 |
+ out.WriteTo(job.Stdout) |
|
| 341 |
+ |
|
| 342 |
+ return engine.StatusOK |
|
| 343 |
+} |
|
| 344 |
+ |
|
| 345 |
+// release an interface for a select ip |
|
| 346 |
+func Release(job *engine.Job) engine.Status {
|
|
| 347 |
+ var ( |
|
| 348 |
+ id = job.Args[0] |
|
| 349 |
+ containerInterface = currentInterfaces[id] |
|
| 350 |
+ ip net.IP |
|
| 351 |
+ port int |
|
| 352 |
+ proto string |
|
| 353 |
+ ) |
|
| 354 |
+ |
|
| 355 |
+ for _, nat := range containerInterface.PortMappings {
|
|
| 356 |
+ if err := portmapper.Unmap(nat); err != nil {
|
|
| 357 |
+ log.Printf("Unable to unmap port %s: %s", nat, err)
|
|
| 358 |
+ } |
|
| 359 |
+ |
|
| 360 |
+ // this is host mappings |
|
| 361 |
+ switch a := nat.(type) {
|
|
| 362 |
+ case *net.TCPAddr: |
|
| 363 |
+ proto = "tcp" |
|
| 364 |
+ ip = a.IP |
|
| 365 |
+ port = a.Port |
|
| 366 |
+ case *net.UDPAddr: |
|
| 367 |
+ proto = "udp" |
|
| 368 |
+ ip = a.IP |
|
| 369 |
+ port = a.Port |
|
| 370 |
+ } |
|
| 371 |
+ |
|
| 372 |
+ if err := portallocator.ReleasePort(ip, proto, port); err != nil {
|
|
| 373 |
+ log.Printf("Unable to release port %s", nat)
|
|
| 374 |
+ } |
|
| 375 |
+ } |
|
| 376 |
+ |
|
| 377 |
+ if err := ipallocator.ReleaseIP(bridgeNetwork, &containerInterface.IP); err != nil {
|
|
| 378 |
+ log.Printf("Unable to release ip %s\n", err)
|
|
| 379 |
+ } |
|
| 380 |
+ return engine.StatusOK |
|
| 381 |
+} |
|
| 382 |
+ |
|
| 383 |
+// Allocate an external port and map it to the interface |
|
| 384 |
+func AllocatePort(job *engine.Job) engine.Status {
|
|
| 385 |
+ var ( |
|
| 386 |
+ err error |
|
| 387 |
+ |
|
| 388 |
+ ip = defaultBindingIP |
|
| 389 |
+ id = job.Args[0] |
|
| 390 |
+ hostIP = job.Getenv("HostIP")
|
|
| 391 |
+ hostPort = job.GetenvInt("HostPort")
|
|
| 392 |
+ containerPort = job.GetenvInt("ContainerPort")
|
|
| 393 |
+ proto = job.Getenv("Proto")
|
|
| 394 |
+ network = currentInterfaces[id] |
|
| 395 |
+ ) |
|
| 396 |
+ |
|
| 397 |
+ if hostIP != "" {
|
|
| 398 |
+ ip = net.ParseIP(hostIP) |
|
| 399 |
+ } |
|
| 400 |
+ |
|
| 401 |
+ // host ip, proto, and host port |
|
| 402 |
+ hostPort, err = portallocator.RequestPort(ip, proto, hostPort) |
|
| 403 |
+ if err != nil {
|
|
| 404 |
+ job.Error(err) |
|
| 405 |
+ return engine.StatusErr |
|
| 406 |
+ } |
|
| 407 |
+ |
|
| 408 |
+ var ( |
|
| 409 |
+ container net.Addr |
|
| 410 |
+ host net.Addr |
|
| 411 |
+ ) |
|
| 412 |
+ |
|
| 413 |
+ if proto == "tcp" {
|
|
| 414 |
+ host = &net.TCPAddr{IP: ip, Port: hostPort}
|
|
| 415 |
+ container = &net.TCPAddr{IP: network.IP, Port: containerPort}
|
|
| 416 |
+ } else {
|
|
| 417 |
+ host = &net.UDPAddr{IP: ip, Port: hostPort}
|
|
| 418 |
+ container = &net.UDPAddr{IP: network.IP, Port: containerPort}
|
|
| 419 |
+ } |
|
| 420 |
+ |
|
| 421 |
+ if err := portmapper.Map(container, ip, hostPort); err != nil {
|
|
| 422 |
+ portallocator.ReleasePort(ip, proto, hostPort) |
|
| 423 |
+ |
|
| 424 |
+ job.Error(err) |
|
| 425 |
+ return engine.StatusErr |
|
| 426 |
+ } |
|
| 427 |
+ network.PortMappings = append(network.PortMappings, host) |
|
| 428 |
+ |
|
| 429 |
+ out := engine.Env{}
|
|
| 430 |
+ out.Set("HostIP", ip.String())
|
|
| 431 |
+ out.SetInt("HostPort", hostPort)
|
|
| 432 |
+ |
|
| 433 |
+ if _, err := out.WriteTo(job.Stdout); err != nil {
|
|
| 434 |
+ job.Error(err) |
|
| 435 |
+ return engine.StatusErr |
|
| 436 |
+ } |
|
| 437 |
+ return engine.StatusOK |
|
| 438 |
+} |
|
| 439 |
+ |
|
| 440 |
+func LinkContainers(job *engine.Job) engine.Status {
|
|
| 441 |
+ var ( |
|
| 442 |
+ action = job.Args[0] |
|
| 443 |
+ childIP = job.Getenv("ChildIP")
|
|
| 444 |
+ parentIP = job.Getenv("ParentIP")
|
|
| 445 |
+ ignoreErrors = job.GetenvBool("IgnoreErrors")
|
|
| 446 |
+ ports = job.GetenvList("Ports")
|
|
| 447 |
+ ) |
|
| 448 |
+ split := func(p string) (string, string) {
|
|
| 449 |
+ parts := strings.Split(p, "/") |
|
| 450 |
+ return parts[0], parts[1] |
|
| 451 |
+ } |
|
| 452 |
+ |
|
| 453 |
+ for _, p := range ports {
|
|
| 454 |
+ port, proto := split(p) |
|
| 455 |
+ if output, err := iptables.Raw(action, "FORWARD", |
|
| 456 |
+ "-i", bridgeIface, "-o", bridgeIface, |
|
| 457 |
+ "-p", proto, |
|
| 458 |
+ "-s", parentIP, |
|
| 459 |
+ "--dport", port, |
|
| 460 |
+ "-d", childIP, |
|
| 461 |
+ "-j", "ACCEPT"); !ignoreErrors && err != nil {
|
|
| 462 |
+ job.Error(err) |
|
| 463 |
+ return engine.StatusErr |
|
| 464 |
+ } else if len(output) != 0 {
|
|
| 465 |
+ job.Errorf("Error toggle iptables forward: %s", output)
|
|
| 466 |
+ return engine.StatusErr |
|
| 467 |
+ } |
|
| 468 |
+ } |
|
| 469 |
+ return engine.StatusOK |
|
| 470 |
+} |
| ... | ... |
@@ -1,80 +1,10 @@ |
| 1 | 1 |
package networkdriver |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "encoding/binary" |
|
| 5 | 4 |
"errors" |
| 6 |
- "github.com/dotcloud/docker/pkg/netlink" |
|
| 7 |
- "net" |
|
| 8 | 5 |
) |
| 9 | 6 |
|
| 10 | 7 |
var ( |
| 11 | 8 |
ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
|
| 12 | 9 |
ErrNetworkOverlaps = errors.New("requested network overlaps with existing network")
|
| 13 | 10 |
) |
| 14 |
- |
|
| 15 |
-var ( |
|
| 16 |
- networkGetRoutesFct = netlink.NetworkGetRoutes |
|
| 17 |
-) |
|
| 18 |
- |
|
| 19 |
-func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
|
|
| 20 |
- if len(nameservers) > 0 {
|
|
| 21 |
- for _, ns := range nameservers {
|
|
| 22 |
- _, nsNetwork, err := net.ParseCIDR(ns) |
|
| 23 |
- if err != nil {
|
|
| 24 |
- return err |
|
| 25 |
- } |
|
| 26 |
- if NetworkOverlaps(toCheck, nsNetwork) {
|
|
| 27 |
- return ErrNetworkOverlapsWithNameservers |
|
| 28 |
- } |
|
| 29 |
- } |
|
| 30 |
- } |
|
| 31 |
- return nil |
|
| 32 |
-} |
|
| 33 |
- |
|
| 34 |
-func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
|
| 35 |
- networks, err := networkGetRoutesFct() |
|
| 36 |
- if err != nil {
|
|
| 37 |
- return err |
|
| 38 |
- } |
|
| 39 |
- |
|
| 40 |
- for _, network := range networks {
|
|
| 41 |
- if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
|
|
| 42 |
- return ErrNetworkOverlaps |
|
| 43 |
- } |
|
| 44 |
- } |
|
| 45 |
- return nil |
|
| 46 |
-} |
|
| 47 |
- |
|
| 48 |
-// Detects overlap between one IPNet and another |
|
| 49 |
-func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
|
| 50 |
- if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
|
|
| 51 |
- return true |
|
| 52 |
- } |
|
| 53 |
- if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
|
|
| 54 |
- return true |
|
| 55 |
- } |
|
| 56 |
- return false |
|
| 57 |
-} |
|
| 58 |
- |
|
| 59 |
-// Calculates the first and last IP addresses in an IPNet |
|
| 60 |
-func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
|
|
| 61 |
- var ( |
|
| 62 |
- netIP = network.IP.To4() |
|
| 63 |
- firstIP = netIP.Mask(network.Mask) |
|
| 64 |
- lastIP = net.IPv4(0, 0, 0, 0).To4() |
|
| 65 |
- ) |
|
| 66 |
- |
|
| 67 |
- for i := 0; i < len(lastIP); i++ {
|
|
| 68 |
- lastIP[i] = netIP[i] | ^network.Mask[i] |
|
| 69 |
- } |
|
| 70 |
- return firstIP, lastIP |
|
| 71 |
-} |
|
| 72 |
- |
|
| 73 |
-// Given a netmask, calculates the number of available hosts |
|
| 74 |
-func NetworkSize(mask net.IPMask) int32 {
|
|
| 75 |
- m := net.IPv4Mask(0, 0, 0, 0) |
|
| 76 |
- for i := 0; i < net.IPv4len; i++ {
|
|
| 77 |
- m[i] = ^mask[i] |
|
| 78 |
- } |
|
| 79 |
- return int32(binary.BigEndian.Uint32(m)) + 1 |
|
| 80 |
-} |
| 58 | 58 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,102 @@ |
| 0 |
+package networkdriver |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/binary" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "github.com/dotcloud/docker/pkg/netlink" |
|
| 6 |
+ "net" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+var ( |
|
| 10 |
+ networkGetRoutesFct = netlink.NetworkGetRoutes |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 13 |
+func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
|
|
| 14 |
+ if len(nameservers) > 0 {
|
|
| 15 |
+ for _, ns := range nameservers {
|
|
| 16 |
+ _, nsNetwork, err := net.ParseCIDR(ns) |
|
| 17 |
+ if err != nil {
|
|
| 18 |
+ return err |
|
| 19 |
+ } |
|
| 20 |
+ if NetworkOverlaps(toCheck, nsNetwork) {
|
|
| 21 |
+ return ErrNetworkOverlapsWithNameservers |
|
| 22 |
+ } |
|
| 23 |
+ } |
|
| 24 |
+ } |
|
| 25 |
+ return nil |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
|
| 29 |
+ networks, err := networkGetRoutesFct() |
|
| 30 |
+ if err != nil {
|
|
| 31 |
+ return err |
|
| 32 |
+ } |
|
| 33 |
+ |
|
| 34 |
+ for _, network := range networks {
|
|
| 35 |
+ if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
|
|
| 36 |
+ return ErrNetworkOverlaps |
|
| 37 |
+ } |
|
| 38 |
+ } |
|
| 39 |
+ return nil |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+// Detects overlap between one IPNet and another |
|
| 43 |
+func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
|
| 44 |
+ if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
|
|
| 45 |
+ return true |
|
| 46 |
+ } |
|
| 47 |
+ if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
|
|
| 48 |
+ return true |
|
| 49 |
+ } |
|
| 50 |
+ return false |
|
| 51 |
+} |
|
| 52 |
+ |
|
| 53 |
+// Calculates the first and last IP addresses in an IPNet |
|
| 54 |
+func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
|
|
| 55 |
+ var ( |
|
| 56 |
+ netIP = network.IP.To4() |
|
| 57 |
+ firstIP = netIP.Mask(network.Mask) |
|
| 58 |
+ lastIP = net.IPv4(0, 0, 0, 0).To4() |
|
| 59 |
+ ) |
|
| 60 |
+ |
|
| 61 |
+ for i := 0; i < len(lastIP); i++ {
|
|
| 62 |
+ lastIP[i] = netIP[i] | ^network.Mask[i] |
|
| 63 |
+ } |
|
| 64 |
+ return firstIP, lastIP |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+// Given a netmask, calculates the number of available hosts |
|
| 68 |
+func NetworkSize(mask net.IPMask) int32 {
|
|
| 69 |
+ m := net.IPv4Mask(0, 0, 0, 0) |
|
| 70 |
+ for i := 0; i < net.IPv4len; i++ {
|
|
| 71 |
+ m[i] = ^mask[i] |
|
| 72 |
+ } |
|
| 73 |
+ return int32(binary.BigEndian.Uint32(m)) + 1 |
|
| 74 |
+} |
|
| 75 |
+ |
|
| 76 |
+// Return the IPv4 address of a network interface |
|
| 77 |
+func GetIfaceAddr(name string) (net.Addr, error) {
|
|
| 78 |
+ iface, err := net.InterfaceByName(name) |
|
| 79 |
+ if err != nil {
|
|
| 80 |
+ return nil, err |
|
| 81 |
+ } |
|
| 82 |
+ addrs, err := iface.Addrs() |
|
| 83 |
+ if err != nil {
|
|
| 84 |
+ return nil, err |
|
| 85 |
+ } |
|
| 86 |
+ var addrs4 []net.Addr |
|
| 87 |
+ for _, addr := range addrs {
|
|
| 88 |
+ ip := (addr.(*net.IPNet)).IP |
|
| 89 |
+ if ip4 := ip.To4(); len(ip4) == net.IPv4len {
|
|
| 90 |
+ addrs4 = append(addrs4, addr) |
|
| 91 |
+ } |
|
| 92 |
+ } |
|
| 93 |
+ switch {
|
|
| 94 |
+ case len(addrs4) == 0: |
|
| 95 |
+ return nil, fmt.Errorf("Interface %v has no IP addresses", name)
|
|
| 96 |
+ case len(addrs4) > 1: |
|
| 97 |
+ fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
|
|
| 98 |
+ name, (addrs4[0].(*net.IPNet)).IP) |
|
| 99 |
+ } |
|
| 100 |
+ return addrs4[0], nil |
|
| 101 |
+} |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"container/list" |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"github.com/dotcloud/docker/archive" |
| 7 |
+ "github.com/dotcloud/docker/engine" |
|
| 7 | 8 |
"github.com/dotcloud/docker/execdriver" |
| 8 | 9 |
"github.com/dotcloud/docker/execdriver/chroot" |
| 9 | 10 |
"github.com/dotcloud/docker/execdriver/lxc" |
| ... | ... |
@@ -12,6 +13,7 @@ import ( |
| 12 | 12 |
_ "github.com/dotcloud/docker/graphdriver/btrfs" |
| 13 | 13 |
_ "github.com/dotcloud/docker/graphdriver/devmapper" |
| 14 | 14 |
_ "github.com/dotcloud/docker/graphdriver/vfs" |
| 15 |
+ _ "github.com/dotcloud/docker/networkdriver/lxc" |
|
| 15 | 16 |
"github.com/dotcloud/docker/networkdriver/portallocator" |
| 16 | 17 |
"github.com/dotcloud/docker/pkg/graphdb" |
| 17 | 18 |
"github.com/dotcloud/docker/pkg/sysinfo" |
| ... | ... |
@@ -42,13 +44,13 @@ type Runtime struct {
|
| 42 | 42 |
repository string |
| 43 | 43 |
sysInitPath string |
| 44 | 44 |
containers *list.List |
| 45 |
- networkManager *NetworkManager |
|
| 46 | 45 |
graph *Graph |
| 47 | 46 |
repositories *TagStore |
| 48 | 47 |
idIndex *utils.TruncIndex |
| 49 | 48 |
sysInfo *sysinfo.SysInfo |
| 50 | 49 |
volumes *Graph |
| 51 | 50 |
srv *Server |
| 51 |
+ eng *engine.Engine |
|
| 52 | 52 |
config *DaemonConfig |
| 53 | 53 |
containerGraph *graphdb.Database |
| 54 | 54 |
driver graphdriver.Driver |
| ... | ... |
@@ -609,15 +611,15 @@ func (runtime *Runtime) RegisterLink(parent, child *Container, alias string) err |
| 609 | 609 |
} |
| 610 | 610 |
|
| 611 | 611 |
// FIXME: harmonize with NewGraph() |
| 612 |
-func NewRuntime(config *DaemonConfig) (*Runtime, error) {
|
|
| 613 |
- runtime, err := NewRuntimeFromDirectory(config) |
|
| 612 |
+func NewRuntime(config *DaemonConfig, eng *engine.Engine) (*Runtime, error) {
|
|
| 613 |
+ runtime, err := NewRuntimeFromDirectory(config, eng) |
|
| 614 | 614 |
if err != nil {
|
| 615 | 615 |
return nil, err |
| 616 | 616 |
} |
| 617 | 617 |
return runtime, nil |
| 618 | 618 |
} |
| 619 | 619 |
|
| 620 |
-func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
|
|
| 620 |
+func NewRuntimeFromDirectory(config *DaemonConfig, eng *engine.Engine) (*Runtime, error) {
|
|
| 621 | 621 |
|
| 622 | 622 |
// Set the default driver |
| 623 | 623 |
graphdriver.DefaultDriver = config.GraphDriver |
| ... | ... |
@@ -664,12 +666,20 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
|
| 664 | 664 |
if err != nil {
|
| 665 | 665 |
return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
|
| 666 | 666 |
} |
| 667 |
- if config.BridgeIface == "" {
|
|
| 668 |
- config.BridgeIface = DefaultNetworkBridge |
|
| 669 |
- } |
|
| 670 |
- netManager, err := newNetworkManager(config) |
|
| 671 |
- if err != nil {
|
|
| 672 |
- return nil, err |
|
| 667 |
+ |
|
| 668 |
+ if !config.DisableNetwork {
|
|
| 669 |
+ job := eng.Job("init_networkdriver")
|
|
| 670 |
+ |
|
| 671 |
+ job.SetenvBool("EnableIptables", config.EnableIptables)
|
|
| 672 |
+ job.SetenvBool("InterContainerCommunication", config.InterContainerCommunication)
|
|
| 673 |
+ job.SetenvBool("EnableIpForward", config.EnableIpForward)
|
|
| 674 |
+ job.Setenv("BridgeIface", config.BridgeIface)
|
|
| 675 |
+ job.Setenv("BridgeIP", config.BridgeIP)
|
|
| 676 |
+ job.Setenv("DefaultBindingIP", config.DefaultIp.String())
|
|
| 677 |
+ |
|
| 678 |
+ if err := job.Run(); err != nil {
|
|
| 679 |
+ return nil, err |
|
| 680 |
+ } |
|
| 673 | 681 |
} |
| 674 | 682 |
|
| 675 | 683 |
graphdbPath := path.Join(config.Root, "linkgraph.db") |
| ... | ... |
@@ -721,7 +731,6 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
|
| 721 | 721 |
runtime := &Runtime{
|
| 722 | 722 |
repository: runtimeRepo, |
| 723 | 723 |
containers: list.New(), |
| 724 |
- networkManager: netManager, |
|
| 725 | 724 |
graph: g, |
| 726 | 725 |
repositories: repositories, |
| 727 | 726 |
idIndex: utils.NewTruncIndex(), |
| ... | ... |
@@ -732,6 +741,7 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
|
| 732 | 732 |
driver: driver, |
| 733 | 733 |
sysInitPath: sysInitPath, |
| 734 | 734 |
execDriver: ed, |
| 735 |
+ eng: eng, |
|
| 735 | 736 |
} |
| 736 | 737 |
|
| 737 | 738 |
if err := runtime.restore(); err != nil {
|
| ... | ... |
@@ -64,10 +64,7 @@ func jobInitServer(job *engine.Job) engine.Status {
|
| 64 | 64 |
}() |
| 65 | 65 |
job.Eng.Hack_SetGlobalVar("httpapi.server", srv)
|
| 66 | 66 |
job.Eng.Hack_SetGlobalVar("httpapi.runtime", srv.runtime)
|
| 67 |
- // https://github.com/dotcloud/docker/issues/2768 |
|
| 68 |
- if srv.runtime.networkManager.bridgeNetwork != nil {
|
|
| 69 |
- job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", srv.runtime.networkManager.bridgeNetwork.IP)
|
|
| 70 |
- } |
|
| 67 |
+ |
|
| 71 | 68 |
for name, handler := range map[string]engine.Handler{
|
| 72 | 69 |
"export": srv.ContainerExport, |
| 73 | 70 |
"create": srv.ContainerCreate, |
| ... | ... |
@@ -2325,7 +2322,7 @@ func (srv *Server) ContainerCopy(job *engine.Job) engine.Status {
|
| 2325 | 2325 |
} |
| 2326 | 2326 |
|
| 2327 | 2327 |
func NewServer(eng *engine.Engine, config *DaemonConfig) (*Server, error) {
|
| 2328 |
- runtime, err := NewRuntime(config) |
|
| 2328 |
+ runtime, err := NewRuntime(config, eng) |
|
| 2329 | 2329 |
if err != nil {
|
| 2330 | 2330 |
return nil, err |
| 2331 | 2331 |
} |