github.com/moby/docker@v26.1.3+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 networkOptions := make(map[string]string) 309 for k, v := range create.Options { 310 networkOptions[k] = v 311 } 312 if defaultOpts, ok := cfg.DefaultNetworkOpts[driver]; create.ConfigFrom == nil && ok { 313 for k, v := range defaultOpts { 314 if _, ok := networkOptions[k]; !ok { 315 log.G(context.TODO()).WithFields(log.Fields{"driver": driver, "network": id, k: v}).Debug("Applying network default option") 316 networkOptions[k] = v 317 } 318 } 319 } 320 321 nwOptions := []libnetwork.NetworkOption{ 322 libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6), 323 libnetwork.NetworkOptionDriverOpts(networkOptions), 324 libnetwork.NetworkOptionLabels(create.Labels), 325 libnetwork.NetworkOptionAttachable(create.Attachable), 326 libnetwork.NetworkOptionIngress(create.Ingress), 327 libnetwork.NetworkOptionScope(create.Scope), 328 } 329 330 if create.ConfigOnly { 331 nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigOnly()) 332 } 333 334 if err := network.ValidateIPAM(create.IPAM, create.EnableIPv6); err != nil { 335 if agent { 336 // This function is called with agent=false for all networks. For swarm-scoped 337 // networks, the configuration is validated but ManagerRedirectError is returned 338 // and the network is not created. Then, each time a swarm-scoped network is 339 // needed, this function is called again with agent=true. 340 // 341 // Non-swarm networks created before ValidateIPAM was introduced continue to work 342 // as they did before-upgrade, even if they would fail the new checks on creation 343 // (for example, by having host-bits set in their subnet). Those networks are not 344 // seen again here. 345 // 346 // By dropping errors for agent networks, existing swarm-scoped networks also 347 // continue to behave as they did before upgrade - but new networks are still 348 // validated. 349 log.G(context.TODO()).WithFields(log.Fields{ 350 "error": err, 351 "network": create.Name, 352 }).Warn("Continuing with validation errors in agent IPAM") 353 } else { 354 return nil, errdefs.InvalidParameter(err) 355 } 356 } 357 358 if create.IPAM != nil { 359 ipam := create.IPAM 360 v4Conf, v6Conf, err := getIpamConfig(ipam.Config) 361 if err != nil { 362 return nil, err 363 } 364 nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options)) 365 } 366 367 if create.Internal { 368 nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork()) 369 } 370 if agent { 371 nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic()) 372 nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false)) 373 } 374 375 if create.ConfigFrom != nil { 376 nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigFrom(create.ConfigFrom.Network)) 377 } 378 379 if agent && driver == "overlay" { 380 nodeIP, exists := daemon.GetAttachmentStore().GetIPForNetwork(id) 381 if !exists { 382 return nil, fmt.Errorf("failed to find a load balancer IP to use for network: %v", id) 383 } 384 385 nwOptions = append(nwOptions, libnetwork.NetworkOptionLBEndpoint(nodeIP)) 386 } 387 388 n, err := c.NewNetwork(driver, create.Name, id, nwOptions...) 389 if err != nil { 390 return nil, err 391 } 392 393 daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.Acquire) 394 if create.IPAM != nil { 395 daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.Acquire) 396 } 397 daemon.LogNetworkEvent(n, events.ActionCreate) 398 399 return &types.NetworkCreateResponse{ 400 ID: n.ID(), 401 }, nil 402 } 403 404 func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) { 405 var builtinDrivers []string 406 407 if capability == driverapi.NetworkPluginEndpointType { 408 builtinDrivers = daemon.netController.BuiltinDrivers() 409 } else if capability == ipamapi.PluginEndpointType { 410 builtinDrivers = daemon.netController.BuiltinIPAMDrivers() 411 } 412 413 for _, d := range builtinDrivers { 414 if d == driver { 415 return 416 } 417 } 418 419 if daemon.PluginStore != nil { 420 _, err := daemon.PluginStore.Get(driver, capability, mode) 421 if err != nil { 422 log.G(context.TODO()).WithError(err).WithFields(log.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation") 423 } 424 } 425 } 426 427 func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) { 428 ipamV4Cfg := []*libnetwork.IpamConf{} 429 ipamV6Cfg := []*libnetwork.IpamConf{} 430 for _, d := range data { 431 iCfg := libnetwork.IpamConf{} 432 iCfg.PreferredPool = d.Subnet 433 iCfg.SubPool = d.IPRange 434 iCfg.Gateway = d.Gateway 435 iCfg.AuxAddresses = d.AuxAddress 436 ip, _, err := net.ParseCIDR(d.Subnet) 437 if err != nil { 438 return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err) 439 } 440 if ip.To4() != nil { 441 ipamV4Cfg = append(ipamV4Cfg, &iCfg) 442 } else { 443 ipamV6Cfg = append(ipamV6Cfg, &iCfg) 444 } 445 } 446 return ipamV4Cfg, ipamV6Cfg, nil 447 } 448 449 // UpdateContainerServiceConfig updates a service configuration. 450 func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error { 451 ctr, err := daemon.GetContainer(containerName) 452 if err != nil { 453 return err 454 } 455 456 ctr.NetworkSettings.Service = serviceConfig 457 return nil 458 } 459 460 // ConnectContainerToNetwork connects the given container to the given 461 // network. If either cannot be found, an err is returned. If the 462 // network cannot be set up, an err is returned. 463 func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error { 464 ctr, err := daemon.GetContainer(containerName) 465 if err != nil { 466 return err 467 } 468 return daemon.ConnectToNetwork(ctr, networkName, endpointConfig) 469 } 470 471 // DisconnectContainerFromNetwork disconnects the given container from 472 // the given network. If either cannot be found, an err is returned. 473 func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error { 474 ctr, err := daemon.GetContainer(containerName) 475 if err != nil { 476 if force { 477 return daemon.ForceEndpointDelete(containerName, networkName) 478 } 479 return err 480 } 481 return daemon.DisconnectFromNetwork(ctr, networkName, force) 482 } 483 484 // GetNetworkDriverList returns the list of plugins drivers 485 // registered for network. 486 func (daemon *Daemon) GetNetworkDriverList(ctx context.Context) []string { 487 if !daemon.NetworkControllerEnabled() { 488 return nil 489 } 490 491 pluginList := daemon.netController.BuiltinDrivers() 492 493 managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType) 494 495 for _, plugin := range managedPlugins { 496 pluginList = append(pluginList, plugin.Name()) 497 } 498 499 pluginMap := make(map[string]bool) 500 for _, plugin := range pluginList { 501 pluginMap[plugin] = true 502 } 503 504 networks := daemon.netController.Networks(ctx) 505 506 for _, nw := range networks { 507 if !pluginMap[nw.Type()] { 508 pluginList = append(pluginList, nw.Type()) 509 pluginMap[nw.Type()] = true 510 } 511 } 512 513 sort.Strings(pluginList) 514 515 return pluginList 516 } 517 518 // DeleteManagedNetwork deletes an agent network. 519 // The requirement of networkID is enforced. 520 func (daemon *Daemon) DeleteManagedNetwork(networkID string) error { 521 n, err := daemon.GetNetworkByID(networkID) 522 if err != nil { 523 return err 524 } 525 return daemon.deleteNetwork(n, true) 526 } 527 528 // DeleteNetwork destroys a network unless it's one of docker's predefined networks. 529 func (daemon *Daemon) DeleteNetwork(networkID string) error { 530 n, err := daemon.GetNetworkByID(networkID) 531 if err != nil { 532 return fmt.Errorf("could not find network by ID: %w", err) 533 } 534 return daemon.deleteNetwork(n, false) 535 } 536 537 func (daemon *Daemon) deleteNetwork(nw *libnetwork.Network, dynamic bool) error { 538 if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic { 539 err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name()) 540 return errdefs.Forbidden(err) 541 } 542 543 if dynamic && !nw.Dynamic() { 544 if runconfig.IsPreDefinedNetwork(nw.Name()) { 545 // Predefined networks now support swarm services. Make this 546 // a no-op when cluster requests to remove the predefined network. 547 return nil 548 } 549 err := fmt.Errorf("%s is not a dynamic network", nw.Name()) 550 return errdefs.Forbidden(err) 551 } 552 553 if err := nw.Delete(); err != nil { 554 return fmt.Errorf("error while removing network: %w", err) 555 } 556 557 // If this is not a configuration only network, we need to 558 // update the corresponding remote drivers' reference counts 559 if !nw.ConfigOnly() { 560 daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.Release) 561 ipamType, _, _, _ := nw.IpamConfig() 562 daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.Release) 563 daemon.LogNetworkEvent(nw, events.ActionDestroy) 564 } 565 566 return nil 567 } 568 569 // GetNetworks returns a list of all networks 570 func (daemon *Daemon) GetNetworks(filter filters.Args, config backend.NetworkListConfig) (networks []types.NetworkResource, err error) { 571 var idx map[string]*libnetwork.Network 572 if config.Detailed { 573 idx = make(map[string]*libnetwork.Network) 574 } 575 576 allNetworks := daemon.getAllNetworks() 577 networks = make([]types.NetworkResource, 0, len(allNetworks)) 578 for _, n := range allNetworks { 579 nr := buildNetworkResource(n) 580 networks = append(networks, nr) 581 if config.Detailed { 582 idx[nr.ID] = n 583 } 584 } 585 586 networks, err = internalnetwork.FilterNetworks(networks, filter) 587 if err != nil { 588 return nil, err 589 } 590 591 if config.Detailed { 592 for i, nw := range networks { 593 networks[i].Containers = buildContainerAttachments(idx[nw.ID]) 594 if config.Verbose { 595 networks[i].Services = buildServiceAttachments(idx[nw.ID]) 596 } 597 } 598 } 599 600 return networks, nil 601 } 602 603 // buildNetworkResource builds a [types.NetworkResource] from the given 604 // [libnetwork.Network], to be returned by the API. 605 func buildNetworkResource(nw *libnetwork.Network) types.NetworkResource { 606 if nw == nil { 607 return types.NetworkResource{} 608 } 609 610 return types.NetworkResource{ 611 Name: nw.Name(), 612 ID: nw.ID(), 613 Created: nw.Created(), 614 Scope: nw.Scope(), 615 Driver: nw.Type(), 616 EnableIPv6: nw.IPv6Enabled(), 617 IPAM: buildIPAMResources(nw), 618 Internal: nw.Internal(), 619 Attachable: nw.Attachable(), 620 Ingress: nw.Ingress(), 621 ConfigFrom: network.ConfigReference{Network: nw.ConfigFrom()}, 622 ConfigOnly: nw.ConfigOnly(), 623 Containers: map[string]types.EndpointResource{}, 624 Options: nw.DriverOptions(), 625 Labels: nw.Labels(), 626 Peers: buildPeerInfoResources(nw.Peers()), 627 } 628 } 629 630 // buildContainerAttachments creates a [types.EndpointResource] map of all 631 // containers attached to the network. It is used when listing networks in 632 // detailed mode. 633 func buildContainerAttachments(nw *libnetwork.Network) map[string]types.EndpointResource { 634 containers := make(map[string]types.EndpointResource) 635 for _, e := range nw.Endpoints() { 636 ei := e.Info() 637 if ei == nil { 638 continue 639 } 640 if sb := ei.Sandbox(); sb != nil { 641 containers[sb.ContainerID()] = buildEndpointResource(e, ei) 642 } else { 643 containers["ep-"+e.ID()] = buildEndpointResource(e, ei) 644 } 645 } 646 return containers 647 } 648 649 // buildServiceAttachments creates a [network.ServiceInfo] map of all services 650 // attached to the network. It is used when listing networks in "verbose" mode. 651 func buildServiceAttachments(nw *libnetwork.Network) map[string]network.ServiceInfo { 652 services := make(map[string]network.ServiceInfo) 653 for name, service := range nw.Services() { 654 tasks := make([]network.Task, 0, len(service.Tasks)) 655 for _, t := range service.Tasks { 656 tasks = append(tasks, network.Task{ 657 Name: t.Name, 658 EndpointID: t.EndpointID, 659 EndpointIP: t.EndpointIP, 660 Info: t.Info, 661 }) 662 } 663 services[name] = network.ServiceInfo{ 664 VIP: service.VIP, 665 Ports: service.Ports, 666 Tasks: tasks, 667 LocalLBIndex: service.LocalLBIndex, 668 } 669 } 670 return services 671 } 672 673 // buildPeerInfoResources converts a list of [networkdb.PeerInfo] to a 674 // [network.PeerInfo] for inclusion in API responses. It returns nil if 675 // the list of peers is empty. 676 func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo { 677 if len(peers) == 0 { 678 return nil 679 } 680 peerInfo := make([]network.PeerInfo, 0, len(peers)) 681 for _, peer := range peers { 682 peerInfo = append(peerInfo, network.PeerInfo(peer)) 683 } 684 return peerInfo 685 } 686 687 // buildIPAMResources constructs a [network.IPAM] from the network's 688 // IPAM information for inclusion in API responses. 689 func buildIPAMResources(nw *libnetwork.Network) network.IPAM { 690 var ipamConfig []network.IPAMConfig 691 692 ipamDriver, ipamOptions, ipv4Conf, ipv6Conf := nw.IpamConfig() 693 694 hasIPv4Config := false 695 for _, cfg := range ipv4Conf { 696 if cfg.PreferredPool == "" { 697 continue 698 } 699 hasIPv4Config = true 700 ipamConfig = append(ipamConfig, network.IPAMConfig{ 701 Subnet: cfg.PreferredPool, 702 IPRange: cfg.SubPool, 703 Gateway: cfg.Gateway, 704 AuxAddress: cfg.AuxAddresses, 705 }) 706 } 707 708 hasIPv6Config := false 709 for _, cfg := range ipv6Conf { 710 if cfg.PreferredPool == "" { 711 continue 712 } 713 hasIPv6Config = true 714 ipamConfig = append(ipamConfig, network.IPAMConfig{ 715 Subnet: cfg.PreferredPool, 716 IPRange: cfg.SubPool, 717 Gateway: cfg.Gateway, 718 AuxAddress: cfg.AuxAddresses, 719 }) 720 } 721 722 if !hasIPv4Config || !hasIPv6Config { 723 ipv4Info, ipv6Info := nw.IpamInfo() 724 if !hasIPv4Config { 725 for _, info := range ipv4Info { 726 var gw string 727 if info.IPAMData.Gateway != nil { 728 gw = info.IPAMData.Gateway.IP.String() 729 } 730 ipamConfig = append(ipamConfig, network.IPAMConfig{ 731 Subnet: info.IPAMData.Pool.String(), 732 Gateway: gw, 733 }) 734 } 735 } 736 737 if !hasIPv6Config { 738 for _, info := range ipv6Info { 739 if info.IPAMData.Pool == nil { 740 continue 741 } 742 ipamConfig = append(ipamConfig, network.IPAMConfig{ 743 Subnet: info.IPAMData.Pool.String(), 744 Gateway: info.IPAMData.Gateway.String(), 745 }) 746 } 747 } 748 } 749 750 return network.IPAM{ 751 Driver: ipamDriver, 752 Options: ipamOptions, 753 Config: ipamConfig, 754 } 755 } 756 757 // buildEndpointResource combines information from the endpoint and additional 758 // endpoint-info into a [types.EndpointResource]. 759 func buildEndpointResource(ep *libnetwork.Endpoint, info libnetwork.EndpointInfo) types.EndpointResource { 760 er := types.EndpointResource{ 761 EndpointID: ep.ID(), 762 Name: ep.Name(), 763 } 764 if iface := info.Iface(); iface != nil { 765 if mac := iface.MacAddress(); mac != nil { 766 er.MacAddress = mac.String() 767 } 768 if ip := iface.Address(); ip != nil && len(ip.IP) > 0 { 769 er.IPv4Address = ip.String() 770 } 771 if ip := iface.AddressIPv6(); ip != nil && len(ip.IP) > 0 { 772 er.IPv6Address = ip.String() 773 } 774 } 775 return er 776 } 777 778 // clearAttachableNetworks removes the attachable networks 779 // after disconnecting any connected container 780 func (daemon *Daemon) clearAttachableNetworks() { 781 for _, n := range daemon.getAllNetworks() { 782 if !n.Attachable() { 783 continue 784 } 785 for _, ep := range n.Endpoints() { 786 epInfo := ep.Info() 787 if epInfo == nil { 788 continue 789 } 790 sb := epInfo.Sandbox() 791 if sb == nil { 792 continue 793 } 794 containerID := sb.ContainerID() 795 if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil { 796 log.G(context.TODO()).Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v", 797 containerID, n.Name(), err) 798 } 799 } 800 if err := daemon.DeleteManagedNetwork(n.ID()); err != nil { 801 log.G(context.TODO()).Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err) 802 } 803 } 804 } 805 806 // buildCreateEndpointOptions builds endpoint options from a given network. 807 func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *internalnetwork.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) { 808 var createOptions []libnetwork.EndpointOption 809 var genericOptions = make(options.Generic) 810 811 nwName := n.Name() 812 813 if epConfig != nil { 814 if ipam := epConfig.IPAMConfig; ipam != nil { 815 var ipList []net.IP 816 for _, ips := range ipam.LinkLocalIPs { 817 linkIP := net.ParseIP(ips) 818 if linkIP == nil && ips != "" { 819 return nil, fmt.Errorf("invalid link-local IP address: %s", ipam.LinkLocalIPs) 820 } 821 ipList = append(ipList, linkIP) 822 } 823 824 ip := net.ParseIP(ipam.IPv4Address) 825 if ip == nil && ipam.IPv4Address != "" { 826 return nil, fmt.Errorf("invalid IPv4 address: %s", ipam.IPv4Address) 827 } 828 829 ip6 := net.ParseIP(ipam.IPv6Address) 830 if ip6 == nil && ipam.IPv6Address != "" { 831 return nil, fmt.Errorf("invalid IPv6 address: %s", ipam.IPv6Address) 832 } 833 834 createOptions = append(createOptions, libnetwork.CreateOptionIpam(ip, ip6, ipList, nil)) 835 } 836 837 createOptions = append(createOptions, libnetwork.CreateOptionDNSNames(epConfig.DNSNames)) 838 839 for k, v := range epConfig.DriverOpts { 840 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v})) 841 } 842 843 if epConfig.DesiredMacAddress != "" { 844 mac, err := net.ParseMAC(epConfig.DesiredMacAddress) 845 if err != nil { 846 return nil, err 847 } 848 genericOptions[netlabel.MacAddress] = mac 849 } 850 } 851 852 if svcCfg := c.NetworkSettings.Service; svcCfg != nil { 853 nwID := n.ID() 854 855 var vip net.IP 856 if virtualAddress := svcCfg.VirtualAddresses[nwID]; virtualAddress != nil { 857 vip = net.ParseIP(virtualAddress.IPv4) 858 } 859 860 var portConfigs []*libnetwork.PortConfig 861 for _, portConfig := range svcCfg.ExposedPorts { 862 portConfigs = append(portConfigs, &libnetwork.PortConfig{ 863 Name: portConfig.Name, 864 Protocol: libnetwork.PortConfig_Protocol(portConfig.Protocol), 865 TargetPort: portConfig.TargetPort, 866 PublishedPort: portConfig.PublishedPort, 867 }) 868 } 869 870 createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, vip, portConfigs, svcCfg.Aliases[nwID])) 871 } 872 873 if !containertypes.NetworkMode(nwName).IsUserDefined() { 874 createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) 875 } 876 877 opts, err := buildPortsRelatedCreateEndpointOptions(c, n, sb) 878 if err != nil { 879 return nil, err 880 } 881 createOptions = append(createOptions, opts...) 882 883 // On Windows, DNS config is a per-adapter config option whereas on Linux, it's a sandbox-wide parameter; hence why 884 // we're dealing with DNS config both here and in buildSandboxOptions. Following DNS options are only honored by 885 // Windows netdrivers, whereas DNS options in buildSandboxOptions are only honored by Linux netdrivers. 886 if !n.Internal() { 887 if len(c.HostConfig.DNS) > 0 { 888 createOptions = append(createOptions, libnetwork.CreateOptionDNS(c.HostConfig.DNS)) 889 } else if len(daemonDNS) > 0 { 890 createOptions = append(createOptions, libnetwork.CreateOptionDNS(daemonDNS)) 891 } 892 } 893 894 createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOptions)) 895 896 return createOptions, nil 897 } 898 899 // buildPortsRelatedCreateEndpointOptions returns the appropriate endpoint options to apply config related to port 900 // mapping and exposed ports. 901 func buildPortsRelatedCreateEndpointOptions(c *container.Container, n *libnetwork.Network, sb *libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) { 902 // Port-mapping rules belong to the container & applicable only to non-internal networks. 903 // 904 // TODO(thaJeztah): Look if we can provide a more minimal function for getPortMapInfo, as it does a lot, and we only need the "length". 905 if n.Internal() || len(getPortMapInfo(sb)) > 0 { 906 return nil, nil 907 } 908 909 bindings := make(nat.PortMap) 910 if c.HostConfig.PortBindings != nil { 911 for p, b := range c.HostConfig.PortBindings { 912 bindings[p] = []nat.PortBinding{} 913 for _, bb := range b { 914 bindings[p] = append(bindings[p], nat.PortBinding{ 915 HostIP: bb.HostIP, 916 HostPort: bb.HostPort, 917 }) 918 } 919 } 920 } 921 922 // TODO(thaJeztah): Move this code to a method on nat.PortSet. 923 ports := make([]nat.Port, 0, len(c.Config.ExposedPorts)) 924 for p := range c.Config.ExposedPorts { 925 ports = append(ports, p) 926 } 927 nat.SortPortMap(ports, bindings) 928 929 var ( 930 exposedPorts []networktypes.TransportPort 931 publishedPorts []networktypes.PortBinding 932 ) 933 for _, port := range ports { 934 portProto := networktypes.ParseProtocol(port.Proto()) 935 portNum := uint16(port.Int()) 936 exposedPorts = append(exposedPorts, networktypes.TransportPort{ 937 Proto: portProto, 938 Port: portNum, 939 }) 940 941 for _, binding := range bindings[port] { 942 newP, err := nat.NewPort(nat.SplitProtoPort(binding.HostPort)) 943 var portStart, portEnd int 944 if err == nil { 945 portStart, portEnd, err = newP.Range() 946 } 947 if err != nil { 948 return nil, fmt.Errorf("error parsing HostPort value (%s): %w", binding.HostPort, err) 949 } 950 publishedPorts = append(publishedPorts, networktypes.PortBinding{ 951 Proto: portProto, 952 Port: portNum, 953 HostIP: net.ParseIP(binding.HostIP), 954 HostPort: uint16(portStart), 955 HostPortEnd: uint16(portEnd), 956 }) 957 } 958 959 if c.HostConfig.PublishAllPorts && len(bindings[port]) == 0 { 960 publishedPorts = append(publishedPorts, networktypes.PortBinding{ 961 Proto: portProto, 962 Port: portNum, 963 }) 964 } 965 } 966 967 return []libnetwork.EndpointOption{ 968 libnetwork.CreateOptionPortMapping(publishedPorts), 969 libnetwork.CreateOptionExposedPorts(exposedPorts), 970 }, nil 971 } 972 973 // getPortMapInfo retrieves the current port-mapping programmed for the given sandbox 974 func getPortMapInfo(sb *libnetwork.Sandbox) nat.PortMap { 975 pm := nat.PortMap{} 976 if sb == nil { 977 return pm 978 } 979 980 for _, ep := range sb.Endpoints() { 981 pm, _ = getEndpointPortMapInfo(ep) 982 if len(pm) > 0 { 983 break 984 } 985 } 986 return pm 987 } 988 989 func getEndpointPortMapInfo(ep *libnetwork.Endpoint) (nat.PortMap, error) { 990 pm := nat.PortMap{} 991 driverInfo, err := ep.DriverInfo() 992 if err != nil { 993 return pm, err 994 } 995 996 if driverInfo == nil { 997 // It is not an error for epInfo to be nil 998 return pm, nil 999 } 1000 1001 if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { 1002 if exposedPorts, ok := expData.([]networktypes.TransportPort); ok { 1003 for _, tp := range exposedPorts { 1004 natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) 1005 if err != nil { 1006 return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err) 1007 } 1008 pm[natPort] = nil 1009 } 1010 } 1011 } 1012 1013 mapData, ok := driverInfo[netlabel.PortMap] 1014 if !ok { 1015 return pm, nil 1016 } 1017 1018 if portMapping, ok := mapData.([]networktypes.PortBinding); ok { 1019 for _, pp := range portMapping { 1020 natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) 1021 if err != nil { 1022 return pm, err 1023 } 1024 natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} 1025 pm[natPort] = append(pm[natPort], natBndg) 1026 } 1027 } 1028 1029 return pm, nil 1030 } 1031 1032 // buildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint. 1033 func buildEndpointInfo(networkSettings *internalnetwork.Settings, n *libnetwork.Network, ep *libnetwork.Endpoint) error { 1034 if ep == nil { 1035 return errors.New("endpoint cannot be nil") 1036 } 1037 1038 if networkSettings == nil { 1039 return errors.New("network cannot be nil") 1040 } 1041 1042 epInfo := ep.Info() 1043 if epInfo == nil { 1044 // It is not an error to get an empty endpoint info 1045 return nil 1046 } 1047 1048 nwName := n.Name() 1049 if _, ok := networkSettings.Networks[nwName]; !ok { 1050 networkSettings.Networks[nwName] = &internalnetwork.EndpointSettings{ 1051 EndpointSettings: &network.EndpointSettings{}, 1052 } 1053 } 1054 networkSettings.Networks[nwName].NetworkID = n.ID() 1055 networkSettings.Networks[nwName].EndpointID = ep.ID() 1056 1057 iface := epInfo.Iface() 1058 if iface == nil { 1059 return nil 1060 } 1061 1062 if iface.MacAddress() != nil { 1063 networkSettings.Networks[nwName].MacAddress = iface.MacAddress().String() 1064 } 1065 1066 if iface.Address() != nil { 1067 ones, _ := iface.Address().Mask.Size() 1068 networkSettings.Networks[nwName].IPAddress = iface.Address().IP.String() 1069 networkSettings.Networks[nwName].IPPrefixLen = ones 1070 } 1071 1072 if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil { 1073 onesv6, _ := iface.AddressIPv6().Mask.Size() 1074 networkSettings.Networks[nwName].GlobalIPv6Address = iface.AddressIPv6().IP.String() 1075 networkSettings.Networks[nwName].GlobalIPv6PrefixLen = onesv6 1076 } 1077 1078 return nil 1079 } 1080 1081 // buildJoinOptions builds endpoint Join options from a given network. 1082 func buildJoinOptions(networkSettings *internalnetwork.Settings, n interface{ Name() string }) ([]libnetwork.EndpointOption, error) { 1083 var joinOptions []libnetwork.EndpointOption 1084 if epConfig, ok := networkSettings.Networks[n.Name()]; ok { 1085 for _, str := range epConfig.Links { 1086 name, alias, err := opts.ParseLink(str) 1087 if err != nil { 1088 return nil, err 1089 } 1090 joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias)) 1091 } 1092 for k, v := range epConfig.DriverOpts { 1093 joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v})) 1094 } 1095 } 1096 1097 return joinOptions, nil 1098 }