github.com/rhatdan/docker@v0.7.7-0.20180119204836-47a0dcbcd20a/daemon/network.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "net" 6 "runtime" 7 "sort" 8 "strings" 9 "sync" 10 11 "github.com/docker/docker/api/types" 12 "github.com/docker/docker/api/types/network" 13 clustertypes "github.com/docker/docker/daemon/cluster/provider" 14 "github.com/docker/docker/errdefs" 15 "github.com/docker/docker/pkg/plugingetter" 16 "github.com/docker/docker/runconfig" 17 "github.com/docker/libnetwork" 18 lncluster "github.com/docker/libnetwork/cluster" 19 "github.com/docker/libnetwork/driverapi" 20 "github.com/docker/libnetwork/ipamapi" 21 networktypes "github.com/docker/libnetwork/types" 22 "github.com/pkg/errors" 23 "github.com/sirupsen/logrus" 24 "golang.org/x/net/context" 25 ) 26 27 // NetworkControllerEnabled checks if the networking stack is enabled. 28 // This feature depends on OS primitives and it's disabled in systems like Windows. 29 func (daemon *Daemon) NetworkControllerEnabled() bool { 30 return daemon.netController != nil 31 } 32 33 // FindNetwork returns a network based on: 34 // 1. Full ID 35 // 2. Full Name 36 // 3. Partial ID 37 // as long as there is no ambiguity 38 func (daemon *Daemon) FindNetwork(term string) (libnetwork.Network, error) { 39 listByFullName := []libnetwork.Network{} 40 listByPartialID := []libnetwork.Network{} 41 for _, nw := range daemon.GetNetworks() { 42 if nw.ID() == term { 43 return nw, nil 44 } 45 if nw.Name() == term { 46 listByFullName = append(listByFullName, nw) 47 } 48 if strings.HasPrefix(nw.ID(), term) { 49 listByPartialID = append(listByPartialID, nw) 50 } 51 } 52 switch { 53 case len(listByFullName) == 1: 54 return listByFullName[0], nil 55 case len(listByFullName) > 1: 56 return nil, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found on name)", term, len(listByFullName))) 57 case len(listByPartialID) == 1: 58 return listByPartialID[0], nil 59 case len(listByPartialID) > 1: 60 return nil, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID))) 61 } 62 63 // Be very careful to change the error type here, the 64 // libnetwork.ErrNoSuchNetwork error is used by the controller 65 // to retry the creation of the network as managed through the swarm manager 66 return nil, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term)) 67 } 68 69 // GetNetworkByID function returns a network whose ID matches the given ID. 70 // It fails with an error if no matching network is found. 71 func (daemon *Daemon) GetNetworkByID(id string) (libnetwork.Network, error) { 72 c := daemon.netController 73 if c == nil { 74 return nil, libnetwork.ErrNoSuchNetwork(id) 75 } 76 return c.NetworkByID(id) 77 } 78 79 // GetNetworkByName function returns a network for a given network name. 80 // If no network name is given, the default network is returned. 81 func (daemon *Daemon) GetNetworkByName(name string) (libnetwork.Network, error) { 82 c := daemon.netController 83 if c == nil { 84 return nil, libnetwork.ErrNoSuchNetwork(name) 85 } 86 if name == "" { 87 name = c.Config().Daemon.DefaultNetwork 88 } 89 return c.NetworkByName(name) 90 } 91 92 // GetNetworksByIDPrefix returns a list of networks whose ID partially matches zero or more networks 93 func (daemon *Daemon) GetNetworksByIDPrefix(partialID string) []libnetwork.Network { 94 c := daemon.netController 95 if c == nil { 96 return nil 97 } 98 list := []libnetwork.Network{} 99 l := func(nw libnetwork.Network) bool { 100 if strings.HasPrefix(nw.ID(), partialID) { 101 list = append(list, nw) 102 } 103 return false 104 } 105 c.WalkNetworks(l) 106 107 return list 108 } 109 110 // getAllNetworks returns a list containing all networks 111 func (daemon *Daemon) getAllNetworks() []libnetwork.Network { 112 c := daemon.netController 113 if c == nil { 114 return nil 115 } 116 return c.Networks() 117 } 118 119 type ingressJob struct { 120 create *clustertypes.NetworkCreateRequest 121 ip net.IP 122 jobDone chan struct{} 123 } 124 125 var ( 126 ingressWorkerOnce sync.Once 127 ingressJobsChannel chan *ingressJob 128 ingressID string 129 ) 130 131 func (daemon *Daemon) startIngressWorker() { 132 ingressJobsChannel = make(chan *ingressJob, 100) 133 go func() { 134 // nolint: gosimple 135 for { 136 select { 137 case r := <-ingressJobsChannel: 138 if r.create != nil { 139 daemon.setupIngress(r.create, r.ip, ingressID) 140 ingressID = r.create.ID 141 } else { 142 daemon.releaseIngress(ingressID) 143 ingressID = "" 144 } 145 close(r.jobDone) 146 } 147 } 148 }() 149 } 150 151 // enqueueIngressJob adds a ingress add/rm request to the worker queue. 152 // It guarantees the worker is started. 153 func (daemon *Daemon) enqueueIngressJob(job *ingressJob) { 154 ingressWorkerOnce.Do(daemon.startIngressWorker) 155 ingressJobsChannel <- job 156 } 157 158 // SetupIngress setups ingress networking. 159 // The function returns a channel which will signal the caller when the programming is completed. 160 func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) (<-chan struct{}, error) { 161 ip, _, err := net.ParseCIDR(nodeIP) 162 if err != nil { 163 return nil, err 164 } 165 done := make(chan struct{}) 166 daemon.enqueueIngressJob(&ingressJob{&create, ip, done}) 167 return done, nil 168 } 169 170 // ReleaseIngress releases the ingress networking. 171 // The function returns a channel which will signal the caller when the programming is completed. 172 func (daemon *Daemon) ReleaseIngress() (<-chan struct{}, error) { 173 done := make(chan struct{}) 174 daemon.enqueueIngressJob(&ingressJob{nil, nil, done}) 175 return done, nil 176 } 177 178 func (daemon *Daemon) setupIngress(create *clustertypes.NetworkCreateRequest, ip net.IP, staleID string) { 179 controller := daemon.netController 180 controller.AgentInitWait() 181 182 if staleID != "" && staleID != create.ID { 183 daemon.releaseIngress(staleID) 184 } 185 186 if _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true); err != nil { 187 // If it is any other error other than already 188 // exists error log error and return. 189 if _, ok := err.(libnetwork.NetworkNameError); !ok { 190 logrus.Errorf("Failed creating ingress network: %v", err) 191 return 192 } 193 // Otherwise continue down the call to create or recreate sandbox. 194 } 195 196 _, err := daemon.GetNetworkByID(create.ID) 197 if err != nil { 198 logrus.Errorf("Failed getting ingress network by id after creating: %v", err) 199 } 200 } 201 202 func (daemon *Daemon) releaseIngress(id string) { 203 controller := daemon.netController 204 205 if id == "" { 206 return 207 } 208 209 n, err := controller.NetworkByID(id) 210 if err != nil { 211 logrus.Errorf("failed to retrieve ingress network %s: %v", id, err) 212 return 213 } 214 215 if err := n.Delete(); err != nil { 216 logrus.Errorf("Failed to delete ingress network %s: %v", n.ID(), err) 217 return 218 } 219 } 220 221 // SetNetworkBootstrapKeys sets the bootstrap keys. 222 func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey) error { 223 err := daemon.netController.SetKeys(keys) 224 if err == nil { 225 // Upon successful key setting dispatch the keys available event 226 daemon.cluster.SendClusterEvent(lncluster.EventNetworkKeysAvailable) 227 } 228 return err 229 } 230 231 // UpdateAttachment notifies the attacher about the attachment config. 232 func (daemon *Daemon) UpdateAttachment(networkName, networkID, containerID string, config *network.NetworkingConfig) error { 233 if daemon.clusterProvider == nil { 234 return fmt.Errorf("cluster provider is not initialized") 235 } 236 237 if err := daemon.clusterProvider.UpdateAttachment(networkName, containerID, config); err != nil { 238 return daemon.clusterProvider.UpdateAttachment(networkID, containerID, config) 239 } 240 241 return nil 242 } 243 244 // WaitForDetachment makes the cluster manager wait for detachment of 245 // the container from the network. 246 func (daemon *Daemon) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error { 247 if daemon.clusterProvider == nil { 248 return fmt.Errorf("cluster provider is not initialized") 249 } 250 251 return daemon.clusterProvider.WaitForDetachment(ctx, networkName, networkID, taskID, containerID) 252 } 253 254 // CreateManagedNetwork creates an agent network. 255 func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error { 256 _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true) 257 return err 258 } 259 260 // CreateNetwork creates a network with the given name, driver and other optional parameters 261 func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) { 262 resp, err := daemon.createNetwork(create, "", false) 263 if err != nil { 264 return nil, err 265 } 266 return resp, err 267 } 268 269 func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) { 270 if runconfig.IsPreDefinedNetwork(create.Name) && !agent { 271 err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name) 272 return nil, errdefs.Forbidden(err) 273 } 274 275 var warning string 276 nw, err := daemon.GetNetworkByName(create.Name) 277 if err != nil { 278 if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok { 279 return nil, err 280 } 281 } 282 if nw != nil { 283 // check if user defined CheckDuplicate, if set true, return err 284 // otherwise prepare a warning message 285 if create.CheckDuplicate { 286 if !agent || nw.Info().Dynamic() { 287 return nil, libnetwork.NetworkNameError(create.Name) 288 } 289 } 290 warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) 291 } 292 293 c := daemon.netController 294 driver := create.Driver 295 if driver == "" { 296 driver = c.Config().Daemon.DefaultDriver 297 } 298 299 nwOptions := []libnetwork.NetworkOption{ 300 libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6), 301 libnetwork.NetworkOptionDriverOpts(create.Options), 302 libnetwork.NetworkOptionLabels(create.Labels), 303 libnetwork.NetworkOptionAttachable(create.Attachable), 304 libnetwork.NetworkOptionIngress(create.Ingress), 305 libnetwork.NetworkOptionScope(create.Scope), 306 } 307 308 if create.ConfigOnly { 309 nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigOnly()) 310 } 311 312 if create.IPAM != nil { 313 ipam := create.IPAM 314 v4Conf, v6Conf, err := getIpamConfig(ipam.Config) 315 if err != nil { 316 return nil, err 317 } 318 nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options)) 319 } 320 321 if create.Internal { 322 nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork()) 323 } 324 if agent { 325 nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic()) 326 nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false)) 327 } 328 329 if create.ConfigFrom != nil { 330 nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigFrom(create.ConfigFrom.Network)) 331 } 332 333 if agent && driver == "overlay" && (create.Ingress || runtime.GOOS == "windows") { 334 nodeIP, exists := daemon.GetAttachmentStore().GetIPForNetwork(id) 335 if !exists { 336 return nil, fmt.Errorf("Failed to find a load balancer IP to use for network: %v", id) 337 } 338 339 nwOptions = append(nwOptions, libnetwork.NetworkOptionLBEndpoint(nodeIP)) 340 } 341 342 n, err := c.NewNetwork(driver, create.Name, id, nwOptions...) 343 if err != nil { 344 if _, ok := err.(libnetwork.ErrDataStoreNotInitialized); ok { 345 // nolint: golint 346 return nil, errors.New("This node is not a swarm manager. Use \"docker swarm init\" or \"docker swarm join\" to connect this node to swarm and try again.") 347 } 348 return nil, err 349 } 350 351 daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.Acquire) 352 if create.IPAM != nil { 353 daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.Acquire) 354 } 355 daemon.LogNetworkEvent(n, "create") 356 357 return &types.NetworkCreateResponse{ 358 ID: n.ID(), 359 Warning: warning, 360 }, nil 361 } 362 363 func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) { 364 var builtinDrivers []string 365 366 if capability == driverapi.NetworkPluginEndpointType { 367 builtinDrivers = daemon.netController.BuiltinDrivers() 368 } else if capability == ipamapi.PluginEndpointType { 369 builtinDrivers = daemon.netController.BuiltinIPAMDrivers() 370 } 371 372 for _, d := range builtinDrivers { 373 if d == driver { 374 return 375 } 376 } 377 378 if daemon.PluginStore != nil { 379 _, err := daemon.PluginStore.Get(driver, capability, mode) 380 if err != nil { 381 logrus.WithError(err).WithFields(logrus.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation") 382 } 383 } 384 } 385 386 func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) { 387 ipamV4Cfg := []*libnetwork.IpamConf{} 388 ipamV6Cfg := []*libnetwork.IpamConf{} 389 for _, d := range data { 390 iCfg := libnetwork.IpamConf{} 391 iCfg.PreferredPool = d.Subnet 392 iCfg.SubPool = d.IPRange 393 iCfg.Gateway = d.Gateway 394 iCfg.AuxAddresses = d.AuxAddress 395 ip, _, err := net.ParseCIDR(d.Subnet) 396 if err != nil { 397 return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err) 398 } 399 if ip.To4() != nil { 400 ipamV4Cfg = append(ipamV4Cfg, &iCfg) 401 } else { 402 ipamV6Cfg = append(ipamV6Cfg, &iCfg) 403 } 404 } 405 return ipamV4Cfg, ipamV6Cfg, nil 406 } 407 408 // UpdateContainerServiceConfig updates a service configuration. 409 func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error { 410 container, err := daemon.GetContainer(containerName) 411 if err != nil { 412 return err 413 } 414 415 container.NetworkSettings.Service = serviceConfig 416 return nil 417 } 418 419 // ConnectContainerToNetwork connects the given container to the given 420 // network. If either cannot be found, an err is returned. If the 421 // network cannot be set up, an err is returned. 422 func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error { 423 container, err := daemon.GetContainer(containerName) 424 if err != nil { 425 return err 426 } 427 return daemon.ConnectToNetwork(container, networkName, endpointConfig) 428 } 429 430 // DisconnectContainerFromNetwork disconnects the given container from 431 // the given network. If either cannot be found, an err is returned. 432 func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error { 433 container, err := daemon.GetContainer(containerName) 434 if err != nil { 435 if force { 436 return daemon.ForceEndpointDelete(containerName, networkName) 437 } 438 return err 439 } 440 return daemon.DisconnectFromNetwork(container, networkName, force) 441 } 442 443 // GetNetworkDriverList returns the list of plugins drivers 444 // registered for network. 445 func (daemon *Daemon) GetNetworkDriverList() []string { 446 if !daemon.NetworkControllerEnabled() { 447 return nil 448 } 449 450 pluginList := daemon.netController.BuiltinDrivers() 451 452 managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType) 453 454 for _, plugin := range managedPlugins { 455 pluginList = append(pluginList, plugin.Name()) 456 } 457 458 pluginMap := make(map[string]bool) 459 for _, plugin := range pluginList { 460 pluginMap[plugin] = true 461 } 462 463 networks := daemon.netController.Networks() 464 465 for _, network := range networks { 466 if !pluginMap[network.Type()] { 467 pluginList = append(pluginList, network.Type()) 468 pluginMap[network.Type()] = true 469 } 470 } 471 472 sort.Strings(pluginList) 473 474 return pluginList 475 } 476 477 // DeleteManagedNetwork deletes an agent network. 478 // The requirement of networkID is enforced. 479 func (daemon *Daemon) DeleteManagedNetwork(networkID string) error { 480 n, err := daemon.GetNetworkByID(networkID) 481 if err != nil { 482 return err 483 } 484 return daemon.deleteNetwork(n, true) 485 } 486 487 // DeleteNetwork destroys a network unless it's one of docker's predefined networks. 488 func (daemon *Daemon) DeleteNetwork(networkID string) error { 489 n, err := daemon.GetNetworkByID(networkID) 490 if err != nil { 491 return err 492 } 493 return daemon.deleteNetwork(n, false) 494 } 495 496 func (daemon *Daemon) deleteLoadBalancerSandbox(n libnetwork.Network) { 497 controller := daemon.netController 498 499 //The only endpoint left should be the LB endpoint (nw.Name() + "-endpoint") 500 endpoints := n.Endpoints() 501 if len(endpoints) == 1 { 502 sandboxName := n.Name() + "-sbox" 503 504 info := endpoints[0].Info() 505 if info != nil { 506 sb := info.Sandbox() 507 if sb != nil { 508 if err := sb.DisableService(); err != nil { 509 logrus.Warnf("Failed to disable service on sandbox %s: %v", sandboxName, err) 510 //Ignore error and attempt to delete the load balancer endpoint 511 } 512 } 513 } 514 515 if err := endpoints[0].Delete(true); err != nil { 516 logrus.Warnf("Failed to delete endpoint %s (%s) in %s: %v", endpoints[0].Name(), endpoints[0].ID(), sandboxName, err) 517 //Ignore error and attempt to delete the sandbox. 518 } 519 520 if err := controller.SandboxDestroy(sandboxName); err != nil { 521 logrus.Warnf("Failed to delete %s sandbox: %v", sandboxName, err) 522 //Ignore error and attempt to delete the network. 523 } 524 } 525 } 526 527 func (daemon *Daemon) deleteNetwork(nw libnetwork.Network, dynamic bool) error { 528 if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic { 529 err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name()) 530 return errdefs.Forbidden(err) 531 } 532 533 if dynamic && !nw.Info().Dynamic() { 534 if runconfig.IsPreDefinedNetwork(nw.Name()) { 535 // Predefined networks now support swarm services. Make this 536 // a no-op when cluster requests to remove the predefined network. 537 return nil 538 } 539 err := fmt.Errorf("%s is not a dynamic network", nw.Name()) 540 return errdefs.Forbidden(err) 541 } 542 543 if err := nw.Delete(); err != nil { 544 return err 545 } 546 547 // If this is not a configuration only network, we need to 548 // update the corresponding remote drivers' reference counts 549 if !nw.Info().ConfigOnly() { 550 daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.Release) 551 ipamType, _, _, _ := nw.Info().IpamConfig() 552 daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.Release) 553 daemon.LogNetworkEvent(nw, "destroy") 554 } 555 556 return nil 557 } 558 559 // GetNetworks returns a list of all networks 560 func (daemon *Daemon) GetNetworks() []libnetwork.Network { 561 return daemon.getAllNetworks() 562 } 563 564 // clearAttachableNetworks removes the attachable networks 565 // after disconnecting any connected container 566 func (daemon *Daemon) clearAttachableNetworks() { 567 for _, n := range daemon.GetNetworks() { 568 if !n.Info().Attachable() { 569 continue 570 } 571 for _, ep := range n.Endpoints() { 572 epInfo := ep.Info() 573 if epInfo == nil { 574 continue 575 } 576 sb := epInfo.Sandbox() 577 if sb == nil { 578 continue 579 } 580 containerID := sb.ContainerID() 581 if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil { 582 logrus.Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v", 583 containerID, n.Name(), err) 584 } 585 } 586 if err := daemon.DeleteManagedNetwork(n.ID()); err != nil { 587 logrus.Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err) 588 } 589 } 590 }