github.com/rish1988/moby@v25.0.2+incompatible/daemon/network.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "sort" 9 "strconv" 10 "strings" 11 "sync" 12 13 "github.com/containerd/log" 14 "github.com/docker/docker/api/types" 15 "github.com/docker/docker/api/types/backend" 16 containertypes "github.com/docker/docker/api/types/container" 17 "github.com/docker/docker/api/types/events" 18 "github.com/docker/docker/api/types/filters" 19 "github.com/docker/docker/api/types/network" 20 "github.com/docker/docker/container" 21 clustertypes "github.com/docker/docker/daemon/cluster/provider" 22 "github.com/docker/docker/daemon/config" 23 internalnetwork "github.com/docker/docker/daemon/network" 24 "github.com/docker/docker/errdefs" 25 "github.com/docker/docker/libnetwork" 26 lncluster "github.com/docker/docker/libnetwork/cluster" 27 "github.com/docker/docker/libnetwork/driverapi" 28 "github.com/docker/docker/libnetwork/ipamapi" 29 "github.com/docker/docker/libnetwork/netlabel" 30 "github.com/docker/docker/libnetwork/networkdb" 31 "github.com/docker/docker/libnetwork/options" 32 networktypes "github.com/docker/docker/libnetwork/types" 33 "github.com/docker/docker/opts" 34 "github.com/docker/docker/pkg/plugingetter" 35 "github.com/docker/docker/runconfig" 36 "github.com/docker/go-connections/nat" 37 ) 38 39 // PredefinedNetworkError is returned when user tries to create predefined network that already exists. 40 type PredefinedNetworkError string 41 42 func (pnr PredefinedNetworkError) Error() string { 43 return fmt.Sprintf("operation is not permitted on predefined %s network ", string(pnr)) 44 } 45 46 // Forbidden denotes the type of this error 47 func (pnr PredefinedNetworkError) Forbidden() {} 48 49 // NetworkControllerEnabled checks if the networking stack is enabled. 50 // This feature depends on OS primitives and it's disabled in systems like Windows. 51 func (daemon *Daemon) NetworkControllerEnabled() bool { 52 return daemon.netController != nil 53 } 54 55 // NetworkController returns the network controller created by the daemon. 56 func (daemon *Daemon) NetworkController() *libnetwork.Controller { 57 return daemon.netController 58 } 59 60 // FindNetwork returns a network based on: 61 // 1. Full ID 62 // 2. Full Name 63 // 3. Partial ID 64 // as long as there is no ambiguity 65 func (daemon *Daemon) FindNetwork(term string) (*libnetwork.Network, error) { 66 var listByFullName, listByPartialID []*libnetwork.Network 67 for _, nw := range daemon.getAllNetworks() { 68 nwID := nw.ID() 69 if nwID == term { 70 return nw, nil 71 } 72 if strings.HasPrefix(nw.ID(), term) { 73 listByPartialID = append(listByPartialID, nw) 74 } 75 if nw.Name() == term { 76 listByFullName = append(listByFullName, nw) 77 } 78 } 79 switch { 80 case len(listByFullName) == 1: 81 return listByFullName[0], nil 82 case len(listByFullName) > 1: 83 return nil, errdefs.InvalidParameter(fmt.Errorf("network %s is ambiguous (%d matches found on name)", term, len(listByFullName))) 84 case len(listByPartialID) == 1: 85 return listByPartialID[0], nil 86 case len(listByPartialID) > 1: 87 return nil, errdefs.InvalidParameter(fmt.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID))) 88 } 89 90 // Be very careful to change the error type here, the 91 // libnetwork.ErrNoSuchNetwork error is used by the controller 92 // to retry the creation of the network as managed through the swarm manager 93 return nil, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term)) 94 } 95 96 // GetNetworkByID function returns a network whose ID matches the given ID. 97 // It fails with an error if no matching network is found. 98 func (daemon *Daemon) GetNetworkByID(id string) (*libnetwork.Network, error) { 99 c := daemon.netController 100 if c == nil { 101 return nil, fmt.Errorf("netcontroller is nil: %w", libnetwork.ErrNoSuchNetwork(id)) 102 } 103 return c.NetworkByID(id) 104 } 105 106 // GetNetworkByName function returns a network for a given network name. 107 // If no network name is given, the default network is returned. 108 func (daemon *Daemon) GetNetworkByName(name string) (*libnetwork.Network, error) { 109 c := daemon.netController 110 if c == nil { 111 return nil, libnetwork.ErrNoSuchNetwork(name) 112 } 113 if name == "" { 114 name = c.Config().DefaultNetwork 115 } 116 return c.NetworkByName(name) 117 } 118 119 // GetNetworksByIDPrefix returns a list of networks whose ID partially matches zero or more networks 120 func (daemon *Daemon) GetNetworksByIDPrefix(partialID string) []*libnetwork.Network { 121 c := daemon.netController 122 if c == nil { 123 return nil 124 } 125 list := []*libnetwork.Network{} 126 l := func(nw *libnetwork.Network) bool { 127 if strings.HasPrefix(nw.ID(), partialID) { 128 list = append(list, nw) 129 } 130 return false 131 } 132 c.WalkNetworks(l) 133 134 return list 135 } 136 137 // getAllNetworks returns a list containing all networks 138 func (daemon *Daemon) getAllNetworks() []*libnetwork.Network { 139 c := daemon.netController 140 if c == nil { 141 return nil 142 } 143 ctx := context.TODO() 144 return c.Networks(ctx) 145 } 146 147 type ingressJob struct { 148 create *clustertypes.NetworkCreateRequest 149 ip net.IP 150 jobDone chan struct{} 151 } 152 153 var ( 154 ingressWorkerOnce sync.Once 155 ingressJobsChannel chan *ingressJob 156 ingressID string 157 ) 158 159 func (daemon *Daemon) startIngressWorker() { 160 ingressJobsChannel = make(chan *ingressJob, 100) 161 go func() { 162 //nolint: gosimple 163 for { 164 select { 165 case r := <-ingressJobsChannel: 166 if r.create != nil { 167 daemon.setupIngress(&daemon.config().Config, r.create, r.ip, ingressID) 168 ingressID = r.create.ID 169 } else { 170 daemon.releaseIngress(ingressID) 171 ingressID = "" 172 } 173 close(r.jobDone) 174 } 175 } 176 }() 177 } 178 179 // enqueueIngressJob adds a ingress add/rm request to the worker queue. 180 // It guarantees the worker is started. 181 func (daemon *Daemon) enqueueIngressJob(job *ingressJob) { 182 ingressWorkerOnce.Do(daemon.startIngressWorker) 183 ingressJobsChannel <- job 184 } 185 186 // SetupIngress setups ingress networking. 187 // The function returns a channel which will signal the caller when the programming is completed. 188 func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) (<-chan struct{}, error) { 189 ip, _, err := net.ParseCIDR(nodeIP) 190 if err != nil { 191 return nil, err 192 } 193 done := make(chan struct{}) 194 daemon.enqueueIngressJob(&ingressJob{&create, ip, done}) 195 return done, nil 196 } 197 198 // ReleaseIngress releases the ingress networking. 199 // The function returns a channel which will signal the caller when the programming is completed. 200 func (daemon *Daemon) ReleaseIngress() (<-chan struct{}, error) { 201 done := make(chan struct{}) 202 daemon.enqueueIngressJob(&ingressJob{nil, nil, done}) 203 return done, nil 204 } 205 206 func (daemon *Daemon) setupIngress(cfg *config.Config, create *clustertypes.NetworkCreateRequest, ip net.IP, staleID string) { 207 controller := daemon.netController 208 controller.AgentInitWait() 209 210 if staleID != "" && staleID != create.ID { 211 daemon.releaseIngress(staleID) 212 } 213 214 if _, err := daemon.createNetwork(cfg, create.NetworkCreateRequest, create.ID, true); err != nil { 215 // If it is any other error other than already 216 // exists error log error and return. 217 if _, ok := err.(libnetwork.NetworkNameError); !ok { 218 log.G(context.TODO()).Errorf("Failed creating ingress network: %v", err) 219 return 220 } 221 // Otherwise continue down the call to create or recreate sandbox. 222 } 223 224 _, err := daemon.GetNetworkByID(create.ID) 225 if err != nil { 226 log.G(context.TODO()).Errorf("Failed getting ingress network by id after creating: %v", err) 227 } 228 } 229 230 func (daemon *Daemon) releaseIngress(id string) { 231 controller := daemon.netController 232 233 if id == "" { 234 return 235 } 236 237 n, err := controller.NetworkByID(id) 238 if err != nil { 239 log.G(context.TODO()).Errorf("failed to retrieve ingress network %s: %v", id, err) 240 return 241 } 242 243 if err := n.Delete(libnetwork.NetworkDeleteOptionRemoveLB); err != nil { 244 log.G(context.TODO()).Errorf("Failed to delete ingress network %s: %v", n.ID(), err) 245 return 246 } 247 } 248 249 // SetNetworkBootstrapKeys sets the bootstrap keys. 250 func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey) error { 251 if err := daemon.netController.SetKeys(keys); err != nil { 252 return err 253 } 254 // Upon successful key setting dispatch the keys available event 255 daemon.cluster.SendClusterEvent(lncluster.EventNetworkKeysAvailable) 256 return nil 257 } 258 259 // UpdateAttachment notifies the attacher about the attachment config. 260 func (daemon *Daemon) UpdateAttachment(networkName, networkID, containerID string, config *network.NetworkingConfig) error { 261 if daemon.clusterProvider == nil { 262 return fmt.Errorf("cluster provider is not initialized") 263 } 264 265 if err := daemon.clusterProvider.UpdateAttachment(networkName, containerID, config); err != nil { 266 return daemon.clusterProvider.UpdateAttachment(networkID, containerID, config) 267 } 268 269 return nil 270 } 271 272 // WaitForDetachment makes the cluster manager wait for detachment of 273 // the container from the network. 274 func (daemon *Daemon) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error { 275 if daemon.clusterProvider == nil { 276 return fmt.Errorf("cluster provider is not initialized") 277 } 278 279 return daemon.clusterProvider.WaitForDetachment(ctx, networkName, networkID, taskID, containerID) 280 } 281 282 // CreateManagedNetwork creates an agent network. 283 func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error { 284 _, err := daemon.createNetwork(&daemon.config().Config, create.NetworkCreateRequest, create.ID, true) 285 return err 286 } 287 288 // CreateNetwork creates a network with the given name, driver and other optional parameters 289 func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) { 290 return daemon.createNetwork(&daemon.config().Config, create, "", false) 291 } 292 293 func (daemon *Daemon) createNetwork(cfg *config.Config, create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) { 294 if runconfig.IsPreDefinedNetwork(create.Name) { 295 return nil, PredefinedNetworkError(create.Name) 296 } 297 298 c := daemon.netController 299 driver := create.Driver 300 if driver == "" { 301 driver = c.Config().DefaultDriver 302 } 303 304 if driver == "overlay" && !daemon.cluster.IsManager() && !agent { 305 return nil, errdefs.Forbidden(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.`)) 306 } 307 308 if network.HasIPv6Subnets(create.IPAM) { 309 create.EnableIPv6 = true 310 } 311 312 networkOptions := make(map[string]string) 313 for k, v := range create.Options { 314 networkOptions[k] = v 315 } 316 if defaultOpts, ok := cfg.DefaultNetworkOpts[driver]; create.ConfigFrom == nil && ok { 317 for k, v := range defaultOpts { 318 if _, ok := networkOptions[k]; !ok { 319 log.G(context.TODO()).WithFields(log.Fields{"driver": driver, "network": id, k: v}).Debug("Applying network default option") 320 networkOptions[k] = v 321 } 322 } 323 } 324 325 nwOptions := []libnetwork.NetworkOption{ 326 libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6), 327 libnetwork.NetworkOptionDriverOpts(networkOptions), 328 libnetwork.NetworkOptionLabels(create.Labels), 329 libnetwork.NetworkOptionAttachable(create.Attachable), 330 libnetwork.NetworkOptionIngress(create.Ingress), 331 libnetwork.NetworkOptionScope(create.Scope), 332 } 333 334 if create.ConfigOnly { 335 nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigOnly()) 336 } 337 338 if err := network.ValidateIPAM(create.IPAM); err != nil { 339 return nil, errdefs.InvalidParameter(err) 340 } 341 342 if create.IPAM != nil { 343 ipam := create.IPAM 344 v4Conf, v6Conf, err := getIpamConfig(ipam.Config) 345 if err != nil { 346 return nil, err 347 } 348 nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options)) 349 } 350 351 if create.Internal { 352 nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork()) 353 } 354 if agent { 355 nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic()) 356 nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false)) 357 } 358 359 if create.ConfigFrom != nil { 360 nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigFrom(create.ConfigFrom.Network)) 361 } 362 363 if agent && driver == "overlay" { 364 nodeIP, exists := daemon.GetAttachmentStore().GetIPForNetwork(id) 365 if !exists { 366 return nil, fmt.Errorf("failed to find a load balancer IP to use for network: %v", id) 367 } 368 369 nwOptions = append(nwOptions, libnetwork.NetworkOptionLBEndpoint(nodeIP)) 370 } 371 372 n, err := c.NewNetwork(driver, create.Name, id, nwOptions...) 373 if err != nil { 374 return nil, err 375 } 376 377 daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.Acquire) 378 if create.IPAM != nil { 379 daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.Acquire) 380 } 381 daemon.LogNetworkEvent(n, events.ActionCreate) 382 383 return &types.NetworkCreateResponse{ 384 ID: n.ID(), 385 }, nil 386 } 387 388 func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) { 389 var builtinDrivers []string 390 391 if capability == driverapi.NetworkPluginEndpointType { 392 builtinDrivers = daemon.netController.BuiltinDrivers() 393 } else if capability == ipamapi.PluginEndpointType { 394 builtinDrivers = daemon.netController.BuiltinIPAMDrivers() 395 } 396 397 for _, d := range builtinDrivers { 398 if d == driver { 399 return 400 } 401 } 402 403 if daemon.PluginStore != nil { 404 _, err := daemon.PluginStore.Get(driver, capability, mode) 405 if err != nil { 406 log.G(context.TODO()).WithError(err).WithFields(log.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation") 407 } 408 } 409 } 410 411 func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) { 412 ipamV4Cfg := []*libnetwork.IpamConf{} 413 ipamV6Cfg := []*libnetwork.IpamConf{} 414 for _, d := range data { 415 iCfg := libnetwork.IpamConf{} 416 iCfg.PreferredPool = d.Subnet 417 iCfg.SubPool = d.IPRange 418 iCfg.Gateway = d.Gateway 419 iCfg.AuxAddresses = d.AuxAddress 420 ip, _, err := net.ParseCIDR(d.Subnet) 421 if err != nil { 422 return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err) 423 } 424 if ip.To4() != nil { 425 ipamV4Cfg = append(ipamV4Cfg, &iCfg) 426 } else { 427 ipamV6Cfg = append(ipamV6Cfg, &iCfg) 428 } 429 } 430 return ipamV4Cfg, ipamV6Cfg, nil 431 } 432 433 // UpdateContainerServiceConfig updates a service configuration. 434 func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error { 435 ctr, err := daemon.GetContainer(containerName) 436 if err != nil { 437 return err 438 } 439 440 ctr.NetworkSettings.Service = serviceConfig 441 return nil 442 } 443 444 // ConnectContainerToNetwork connects the given container to the given 445 // network. If either cannot be found, an err is returned. If the 446 // network cannot be set up, an err is returned. 447 func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error { 448 ctr, err := daemon.GetContainer(containerName) 449 if err != nil { 450 return err 451 } 452 return daemon.ConnectToNetwork(ctr, networkName, endpointConfig) 453 } 454 455 // DisconnectContainerFromNetwork disconnects the given container from 456 // the given network. If either cannot be found, an err is returned. 457 func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error { 458 ctr, err := daemon.GetContainer(containerName) 459 if err != nil { 460 if force { 461 return daemon.ForceEndpointDelete(containerName, networkName) 462 } 463 return err 464 } 465 return daemon.DisconnectFromNetwork(ctr, networkName, force) 466 } 467 468 // GetNetworkDriverList returns the list of plugins drivers 469 // registered for network. 470 func (daemon *Daemon) GetNetworkDriverList(ctx context.Context) []string { 471 if !daemon.NetworkControllerEnabled() { 472 return nil 473 } 474 475 pluginList := daemon.netController.BuiltinDrivers() 476 477 managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType) 478 479 for _, plugin := range managedPlugins { 480 pluginList = append(pluginList, plugin.Name()) 481 } 482 483 pluginMap := make(map[string]bool) 484 for _, plugin := range pluginList { 485 pluginMap[plugin] = true 486 } 487 488 networks := daemon.netController.Networks(ctx) 489 490 for _, nw := range networks { 491 if !pluginMap[nw.Type()] { 492 pluginList = append(pluginList, nw.Type()) 493 pluginMap[nw.Type()] = true 494 } 495 } 496 497 sort.Strings(pluginList) 498 499 return pluginList 500 } 501 502 // DeleteManagedNetwork deletes an agent network. 503 // The requirement of networkID is enforced. 504 func (daemon *Daemon) DeleteManagedNetwork(networkID string) error { 505 n, err := daemon.GetNetworkByID(networkID) 506 if err != nil { 507 return err 508 } 509 return daemon.deleteNetwork(n, true) 510 } 511 512 // DeleteNetwork destroys a network unless it's one of docker's predefined networks. 513 func (daemon *Daemon) DeleteNetwork(networkID string) error { 514 n, err := daemon.GetNetworkByID(networkID) 515 if err != nil { 516 return fmt.Errorf("could not find network by ID: %w", err) 517 } 518 return daemon.deleteNetwork(n, false) 519 } 520 521 func (daemon *Daemon) deleteNetwork(nw *libnetwork.Network, dynamic bool) error { 522 if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic { 523 err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name()) 524 return errdefs.Forbidden(err) 525 } 526 527 if dynamic && !nw.Dynamic() { 528 if runconfig.IsPreDefinedNetwork(nw.Name()) { 529 // Predefined networks now support swarm services. Make this 530 // a no-op when cluster requests to remove the predefined network. 531 return nil 532 } 533 err := fmt.Errorf("%s is not a dynamic network", nw.Name()) 534 return errdefs.Forbidden(err) 535 } 536 537 if err := nw.Delete(); err != nil { 538 return fmt.Errorf("error while removing network: %w", err) 539 } 540 541 // If this is not a configuration only network, we need to 542 // update the corresponding remote drivers' reference counts 543 if !nw.ConfigOnly() { 544 daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.Release) 545 ipamType, _, _, _ := nw.IpamConfig() 546 daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.Release) 547 daemon.LogNetworkEvent(nw, events.ActionDestroy) 548 } 549 550 return nil 551 } 552 553 // GetNetworks returns a list of all networks 554 func (daemon *Daemon) GetNetworks(filter filters.Args, config backend.NetworkListConfig) (networks []types.NetworkResource, err error) { 555 var idx map[string]*libnetwork.Network 556 if config.Detailed { 557 idx = make(map[string]*libnetwork.Network) 558 } 559 560 allNetworks := daemon.getAllNetworks() 561 networks = make([]types.NetworkResource, 0, len(allNetworks)) 562 for _, n := range allNetworks { 563 nr := buildNetworkResource(n) 564 networks = append(networks, nr) 565 if config.Detailed { 566 idx[nr.ID] = n 567 } 568 } 569 570 networks, err = internalnetwork.FilterNetworks(networks, filter) 571 if err != nil { 572 return nil, err 573 } 574 575 if config.Detailed { 576 for i, nw := range networks { 577 networks[i].Containers = buildContainerAttachments(idx[nw.ID]) 578 if config.Verbose { 579 networks[i].Services = buildServiceAttachments(idx[nw.ID]) 580 } 581 } 582 } 583 584 return networks, nil 585 } 586 587 // buildNetworkResource builds a [types.NetworkResource] from the given 588 // [libnetwork.Network], to be returned by the API. 589 func buildNetworkResource(nw *libnetwork.Network) types.NetworkResource { 590 if nw == nil { 591 return types.NetworkResource{} 592 } 593 594 return types.NetworkResource{ 595 Name: nw.Name(), 596 ID: nw.ID(), 597 Created: nw.Created(), 598 Scope: nw.Scope(), 599 Driver: nw.Type(), 600 EnableIPv6: nw.IPv6Enabled(), 601 IPAM: buildIPAMResources(nw), 602 Internal: nw.Internal(), 603 Attachable: nw.Attachable(), 604 Ingress: nw.Ingress(), 605 ConfigFrom: network.ConfigReference{Network: nw.ConfigFrom()}, 606 ConfigOnly: nw.ConfigOnly(), 607 Containers: map[string]types.EndpointResource{}, 608 Options: nw.DriverOptions(), 609 Labels: nw.Labels(), 610 Peers: buildPeerInfoResources(nw.Peers()), 611 } 612 } 613 614 // buildContainerAttachments creates a [types.EndpointResource] map of all 615 // containers attached to the network. It is used when listing networks in 616 // detailed mode. 617 func buildContainerAttachments(nw *libnetwork.Network) map[string]types.EndpointResource { 618 containers := make(map[string]types.EndpointResource) 619 for _, e := range nw.Endpoints() { 620 ei := e.Info() 621 if ei == nil { 622 continue 623 } 624 if sb := ei.Sandbox(); sb != nil { 625 containers[sb.ContainerID()] = buildEndpointResource(e, ei) 626 } else { 627 containers["ep-"+e.ID()] = buildEndpointResource(e, ei) 628 } 629 } 630 return containers 631 } 632 633 // buildServiceAttachments creates a [network.ServiceInfo] map of all services 634 // attached to the network. It is used when listing networks in "verbose" mode. 635 func buildServiceAttachments(nw *libnetwork.Network) map[string]network.ServiceInfo { 636 services := make(map[string]network.ServiceInfo) 637 for name, service := range nw.Services() { 638 tasks := make([]network.Task, 0, len(service.Tasks)) 639 for _, t := range service.Tasks { 640 tasks = append(tasks, network.Task{ 641 Name: t.Name, 642 EndpointID: t.EndpointID, 643 EndpointIP: t.EndpointIP, 644 Info: t.Info, 645 }) 646 } 647 services[name] = network.ServiceInfo{ 648 VIP: service.VIP, 649 Ports: service.Ports, 650 Tasks: tasks, 651 LocalLBIndex: service.LocalLBIndex, 652 } 653 } 654 return services 655 } 656 657 // buildPeerInfoResources converts a list of [networkdb.PeerInfo] to a 658 // [network.PeerInfo] for inclusion in API responses. It returns nil if 659 // the list of peers is empty. 660 func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo { 661 if len(peers) == 0 { 662 return nil 663 } 664 peerInfo := make([]network.PeerInfo, 0, len(peers)) 665 for _, peer := range peers { 666 peerInfo = append(peerInfo, network.PeerInfo(peer)) 667 } 668 return peerInfo 669 } 670 671 // buildIPAMResources constructs a [network.IPAM] from the network's 672 // IPAM information for inclusion in API responses. 673 func buildIPAMResources(nw *libnetwork.Network) network.IPAM { 674 var ipamConfig []network.IPAMConfig 675 676 ipamDriver, ipamOptions, ipv4Conf, ipv6Conf := nw.IpamConfig() 677 678 hasIPv4Config := false 679 for _, cfg := range ipv4Conf { 680 if cfg.PreferredPool == "" { 681 continue 682 } 683 hasIPv4Config = true 684 ipamConfig = append(ipamConfig, network.IPAMConfig{ 685 Subnet: cfg.PreferredPool, 686 IPRange: cfg.SubPool, 687 Gateway: cfg.Gateway, 688 AuxAddress: cfg.AuxAddresses, 689 }) 690 } 691 692 hasIPv6Config := false 693 for _, cfg := range ipv6Conf { 694 if cfg.PreferredPool == "" { 695 continue 696 } 697 hasIPv6Config = true 698 ipamConfig = append(ipamConfig, network.IPAMConfig{ 699 Subnet: cfg.PreferredPool, 700 IPRange: cfg.SubPool, 701 Gateway: cfg.Gateway, 702 AuxAddress: cfg.AuxAddresses, 703 }) 704 } 705 706 if !hasIPv4Config || !hasIPv6Config { 707 ipv4Info, ipv6Info := nw.IpamInfo() 708 if !hasIPv4Config { 709 for _, info := range ipv4Info { 710 var gw string 711 if info.IPAMData.Gateway != nil { 712 gw = info.IPAMData.Gateway.IP.String() 713 } 714 ipamConfig = append(ipamConfig, network.IPAMConfig{ 715 Subnet: info.IPAMData.Pool.String(), 716 Gateway: gw, 717 }) 718 } 719 } 720 721 if !hasIPv6Config { 722 for _, info := range ipv6Info { 723 if info.IPAMData.Pool == nil { 724 continue 725 } 726 ipamConfig = append(ipamConfig, network.IPAMConfig{ 727 Subnet: info.IPAMData.Pool.String(), 728 Gateway: info.IPAMData.Gateway.String(), 729 }) 730 } 731 } 732 } 733 734 return network.IPAM{ 735 Driver: ipamDriver, 736 Options: ipamOptions, 737 Config: ipamConfig, 738 } 739 } 740 741 // buildEndpointResource combines information from the endpoint and additional 742 // endpoint-info into a [types.EndpointResource]. 743 func buildEndpointResource(ep *libnetwork.Endpoint, info libnetwork.EndpointInfo) types.EndpointResource { 744 er := types.EndpointResource{ 745 EndpointID: ep.ID(), 746 Name: ep.Name(), 747 } 748 if iface := info.Iface(); iface != nil { 749 if mac := iface.MacAddress(); mac != nil { 750 er.MacAddress = mac.String() 751 } 752 if ip := iface.Address(); ip != nil && len(ip.IP) > 0 { 753 er.IPv4Address = ip.String() 754 } 755 if ip := iface.AddressIPv6(); ip != nil && len(ip.IP) > 0 { 756 er.IPv6Address = ip.String() 757 } 758 } 759 return er 760 } 761 762 // clearAttachableNetworks removes the attachable networks 763 // after disconnecting any connected container 764 func (daemon *Daemon) clearAttachableNetworks() { 765 for _, n := range daemon.getAllNetworks() { 766 if !n.Attachable() { 767 continue 768 } 769 for _, ep := range n.Endpoints() { 770 epInfo := ep.Info() 771 if epInfo == nil { 772 continue 773 } 774 sb := epInfo.Sandbox() 775 if sb == nil { 776 continue 777 } 778 containerID := sb.ContainerID() 779 if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil { 780 log.G(context.TODO()).Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v", 781 containerID, n.Name(), err) 782 } 783 } 784 if err := daemon.DeleteManagedNetwork(n.ID()); err != nil { 785 log.G(context.TODO()).Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err) 786 } 787 } 788 } 789 790 // buildCreateEndpointOptions builds endpoint options from a given network. 791 func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *network.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) { 792 var createOptions []libnetwork.EndpointOption 793 var genericOptions = make(options.Generic) 794 795 nwName := n.Name() 796 797 if epConfig != nil { 798 if ipam := epConfig.IPAMConfig; ipam != nil { 799 var ipList []net.IP 800 for _, ips := range ipam.LinkLocalIPs { 801 linkIP := net.ParseIP(ips) 802 if linkIP == nil && ips != "" { 803 return nil, fmt.Errorf("invalid link-local IP address: %s", ipam.LinkLocalIPs) 804 } 805 ipList = append(ipList, linkIP) 806 } 807 808 ip := net.ParseIP(ipam.IPv4Address) 809 if ip == nil && ipam.IPv4Address != "" { 810 return nil, fmt.Errorf("invalid IPv4 address: %s", ipam.IPv4Address) 811 } 812 813 ip6 := net.ParseIP(ipam.IPv6Address) 814 if ip6 == nil && ipam.IPv6Address != "" { 815 return nil, fmt.Errorf("invalid IPv6 address: %s", ipam.IPv6Address) 816 } 817 818 createOptions = append(createOptions, libnetwork.CreateOptionIpam(ip, ip6, ipList, nil)) 819 } 820 821 createOptions = append(createOptions, libnetwork.CreateOptionDNSNames(epConfig.DNSNames)) 822 823 for k, v := range epConfig.DriverOpts { 824 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v})) 825 } 826 827 if epConfig.MacAddress != "" { 828 mac, err := net.ParseMAC(epConfig.MacAddress) 829 if err != nil { 830 return nil, err 831 } 832 genericOptions[netlabel.MacAddress] = mac 833 } 834 } 835 836 if svcCfg := c.NetworkSettings.Service; svcCfg != nil { 837 nwID := n.ID() 838 839 var vip net.IP 840 if virtualAddress := svcCfg.VirtualAddresses[nwID]; virtualAddress != nil { 841 vip = net.ParseIP(virtualAddress.IPv4) 842 } 843 844 var portConfigs []*libnetwork.PortConfig 845 for _, portConfig := range svcCfg.ExposedPorts { 846 portConfigs = append(portConfigs, &libnetwork.PortConfig{ 847 Name: portConfig.Name, 848 Protocol: libnetwork.PortConfig_Protocol(portConfig.Protocol), 849 TargetPort: portConfig.TargetPort, 850 PublishedPort: portConfig.PublishedPort, 851 }) 852 } 853 854 createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, vip, portConfigs, svcCfg.Aliases[nwID])) 855 } 856 857 if !containertypes.NetworkMode(nwName).IsUserDefined() { 858 createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) 859 } 860 861 opts, err := buildPortsRelatedCreateEndpointOptions(c, n, sb) 862 if err != nil { 863 return nil, err 864 } 865 createOptions = append(createOptions, opts...) 866 867 // On Windows, DNS config is a per-adapter config option whereas on Linux, it's a sandbox-wide parameter; hence why 868 // we're dealing with DNS config both here and in buildSandboxOptions. Following DNS options are only honored by 869 // Windows netdrivers, whereas DNS options in buildSandboxOptions are only honored by Linux netdrivers. 870 if !n.Internal() { 871 if len(c.HostConfig.DNS) > 0 { 872 createOptions = append(createOptions, libnetwork.CreateOptionDNS(c.HostConfig.DNS)) 873 } else if len(daemonDNS) > 0 { 874 createOptions = append(createOptions, libnetwork.CreateOptionDNS(daemonDNS)) 875 } 876 } 877 878 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOptions)) 879 880 return createOptions, nil 881 } 882 883 // buildPortsRelatedCreateEndpointOptions returns the appropriate endpoint options to apply config related to port 884 // mapping and exposed ports. 885 func buildPortsRelatedCreateEndpointOptions(c *container.Container, n *libnetwork.Network, sb *libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) { 886 // Port-mapping rules belong to the container & applicable only to non-internal networks. 887 // 888 // TODO(thaJeztah): Look if we can provide a more minimal function for getPortMapInfo, as it does a lot, and we only need the "length". 889 if n.Internal() || len(getPortMapInfo(sb)) > 0 { 890 return nil, nil 891 } 892 893 bindings := make(nat.PortMap) 894 if c.HostConfig.PortBindings != nil { 895 for p, b := range c.HostConfig.PortBindings { 896 bindings[p] = []nat.PortBinding{} 897 for _, bb := range b { 898 bindings[p] = append(bindings[p], nat.PortBinding{ 899 HostIP: bb.HostIP, 900 HostPort: bb.HostPort, 901 }) 902 } 903 } 904 } 905 906 // TODO(thaJeztah): Move this code to a method on nat.PortSet. 907 ports := make([]nat.Port, 0, len(c.Config.ExposedPorts)) 908 for p := range c.Config.ExposedPorts { 909 ports = append(ports, p) 910 } 911 nat.SortPortMap(ports, bindings) 912 913 var ( 914 exposedPorts []networktypes.TransportPort 915 publishedPorts []networktypes.PortBinding 916 ) 917 for _, port := range ports { 918 portProto := networktypes.ParseProtocol(port.Proto()) 919 portNum := uint16(port.Int()) 920 exposedPorts = append(exposedPorts, networktypes.TransportPort{ 921 Proto: portProto, 922 Port: portNum, 923 }) 924 925 for _, binding := range bindings[port] { 926 newP, err := nat.NewPort(nat.SplitProtoPort(binding.HostPort)) 927 var portStart, portEnd int 928 if err == nil { 929 portStart, portEnd, err = newP.Range() 930 } 931 if err != nil { 932 return nil, fmt.Errorf("error parsing HostPort value (%s): %w", binding.HostPort, err) 933 } 934 publishedPorts = append(publishedPorts, networktypes.PortBinding{ 935 Proto: portProto, 936 Port: portNum, 937 HostIP: net.ParseIP(binding.HostIP), 938 HostPort: uint16(portStart), 939 HostPortEnd: uint16(portEnd), 940 }) 941 } 942 943 if c.HostConfig.PublishAllPorts && len(bindings[port]) == 0 { 944 publishedPorts = append(publishedPorts, networktypes.PortBinding{ 945 Proto: portProto, 946 Port: portNum, 947 }) 948 } 949 } 950 951 return []libnetwork.EndpointOption{ 952 libnetwork.CreateOptionPortMapping(publishedPorts), 953 libnetwork.CreateOptionExposedPorts(exposedPorts), 954 }, nil 955 } 956 957 // getPortMapInfo retrieves the current port-mapping programmed for the given sandbox 958 func getPortMapInfo(sb *libnetwork.Sandbox) nat.PortMap { 959 pm := nat.PortMap{} 960 if sb == nil { 961 return pm 962 } 963 964 for _, ep := range sb.Endpoints() { 965 pm, _ = getEndpointPortMapInfo(ep) 966 if len(pm) > 0 { 967 break 968 } 969 } 970 return pm 971 } 972 973 func getEndpointPortMapInfo(ep *libnetwork.Endpoint) (nat.PortMap, error) { 974 pm := nat.PortMap{} 975 driverInfo, err := ep.DriverInfo() 976 if err != nil { 977 return pm, err 978 } 979 980 if driverInfo == nil { 981 // It is not an error for epInfo to be nil 982 return pm, nil 983 } 984 985 if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { 986 if exposedPorts, ok := expData.([]networktypes.TransportPort); ok { 987 for _, tp := range exposedPorts { 988 natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) 989 if err != nil { 990 return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err) 991 } 992 pm[natPort] = nil 993 } 994 } 995 } 996 997 mapData, ok := driverInfo[netlabel.PortMap] 998 if !ok { 999 return pm, nil 1000 } 1001 1002 if portMapping, ok := mapData.([]networktypes.PortBinding); ok { 1003 for _, pp := range portMapping { 1004 natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) 1005 if err != nil { 1006 return pm, err 1007 } 1008 natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} 1009 pm[natPort] = append(pm[natPort], natBndg) 1010 } 1011 } 1012 1013 return pm, nil 1014 } 1015 1016 // buildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint. 1017 func buildEndpointInfo(networkSettings *internalnetwork.Settings, n *libnetwork.Network, ep *libnetwork.Endpoint) error { 1018 if ep == nil { 1019 return errors.New("endpoint cannot be nil") 1020 } 1021 1022 if networkSettings == nil { 1023 return errors.New("network cannot be nil") 1024 } 1025 1026 epInfo := ep.Info() 1027 if epInfo == nil { 1028 // It is not an error to get an empty endpoint info 1029 return nil 1030 } 1031 1032 nwName := n.Name() 1033 if _, ok := networkSettings.Networks[nwName]; !ok { 1034 networkSettings.Networks[nwName] = &internalnetwork.EndpointSettings{ 1035 EndpointSettings: &network.EndpointSettings{}, 1036 } 1037 } 1038 networkSettings.Networks[nwName].NetworkID = n.ID() 1039 networkSettings.Networks[nwName].EndpointID = ep.ID() 1040 1041 iface := epInfo.Iface() 1042 if iface == nil { 1043 return nil 1044 } 1045 1046 if iface.MacAddress() != nil { 1047 networkSettings.Networks[nwName].MacAddress = iface.MacAddress().String() 1048 } 1049 1050 if iface.Address() != nil { 1051 ones, _ := iface.Address().Mask.Size() 1052 networkSettings.Networks[nwName].IPAddress = iface.Address().IP.String() 1053 networkSettings.Networks[nwName].IPPrefixLen = ones 1054 } 1055 1056 if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil { 1057 onesv6, _ := iface.AddressIPv6().Mask.Size() 1058 networkSettings.Networks[nwName].GlobalIPv6Address = iface.AddressIPv6().IP.String() 1059 networkSettings.Networks[nwName].GlobalIPv6PrefixLen = onesv6 1060 } 1061 1062 return nil 1063 } 1064 1065 // buildJoinOptions builds endpoint Join options from a given network. 1066 func buildJoinOptions(networkSettings *internalnetwork.Settings, n interface{ Name() string }) ([]libnetwork.EndpointOption, error) { 1067 var joinOptions []libnetwork.EndpointOption 1068 if epConfig, ok := networkSettings.Networks[n.Name()]; ok { 1069 for _, str := range epConfig.Links { 1070 name, alias, err := opts.ParseLink(str) 1071 if err != nil { 1072 return nil, err 1073 } 1074 joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias)) 1075 } 1076 for k, v := range epConfig.DriverOpts { 1077 joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v})) 1078 } 1079 } 1080 1081 return joinOptions, nil 1082 }