github.com/erriapo/docker@v1.6.0-rc2/daemon/networkdriver/bridge/driver_test.go (about) 1 package bridge 2 3 import ( 4 "fmt" 5 "net" 6 "strconv" 7 "testing" 8 9 "github.com/docker/docker/daemon/networkdriver/portmapper" 10 "github.com/docker/docker/engine" 11 "github.com/docker/docker/pkg/iptables" 12 ) 13 14 func init() { 15 // reset the new proxy command for mocking out the userland proxy in tests 16 portmapper.NewProxy = portmapper.NewMockProxyCommand 17 } 18 19 func findFreePort(t *testing.T) int { 20 l, err := net.Listen("tcp", ":0") 21 if err != nil { 22 t.Fatal("Failed to find a free port") 23 } 24 defer l.Close() 25 26 result, err := net.ResolveTCPAddr("tcp", l.Addr().String()) 27 if err != nil { 28 t.Fatal("Failed to resolve address to identify free port") 29 } 30 return result.Port 31 } 32 33 func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) { 34 strPort := strconv.Itoa(port) 35 36 job = eng.Job("allocate_port", "container_id") 37 job.Setenv("HostIP", "127.0.0.1") 38 job.Setenv("HostPort", strPort) 39 job.Setenv("Proto", "tcp") 40 job.Setenv("ContainerPort", strPort) 41 return 42 } 43 44 func newPortAllocationJobWithInvalidHostIP(eng *engine.Engine, port int) (job *engine.Job) { 45 strPort := strconv.Itoa(port) 46 47 job = eng.Job("allocate_port", "container_id") 48 job.Setenv("HostIP", "localhost") 49 job.Setenv("HostPort", strPort) 50 job.Setenv("Proto", "tcp") 51 job.Setenv("ContainerPort", strPort) 52 return 53 } 54 55 func TestAllocatePortDetection(t *testing.T) { 56 eng := engine.New() 57 eng.Logging = false 58 59 freePort := findFreePort(t) 60 61 // Init driver 62 job := eng.Job("initdriver") 63 if res := InitDriver(job); res != engine.StatusOK { 64 t.Fatal("Failed to initialize network driver") 65 } 66 67 // Allocate interface 68 job = eng.Job("allocate_interface", "container_id") 69 if res := Allocate(job); res != engine.StatusOK { 70 t.Fatal("Failed to allocate network interface") 71 } 72 73 // Allocate same port twice, expect failure on second call 74 job = newPortAllocationJob(eng, freePort) 75 if res := AllocatePort(job); res != engine.StatusOK { 76 t.Fatal("Failed to find a free port to allocate") 77 } 78 if res := AllocatePort(job); res == engine.StatusOK { 79 t.Fatal("Duplicate port allocation granted by AllocatePort") 80 } 81 } 82 83 func TestHostnameFormatChecking(t *testing.T) { 84 eng := engine.New() 85 eng.Logging = false 86 87 freePort := findFreePort(t) 88 89 // Init driver 90 job := eng.Job("initdriver") 91 if res := InitDriver(job); res != engine.StatusOK { 92 t.Fatal("Failed to initialize network driver") 93 } 94 95 // Allocate interface 96 job = eng.Job("allocate_interface", "container_id") 97 if res := Allocate(job); res != engine.StatusOK { 98 t.Fatal("Failed to allocate network interface") 99 } 100 101 // Allocate port with invalid HostIP, expect failure with Bad Request http status 102 job = newPortAllocationJobWithInvalidHostIP(eng, freePort) 103 if res := AllocatePort(job); res == engine.StatusOK { 104 t.Fatal("Failed to check invalid HostIP") 105 } 106 } 107 108 func newInterfaceAllocation(t *testing.T, input engine.Env) (output engine.Env) { 109 eng := engine.New() 110 eng.Logging = false 111 112 done := make(chan bool) 113 114 // set IPv6 global if given 115 if input.Exists("globalIPv6Network") { 116 _, globalIPv6Network, _ = net.ParseCIDR(input.Get("globalIPv6Network")) 117 } 118 119 job := eng.Job("allocate_interface", "container_id") 120 job.Env().Init(&input) 121 reader, _ := job.Stdout.AddPipe() 122 go func() { 123 output.Decode(reader) 124 done <- true 125 }() 126 127 res := Allocate(job) 128 job.Stdout.Close() 129 <-done 130 131 if input.Exists("expectFail") && input.GetBool("expectFail") { 132 if res == engine.StatusOK { 133 t.Fatal("Doesn't fail to allocate network interface") 134 } 135 } else { 136 if res != engine.StatusOK { 137 t.Fatal("Failed to allocate network interface") 138 } 139 } 140 141 if input.Exists("globalIPv6Network") { 142 // check for bug #11427 143 _, subnet, _ := net.ParseCIDR(input.Get("globalIPv6Network")) 144 if globalIPv6Network.IP.String() != subnet.IP.String() { 145 t.Fatal("globalIPv6Network was modified during allocation") 146 } 147 // clean up IPv6 global 148 globalIPv6Network = nil 149 } 150 151 return 152 } 153 154 func TestIPv6InterfaceAllocationAutoNetmaskGt80(t *testing.T) { 155 156 input := engine.Env{} 157 158 _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/81") 159 160 // set global ipv6 161 input.Set("globalIPv6Network", subnet.String()) 162 163 output := newInterfaceAllocation(t, input) 164 165 // ensure low manually assigend global ip 166 ip := net.ParseIP(output.Get("GlobalIPv6")) 167 _, subnet, _ = net.ParseCIDR(fmt.Sprintf("%s/%d", subnet.IP.String(), 120)) 168 if !subnet.Contains(ip) { 169 t.Fatalf("Error ip %s not in subnet %s", ip.String(), subnet.String()) 170 } 171 } 172 173 func TestIPv6InterfaceAllocationAutoNetmaskLe80(t *testing.T) { 174 175 input := engine.Env{} 176 177 _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80") 178 179 // set global ipv6 180 input.Set("globalIPv6Network", subnet.String()) 181 input.Set("RequestedMac", "ab:cd:ab:cd:ab:cd") 182 183 output := newInterfaceAllocation(t, input) 184 185 // ensure global ip with mac 186 ip := net.ParseIP(output.Get("GlobalIPv6")) 187 expected_ip := net.ParseIP("2001:db8:1234:1234:1234:abcd:abcd:abcd") 188 if ip.String() != expected_ip.String() { 189 t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String()) 190 } 191 192 // ensure link local format 193 ip = net.ParseIP(output.Get("LinkLocalIPv6")) 194 expected_ip = net.ParseIP("fe80::a9cd:abff:fecd:abcd") 195 if ip.String() != expected_ip.String() { 196 t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String()) 197 } 198 199 } 200 201 func TestIPv6InterfaceAllocationRequest(t *testing.T) { 202 203 input := engine.Env{} 204 205 _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80") 206 expected_ip := net.ParseIP("2001:db8:1234:1234:1234::1328") 207 208 // set global ipv6 209 input.Set("globalIPv6Network", subnet.String()) 210 input.Set("RequestedIPv6", expected_ip.String()) 211 212 output := newInterfaceAllocation(t, input) 213 214 // ensure global ip with mac 215 ip := net.ParseIP(output.Get("GlobalIPv6")) 216 if ip.String() != expected_ip.String() { 217 t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String()) 218 } 219 220 // retry -> fails for duplicated address 221 input.SetBool("expectFail", true) 222 output = newInterfaceAllocation(t, input) 223 } 224 225 func TestMacAddrGeneration(t *testing.T) { 226 ip := net.ParseIP("192.168.0.1") 227 mac := generateMacAddr(ip).String() 228 229 // Should be consistent. 230 if generateMacAddr(ip).String() != mac { 231 t.Fatal("Inconsistent MAC address") 232 } 233 234 // Should be unique. 235 ip2 := net.ParseIP("192.168.0.2") 236 if generateMacAddr(ip2).String() == mac { 237 t.Fatal("Non-unique MAC address") 238 } 239 } 240 241 func TestLinkContainers(t *testing.T) { 242 eng := engine.New() 243 eng.Logging = false 244 245 // Init driver 246 job := eng.Job("initdriver") 247 if res := InitDriver(job); res != engine.StatusOK { 248 t.Fatal("Failed to initialize network driver") 249 } 250 251 // Allocate interface 252 job = eng.Job("allocate_interface", "container_id") 253 if res := Allocate(job); res != engine.StatusOK { 254 t.Fatal("Failed to allocate network interface") 255 } 256 257 job.Args[0] = "-I" 258 259 job.Setenv("ChildIP", "172.17.0.2") 260 job.Setenv("ParentIP", "172.17.0.1") 261 job.SetenvBool("IgnoreErrors", false) 262 job.SetenvList("Ports", []string{"1234"}) 263 264 bridgeIface = "lo" 265 _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) 266 if err != nil { 267 t.Fatal(err) 268 } 269 270 if res := LinkContainers(job); res != engine.StatusOK { 271 t.Fatalf("LinkContainers failed") 272 } 273 274 // flush rules 275 if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil { 276 t.Fatal(err) 277 } 278 279 }