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