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