github.com/khulnasoft-lab/khulnasoft@v26.0.1-0.20240328202558-330a6f959fe0+incompatible/libnetwork/controller.go (about) 1 /* 2 Package libnetwork provides the basic functionality and extension points to 3 create network namespaces and allocate interfaces for containers to use. 4 5 networkType := "bridge" 6 7 // Create a new controller instance 8 driverOptions := options.Generic{} 9 genericOption := make(map[string]interface{}) 10 genericOption[netlabel.GenericData] = driverOptions 11 controller, err := libnetwork.New(config.OptionDriverConfig(networkType, genericOption)) 12 if err != nil { 13 return 14 } 15 16 // Create a network for containers to join. 17 // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make use of 18 network, err := controller.NewNetwork(networkType, "network1", "") 19 if err != nil { 20 return 21 } 22 23 // For each new container: allocate IP and interfaces. The returned network 24 // settings will be used for container infos (inspect and such), as well as 25 // iptables rules for port publishing. This info is contained or accessible 26 // from the returned endpoint. 27 ep, err := network.CreateEndpoint("Endpoint1") 28 if err != nil { 29 return 30 } 31 32 // Create the sandbox for the container. 33 // NewSandbox accepts Variadic optional arguments which libnetwork can use. 34 sbx, err := controller.NewSandbox("container1", 35 libnetwork.OptionHostname("test"), 36 libnetwork.OptionDomainname("example.com")) 37 38 // A sandbox can join the endpoint via the join api. 39 err = ep.Join(sbx) 40 if err != nil { 41 return 42 } 43 */ 44 package libnetwork 45 46 import ( 47 "context" 48 "fmt" 49 "net" 50 "path/filepath" 51 "runtime" 52 "strings" 53 "sync" 54 "time" 55 56 "github.com/containerd/log" 57 "github.com/docker/docker/libnetwork/cluster" 58 "github.com/docker/docker/libnetwork/config" 59 "github.com/docker/docker/libnetwork/datastore" 60 "github.com/docker/docker/libnetwork/diagnostic" 61 "github.com/docker/docker/libnetwork/discoverapi" 62 "github.com/docker/docker/libnetwork/driverapi" 63 remotedriver "github.com/docker/docker/libnetwork/drivers/remote" 64 "github.com/docker/docker/libnetwork/drvregistry" 65 "github.com/docker/docker/libnetwork/ipamapi" 66 "github.com/docker/docker/libnetwork/netlabel" 67 "github.com/docker/docker/libnetwork/osl" 68 "github.com/docker/docker/libnetwork/scope" 69 "github.com/docker/docker/libnetwork/types" 70 "github.com/docker/docker/pkg/plugingetter" 71 "github.com/docker/docker/pkg/plugins" 72 "github.com/docker/docker/pkg/stringid" 73 "github.com/moby/locker" 74 "github.com/pkg/errors" 75 ) 76 77 // NetworkWalker is a client provided function which will be used to walk the Networks. 78 // When the function returns true, the walk will stop. 79 type NetworkWalker func(nw *Network) bool 80 81 // Controller manages networks. 82 type Controller struct { 83 id string 84 drvRegistry drvregistry.Networks 85 ipamRegistry drvregistry.IPAMs 86 sandboxes map[string]*Sandbox 87 cfg *config.Config 88 store *datastore.Store 89 extKeyListener net.Listener 90 svcRecords map[string]*svcInfo 91 serviceBindings map[serviceKey]*service 92 ingressSandbox *Sandbox 93 agent *nwAgent 94 networkLocker *locker.Locker 95 agentInitDone chan struct{} 96 agentStopDone chan struct{} 97 keys []*types.EncryptionKey 98 DiagnosticServer *diagnostic.Server 99 mu sync.Mutex 100 101 // FIXME(thaJeztah): defOsSbox is always nil on non-Linux: move these fields to Linux-only files. 102 defOsSboxOnce sync.Once 103 defOsSbox *osl.Namespace 104 } 105 106 // New creates a new instance of network controller. 107 func New(cfgOptions ...config.Option) (*Controller, error) { 108 c := &Controller{ 109 id: stringid.GenerateRandomID(), 110 cfg: config.New(cfgOptions...), 111 sandboxes: map[string]*Sandbox{}, 112 svcRecords: make(map[string]*svcInfo), 113 serviceBindings: make(map[serviceKey]*service), 114 agentInitDone: make(chan struct{}), 115 networkLocker: locker.New(), 116 DiagnosticServer: diagnostic.New(), 117 } 118 119 if err := c.initStores(); err != nil { 120 return nil, err 121 } 122 123 c.drvRegistry.Notify = c 124 125 // External plugins don't need config passed through daemon. They can 126 // bootstrap themselves. 127 if err := remotedriver.Register(&c.drvRegistry, c.cfg.PluginGetter); err != nil { 128 return nil, err 129 } 130 131 if err := registerNetworkDrivers(&c.drvRegistry, c.makeDriverConfig); err != nil { 132 return nil, err 133 } 134 135 if err := initIPAMDrivers(&c.ipamRegistry, c.cfg.PluginGetter, c.cfg.DefaultAddressPool); err != nil { 136 return nil, err 137 } 138 139 c.WalkNetworks(func(nw *Network) bool { 140 if n := nw; n.hasSpecialDriver() && !n.ConfigOnly() { 141 if err := n.getController().addNetwork(n); err != nil { 142 log.G(context.TODO()).Warnf("Failed to populate network %q with driver %q", nw.Name(), nw.Type()) 143 } 144 } 145 return false 146 }) 147 148 // Reserve pools first before doing cleanup. Otherwise the 149 // cleanups of endpoint/network and sandbox below will 150 // generate many unnecessary warnings 151 c.reservePools() 152 153 // Cleanup resources 154 if err := c.sandboxCleanup(c.cfg.ActiveSandboxes); err != nil { 155 log.G(context.TODO()).WithError(err).Error("error during sandbox cleanup") 156 } 157 if err := c.cleanupLocalEndpoints(); err != nil { 158 log.G(context.TODO()).WithError(err).Warnf("error during endpoint cleanup") 159 } 160 c.networkCleanup() 161 162 if err := c.startExternalKeyListener(); err != nil { 163 return nil, err 164 } 165 166 setupArrangeUserFilterRule(c) 167 return c, nil 168 } 169 170 // SetClusterProvider sets the cluster provider. 171 func (c *Controller) SetClusterProvider(provider cluster.Provider) { 172 var sameProvider bool 173 c.mu.Lock() 174 // Avoids to spawn multiple goroutine for the same cluster provider 175 if c.cfg.ClusterProvider == provider { 176 // If the cluster provider is already set, there is already a go routine spawned 177 // that is listening for events, so nothing to do here 178 sameProvider = true 179 } else { 180 c.cfg.ClusterProvider = provider 181 } 182 c.mu.Unlock() 183 184 if provider == nil || sameProvider { 185 return 186 } 187 // We don't want to spawn a new go routine if the previous one did not exit yet 188 c.AgentStopWait() 189 go c.clusterAgentInit() 190 } 191 192 // SetKeys configures the encryption key for gossip and overlay data path. 193 func (c *Controller) SetKeys(keys []*types.EncryptionKey) error { 194 // libnetwork side of agent depends on the keys. On the first receipt of 195 // keys setup the agent. For subsequent key set handle the key change 196 subsysKeys := make(map[string]int) 197 for _, key := range keys { 198 if key.Subsystem != subsysGossip && 199 key.Subsystem != subsysIPSec { 200 return fmt.Errorf("key received for unrecognized subsystem") 201 } 202 subsysKeys[key.Subsystem]++ 203 } 204 for s, count := range subsysKeys { 205 if count != keyringSize { 206 return fmt.Errorf("incorrect number of keys for subsystem %v", s) 207 } 208 } 209 210 if c.getAgent() == nil { 211 c.mu.Lock() 212 c.keys = keys 213 c.mu.Unlock() 214 return nil 215 } 216 return c.handleKeyChange(keys) 217 } 218 219 func (c *Controller) getAgent() *nwAgent { 220 c.mu.Lock() 221 defer c.mu.Unlock() 222 return c.agent 223 } 224 225 func (c *Controller) clusterAgentInit() { 226 clusterProvider := c.cfg.ClusterProvider 227 var keysAvailable bool 228 for { 229 eventType := <-clusterProvider.ListenClusterEvents() 230 // The events: EventSocketChange, EventNodeReady and EventNetworkKeysAvailable are not ordered 231 // when all the condition for the agent initialization are met then proceed with it 232 switch eventType { 233 case cluster.EventNetworkKeysAvailable: 234 // Validates that the keys are actually available before starting the initialization 235 // This will handle old spurious messages left on the channel 236 c.mu.Lock() 237 keysAvailable = c.keys != nil 238 c.mu.Unlock() 239 fallthrough 240 case cluster.EventSocketChange, cluster.EventNodeReady: 241 if keysAvailable && c.isSwarmNode() { 242 c.agentOperationStart() 243 if err := c.agentSetup(clusterProvider); err != nil { 244 c.agentStopComplete() 245 } else { 246 c.agentInitComplete() 247 } 248 } 249 case cluster.EventNodeLeave: 250 c.agentOperationStart() 251 c.mu.Lock() 252 c.keys = nil 253 c.mu.Unlock() 254 255 // We are leaving the cluster. Make sure we 256 // close the gossip so that we stop all 257 // incoming gossip updates before cleaning up 258 // any remaining service bindings. But before 259 // deleting the networks since the networks 260 // should still be present when cleaning up 261 // service bindings 262 c.agentClose() 263 c.cleanupServiceDiscovery("") 264 c.cleanupServiceBindings("") 265 266 c.agentStopComplete() 267 268 return 269 } 270 } 271 } 272 273 // AgentInitWait waits for agent initialization to be completed in the controller. 274 func (c *Controller) AgentInitWait() { 275 c.mu.Lock() 276 agentInitDone := c.agentInitDone 277 c.mu.Unlock() 278 279 if agentInitDone != nil { 280 <-agentInitDone 281 } 282 } 283 284 // AgentStopWait waits for the Agent stop to be completed in the controller. 285 func (c *Controller) AgentStopWait() { 286 c.mu.Lock() 287 agentStopDone := c.agentStopDone 288 c.mu.Unlock() 289 if agentStopDone != nil { 290 <-agentStopDone 291 } 292 } 293 294 // agentOperationStart marks the start of an Agent Init or Agent Stop 295 func (c *Controller) agentOperationStart() { 296 c.mu.Lock() 297 if c.agentInitDone == nil { 298 c.agentInitDone = make(chan struct{}) 299 } 300 if c.agentStopDone == nil { 301 c.agentStopDone = make(chan struct{}) 302 } 303 c.mu.Unlock() 304 } 305 306 // agentInitComplete notifies the successful completion of the Agent initialization 307 func (c *Controller) agentInitComplete() { 308 c.mu.Lock() 309 if c.agentInitDone != nil { 310 close(c.agentInitDone) 311 c.agentInitDone = nil 312 } 313 c.mu.Unlock() 314 } 315 316 // agentStopComplete notifies the successful completion of the Agent stop 317 func (c *Controller) agentStopComplete() { 318 c.mu.Lock() 319 if c.agentStopDone != nil { 320 close(c.agentStopDone) 321 c.agentStopDone = nil 322 } 323 c.mu.Unlock() 324 } 325 326 func (c *Controller) makeDriverConfig(ntype string) map[string]interface{} { 327 if c.cfg == nil { 328 return nil 329 } 330 331 cfg := map[string]interface{}{} 332 for _, label := range c.cfg.Labels { 333 key, val, _ := strings.Cut(label, "=") 334 if !strings.HasPrefix(key, netlabel.DriverPrefix+"."+ntype) { 335 continue 336 } 337 338 cfg[key] = val 339 } 340 341 // Merge in the existing config for this driver. 342 for k, v := range c.cfg.DriverConfig(ntype) { 343 cfg[k] = v 344 } 345 346 if c.cfg.Scope.IsValid() { 347 cfg[netlabel.LocalKVClient] = c.store 348 } 349 350 return cfg 351 } 352 353 // ID returns the controller's unique identity. 354 func (c *Controller) ID() string { 355 return c.id 356 } 357 358 // BuiltinDrivers returns the list of builtin network drivers. 359 func (c *Controller) BuiltinDrivers() []string { 360 drivers := []string{} 361 c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { 362 if driver.IsBuiltIn() { 363 drivers = append(drivers, name) 364 } 365 return false 366 }) 367 return drivers 368 } 369 370 // BuiltinIPAMDrivers returns the list of builtin ipam drivers. 371 func (c *Controller) BuiltinIPAMDrivers() []string { 372 drivers := []string{} 373 c.ipamRegistry.WalkIPAMs(func(name string, driver ipamapi.Ipam, _ *ipamapi.Capability) bool { 374 if driver.IsBuiltIn() { 375 drivers = append(drivers, name) 376 } 377 return false 378 }) 379 return drivers 380 } 381 382 func (c *Controller) processNodeDiscovery(nodes []net.IP, add bool) { 383 c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { 384 if d, ok := driver.(discoverapi.Discover); ok { 385 c.pushNodeDiscovery(d, capability, nodes, add) 386 } 387 return false 388 }) 389 } 390 391 func (c *Controller) pushNodeDiscovery(d discoverapi.Discover, capability driverapi.Capability, nodes []net.IP, add bool) { 392 var self net.IP 393 // try swarm-mode config 394 if agent := c.getAgent(); agent != nil { 395 self = net.ParseIP(agent.advertiseAddr) 396 } 397 398 if d == nil || capability.ConnectivityScope != scope.Global || nodes == nil { 399 return 400 } 401 402 for _, node := range nodes { 403 nodeData := discoverapi.NodeDiscoveryData{Address: node.String(), Self: node.Equal(self)} 404 var err error 405 if add { 406 err = d.DiscoverNew(discoverapi.NodeDiscovery, nodeData) 407 } else { 408 err = d.DiscoverDelete(discoverapi.NodeDiscovery, nodeData) 409 } 410 if err != nil { 411 log.G(context.TODO()).Debugf("discovery notification error: %v", err) 412 } 413 } 414 } 415 416 // Config returns the bootup configuration for the controller. 417 func (c *Controller) Config() config.Config { 418 c.mu.Lock() 419 defer c.mu.Unlock() 420 if c.cfg == nil { 421 return config.Config{} 422 } 423 return *c.cfg 424 } 425 426 func (c *Controller) isManager() bool { 427 c.mu.Lock() 428 defer c.mu.Unlock() 429 if c.cfg == nil || c.cfg.ClusterProvider == nil { 430 return false 431 } 432 return c.cfg.ClusterProvider.IsManager() 433 } 434 435 func (c *Controller) isAgent() bool { 436 c.mu.Lock() 437 defer c.mu.Unlock() 438 if c.cfg == nil || c.cfg.ClusterProvider == nil { 439 return false 440 } 441 return c.cfg.ClusterProvider.IsAgent() 442 } 443 444 func (c *Controller) isSwarmNode() bool { 445 return c.isManager() || c.isAgent() 446 } 447 448 func (c *Controller) GetPluginGetter() plugingetter.PluginGetter { 449 return c.cfg.PluginGetter 450 } 451 452 func (c *Controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error { 453 if d, ok := driver.(discoverapi.Discover); ok { 454 c.agentDriverNotify(d) 455 } 456 return nil 457 } 458 459 // XXX This should be made driver agnostic. See comment below. 460 const overlayDSROptionString = "dsr" 461 462 // NewNetwork creates a new network of the specified network type. The options 463 // are network specific and modeled in a generic way. 464 func (c *Controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (_ *Network, retErr error) { 465 if id != "" { 466 c.networkLocker.Lock(id) 467 defer c.networkLocker.Unlock(id) //nolint:errcheck 468 469 if _, err := c.NetworkByID(id); err == nil { 470 return nil, NetworkNameError(id) 471 } 472 } 473 474 if strings.TrimSpace(name) == "" { 475 return nil, ErrInvalidName(name) 476 } 477 478 // Make sure two concurrent calls to this method won't create conflicting 479 // networks, otherwise libnetwork will end up in an invalid state. 480 if name != "" { 481 c.networkLocker.Lock(name) 482 defer c.networkLocker.Unlock(name) 483 484 if _, err := c.NetworkByName(name); err == nil { 485 return nil, NetworkNameError(name) 486 } 487 } 488 489 if id == "" { 490 id = stringid.GenerateRandomID() 491 } 492 493 defaultIpam := defaultIpamForNetworkType(networkType) 494 // Construct the network object 495 nw := &Network{ 496 name: name, 497 networkType: networkType, 498 generic: map[string]interface{}{netlabel.GenericData: make(map[string]string)}, 499 ipamType: defaultIpam, 500 id: id, 501 created: time.Now(), 502 ctrlr: c, 503 persist: true, 504 drvOnce: &sync.Once{}, 505 loadBalancerMode: loadBalancerModeDefault, 506 } 507 508 nw.processOptions(options...) 509 if err := nw.validateConfiguration(); err != nil { 510 return nil, err 511 } 512 513 // These variables must be defined here, as declaration would otherwise 514 // be skipped by the "goto addToStore" 515 var ( 516 caps driverapi.Capability 517 err error 518 519 skipCfgEpCount bool 520 ) 521 522 // Reset network types, force local scope and skip allocation and 523 // plumbing for configuration networks. Reset of the config-only 524 // network drivers is needed so that this special network is not 525 // usable by old engine versions. 526 if nw.configOnly { 527 nw.scope = scope.Local 528 nw.networkType = "null" 529 goto addToStore 530 } 531 532 _, caps, err = nw.resolveDriver(nw.networkType, true) 533 if err != nil { 534 return nil, err 535 } 536 537 if nw.scope == scope.Local && caps.DataScope == scope.Global { 538 return nil, types.ForbiddenErrorf("cannot downgrade network scope for %s networks", networkType) 539 } 540 if nw.ingress && caps.DataScope != scope.Global { 541 return nil, types.ForbiddenErrorf("Ingress network can only be global scope network") 542 } 543 544 // At this point the network scope is still unknown if not set by user 545 if (caps.DataScope == scope.Global || nw.scope == scope.Swarm) && 546 c.isSwarmNode() && !nw.dynamic { 547 if c.isManager() { 548 // For non-distributed controlled environment, globalscoped non-dynamic networks are redirected to Manager 549 return nil, ManagerRedirectError(name) 550 } 551 return nil, types.ForbiddenErrorf("Cannot create a multi-host network from a worker node. Please create the network from a manager node.") 552 } 553 554 if nw.scope == scope.Swarm && !c.isSwarmNode() { 555 return nil, types.ForbiddenErrorf("cannot create a swarm scoped network when swarm is not active") 556 } 557 558 // Make sure we have a driver available for this network type 559 // before we allocate anything. 560 if _, err := nw.driver(true); err != nil { 561 return nil, err 562 } 563 564 // From this point on, we need the network specific configuration, 565 // which may come from a configuration-only network 566 if nw.configFrom != "" { 567 configNetwork, err := c.getConfigNetwork(nw.configFrom) 568 if err != nil { 569 return nil, types.NotFoundErrorf("configuration network %q does not exist", nw.configFrom) 570 } 571 if err := configNetwork.applyConfigurationTo(nw); err != nil { 572 return nil, types.InternalErrorf("Failed to apply configuration: %v", err) 573 } 574 nw.generic[netlabel.Internal] = nw.internal 575 defer func() { 576 if retErr == nil && !skipCfgEpCount { 577 if err := configNetwork.getEpCnt().IncEndpointCnt(); err != nil { 578 log.G(context.TODO()).Warnf("Failed to update reference count for configuration network %q on creation of network %q: %v", configNetwork.Name(), nw.name, err) 579 } 580 } 581 }() 582 } 583 584 if err := nw.ipamAllocate(); err != nil { 585 return nil, err 586 } 587 defer func() { 588 if retErr != nil { 589 nw.ipamRelease() 590 } 591 }() 592 593 // Note from thaJeztah to future code visitors, or "future self". 594 // 595 // This code was previously assigning the error to the global "err" 596 // variable (before it was renamed to "retErr"), but in case of a 597 // "MaskableError" did not *return* the error: 598 // https://github.com/moby/moby/blob/b325dcbff60a04cedbe40eb627465fc7379d05bf/libnetwork/controller.go#L566-L573 599 // 600 // Depending on code paths further down, that meant that this error 601 // was either overwritten by other errors (and thus not handled in 602 // defer statements) or handled (if no other code was overwriting it. 603 // 604 // I suspect this was a bug (but possible without effect), but it could 605 // have been intentional. This logic is confusing at least, and even 606 // more so combined with the handling in defer statements that check for 607 // both the "err" return AND "skipCfgEpCount": 608 // https://github.com/moby/moby/blob/b325dcbff60a04cedbe40eb627465fc7379d05bf/libnetwork/controller.go#L586-L602 609 // 610 // To save future visitors some time to dig up history: 611 // 612 // - config-only networks were added in 25082206df465d1c11dd1276a65b4a1dc701bd43 613 // - the special error-handling and "skipCfgEpcoung" was added in ddd22a819867faa0cd7d12b0c3fad1099ac3eb26 614 // - and updated in 87b082f3659f9ec245ab15d781e6bfffced0af83 to don't use string-matching 615 // 616 // To cut a long story short: if this broke anything, you know who to blame :) 617 if err := c.addNetwork(nw); err != nil { 618 if _, ok := err.(types.MaskableError); ok { //nolint:gosimple 619 // This error can be ignored and set this boolean 620 // value to skip a refcount increment for configOnly networks 621 skipCfgEpCount = true 622 } else { 623 return nil, err 624 } 625 } 626 defer func() { 627 if retErr != nil { 628 if err := nw.deleteNetwork(); err != nil { 629 log.G(context.TODO()).Warnf("couldn't roll back driver network on network %s creation failure: %v", nw.name, retErr) 630 } 631 } 632 }() 633 634 // XXX If the driver type is "overlay" check the options for DSR 635 // being set. If so, set the network's load balancing mode to DSR. 636 // This should really be done in a network option, but due to 637 // time pressure to get this in without adding changes to moby, 638 // swarm and CLI, it is being implemented as a driver-specific 639 // option. Unfortunately, drivers can't influence the core 640 // "libnetwork.Network" data type. Hence we need this hack code 641 // to implement in this manner. 642 if gval, ok := nw.generic[netlabel.GenericData]; ok && nw.networkType == "overlay" { 643 optMap := gval.(map[string]string) 644 if _, ok := optMap[overlayDSROptionString]; ok { 645 nw.loadBalancerMode = loadBalancerModeDSR 646 } 647 } 648 649 addToStore: 650 // First store the endpoint count, then the network. To avoid to 651 // end up with a datastore containing a network and not an epCnt, 652 // in case of an ungraceful shutdown during this function call. 653 epCnt := &endpointCnt{n: nw} 654 if err := c.updateToStore(epCnt); err != nil { 655 return nil, err 656 } 657 defer func() { 658 if retErr != nil { 659 if err := c.deleteFromStore(epCnt); err != nil { 660 log.G(context.TODO()).Warnf("could not rollback from store, epCnt %v on failure (%v): %v", epCnt, retErr, err) 661 } 662 } 663 }() 664 665 nw.epCnt = epCnt 666 if err := c.updateToStore(nw); err != nil { 667 return nil, err 668 } 669 defer func() { 670 if retErr != nil { 671 if err := c.deleteFromStore(nw); err != nil { 672 log.G(context.TODO()).Warnf("could not rollback from store, network %v on failure (%v): %v", nw, retErr, err) 673 } 674 } 675 }() 676 677 if nw.configOnly { 678 return nw, nil 679 } 680 681 joinCluster(nw) 682 defer func() { 683 if retErr != nil { 684 nw.cancelDriverWatches() 685 if err := nw.leaveCluster(); err != nil { 686 log.G(context.TODO()).Warnf("Failed to leave agent cluster on network %s on failure (%v): %v", nw.name, retErr, err) 687 } 688 } 689 }() 690 691 if nw.hasLoadBalancerEndpoint() { 692 if err := nw.createLoadBalancerSandbox(); err != nil { 693 return nil, err 694 } 695 } 696 697 if c.isSwarmNode() { 698 c.mu.Lock() 699 arrangeIngressFilterRule() 700 c.mu.Unlock() 701 } 702 703 // Sets up the DOCKER-USER chain for each iptables version (IPv4, IPv6) 704 // that's enabled in the controller's configuration. 705 for _, ipVersion := range c.enabledIptablesVersions() { 706 if err := setupUserChain(ipVersion); err != nil { 707 log.G(context.TODO()).WithError(err).Warnf("Controller.NewNetwork %s:", name) 708 } 709 } 710 711 return nw, nil 712 } 713 714 var joinCluster NetworkWalker = func(nw *Network) bool { 715 if nw.configOnly { 716 return false 717 } 718 if err := nw.joinCluster(); err != nil { 719 log.G(context.TODO()).Errorf("Failed to join network %s (%s) into agent cluster: %v", nw.Name(), nw.ID(), err) 720 } 721 nw.addDriverWatches() 722 return false 723 } 724 725 func (c *Controller) reservePools() { 726 networks, err := c.getNetworks() 727 if err != nil { 728 log.G(context.TODO()).Warnf("Could not retrieve networks from local store during ipam allocation for existing networks: %v", err) 729 return 730 } 731 732 for _, n := range networks { 733 if n.configOnly { 734 continue 735 } 736 if !doReplayPoolReserve(n) { 737 continue 738 } 739 // Construct pseudo configs for the auto IP case 740 autoIPv4 := (len(n.ipamV4Config) == 0 || (len(n.ipamV4Config) == 1 && n.ipamV4Config[0].PreferredPool == "")) && len(n.ipamV4Info) > 0 741 autoIPv6 := (len(n.ipamV6Config) == 0 || (len(n.ipamV6Config) == 1 && n.ipamV6Config[0].PreferredPool == "")) && len(n.ipamV6Info) > 0 742 if autoIPv4 { 743 n.ipamV4Config = []*IpamConf{{PreferredPool: n.ipamV4Info[0].Pool.String()}} 744 } 745 if n.enableIPv6 && autoIPv6 { 746 n.ipamV6Config = []*IpamConf{{PreferredPool: n.ipamV6Info[0].Pool.String()}} 747 } 748 // Account current network gateways 749 for i, cfg := range n.ipamV4Config { 750 if cfg.Gateway == "" && n.ipamV4Info[i].Gateway != nil { 751 cfg.Gateway = n.ipamV4Info[i].Gateway.IP.String() 752 } 753 } 754 if n.enableIPv6 { 755 for i, cfg := range n.ipamV6Config { 756 if cfg.Gateway == "" && n.ipamV6Info[i].Gateway != nil { 757 cfg.Gateway = n.ipamV6Info[i].Gateway.IP.String() 758 } 759 } 760 } 761 // Reserve pools 762 if err := n.ipamAllocate(); err != nil { 763 log.G(context.TODO()).Warnf("Failed to allocate ipam pool(s) for network %q (%s): %v", n.Name(), n.ID(), err) 764 } 765 // Reserve existing endpoints' addresses 766 ipam, _, err := n.getController().getIPAMDriver(n.ipamType) 767 if err != nil { 768 log.G(context.TODO()).Warnf("Failed to retrieve ipam driver for network %q (%s) during address reservation", n.Name(), n.ID()) 769 continue 770 } 771 epl, err := n.getEndpointsFromStore() 772 if err != nil { 773 log.G(context.TODO()).Warnf("Failed to retrieve list of current endpoints on network %q (%s)", n.Name(), n.ID()) 774 continue 775 } 776 for _, ep := range epl { 777 if ep.Iface() == nil { 778 log.G(context.TODO()).Warnf("endpoint interface is empty for %q (%s)", ep.Name(), ep.ID()) 779 continue 780 } 781 if err := ep.assignAddress(ipam, true, ep.Iface().AddressIPv6() != nil); err != nil { 782 log.G(context.TODO()).Warnf("Failed to reserve current address for endpoint %q (%s) on network %q (%s)", 783 ep.Name(), ep.ID(), n.Name(), n.ID()) 784 } 785 } 786 } 787 } 788 789 func doReplayPoolReserve(n *Network) bool { 790 _, caps, err := n.getController().getIPAMDriver(n.ipamType) 791 if err != nil { 792 log.G(context.TODO()).Warnf("Failed to retrieve ipam driver for network %q (%s): %v", n.Name(), n.ID(), err) 793 return false 794 } 795 return caps.RequiresRequestReplay 796 } 797 798 func (c *Controller) addNetwork(n *Network) error { 799 d, err := n.driver(true) 800 if err != nil { 801 return err 802 } 803 804 // Create the network 805 if err := d.CreateNetwork(n.id, n.generic, n, n.getIPData(4), n.getIPData(6)); err != nil { 806 return err 807 } 808 809 n.startResolver() 810 811 return nil 812 } 813 814 // Networks returns the list of Network(s) managed by this controller. 815 func (c *Controller) Networks(ctx context.Context) []*Network { 816 var list []*Network 817 818 for _, n := range c.getNetworksFromStore(ctx) { 819 if n.inDelete { 820 continue 821 } 822 list = append(list, n) 823 } 824 825 return list 826 } 827 828 // WalkNetworks uses the provided function to walk the Network(s) managed by this controller. 829 func (c *Controller) WalkNetworks(walker NetworkWalker) { 830 for _, n := range c.Networks(context.TODO()) { 831 if walker(n) { 832 return 833 } 834 } 835 } 836 837 // NetworkByName returns the Network which has the passed name. 838 // If not found, the error [ErrNoSuchNetwork] is returned. 839 func (c *Controller) NetworkByName(name string) (*Network, error) { 840 if name == "" { 841 return nil, ErrInvalidName(name) 842 } 843 var n *Network 844 845 c.WalkNetworks(func(current *Network) bool { 846 if current.Name() == name { 847 n = current 848 return true 849 } 850 return false 851 }) 852 853 if n == nil { 854 return nil, ErrNoSuchNetwork(name) 855 } 856 857 return n, nil 858 } 859 860 // NetworkByID returns the Network which has the passed id. 861 // If not found, the error [ErrNoSuchNetwork] is returned. 862 func (c *Controller) NetworkByID(id string) (*Network, error) { 863 if id == "" { 864 return nil, ErrInvalidID(id) 865 } 866 return c.getNetworkFromStore(id) 867 } 868 869 // NewSandbox creates a new sandbox for containerID. 870 func (c *Controller) NewSandbox(containerID string, options ...SandboxOption) (_ *Sandbox, retErr error) { 871 if containerID == "" { 872 return nil, types.InvalidParameterErrorf("invalid container ID") 873 } 874 875 var sb *Sandbox 876 c.mu.Lock() 877 for _, s := range c.sandboxes { 878 if s.containerID == containerID { 879 // If not a stub, then we already have a complete sandbox. 880 if !s.isStub { 881 sbID := s.ID() 882 c.mu.Unlock() 883 return nil, types.ForbiddenErrorf("container %s is already present in sandbox %s", containerID, sbID) 884 } 885 886 // We already have a stub sandbox from the 887 // store. Make use of it so that we don't lose 888 // the endpoints from store but reset the 889 // isStub flag. 890 sb = s 891 sb.isStub = false 892 break 893 } 894 } 895 c.mu.Unlock() 896 897 // Create sandbox and process options first. Key generation depends on an option 898 if sb == nil { 899 // TODO(thaJeztah): given that a "containerID" must be unique in the list of sandboxes, is there any reason we're not using containerID as sandbox ID on non-Windows? 900 sandboxID := containerID 901 if runtime.GOOS != "windows" { 902 sandboxID = stringid.GenerateRandomID() 903 } 904 sb = &Sandbox{ 905 id: sandboxID, 906 containerID: containerID, 907 endpoints: []*Endpoint{}, 908 epPriority: map[string]int{}, 909 populatedEndpoints: map[string]struct{}{}, 910 config: containerConfig{}, 911 controller: c, 912 extDNS: []extDNSEntry{}, 913 } 914 } 915 916 sb.processOptions(options...) 917 918 c.mu.Lock() 919 if sb.ingress && c.ingressSandbox != nil { 920 c.mu.Unlock() 921 return nil, types.ForbiddenErrorf("ingress sandbox already present") 922 } 923 924 if sb.ingress { 925 c.ingressSandbox = sb 926 sb.config.hostsPath = filepath.Join(c.cfg.DataDir, "/network/files/hosts") 927 sb.config.resolvConfPath = filepath.Join(c.cfg.DataDir, "/network/files/resolv.conf") 928 sb.id = "ingress_sbox" 929 } else if sb.loadBalancerNID != "" { 930 sb.id = "lb_" + sb.loadBalancerNID 931 } 932 c.mu.Unlock() 933 934 defer func() { 935 if retErr != nil { 936 c.mu.Lock() 937 if sb.ingress { 938 c.ingressSandbox = nil 939 } 940 c.mu.Unlock() 941 } 942 }() 943 944 if err := sb.setupResolutionFiles(); err != nil { 945 return nil, err 946 } 947 if err := c.setupOSLSandbox(sb); err != nil { 948 return nil, err 949 } 950 951 c.mu.Lock() 952 c.sandboxes[sb.id] = sb 953 c.mu.Unlock() 954 defer func() { 955 if retErr != nil { 956 c.mu.Lock() 957 delete(c.sandboxes, sb.id) 958 c.mu.Unlock() 959 } 960 }() 961 962 if err := sb.storeUpdate(); err != nil { 963 return nil, fmt.Errorf("failed to update the store state of sandbox: %v", err) 964 } 965 966 return sb, nil 967 } 968 969 // GetSandbox returns the Sandbox which has the passed id. 970 // 971 // It returns an [ErrInvalidID] when passing an invalid ID, or an 972 // [types.NotFoundError] if no Sandbox was found for the container. 973 func (c *Controller) GetSandbox(containerID string) (*Sandbox, error) { 974 if containerID == "" { 975 return nil, ErrInvalidID("id is empty") 976 } 977 c.mu.Lock() 978 defer c.mu.Unlock() 979 if runtime.GOOS == "windows" { 980 // fast-path for Windows, which uses the container ID as sandbox ID. 981 if sb := c.sandboxes[containerID]; sb != nil && !sb.isStub { 982 return sb, nil 983 } 984 } else { 985 for _, sb := range c.sandboxes { 986 if sb.containerID == containerID && !sb.isStub { 987 return sb, nil 988 } 989 } 990 } 991 992 return nil, types.NotFoundErrorf("network sandbox for container %s not found", containerID) 993 } 994 995 // SandboxByID returns the Sandbox which has the passed id. 996 // If not found, a [types.NotFoundError] is returned. 997 func (c *Controller) SandboxByID(id string) (*Sandbox, error) { 998 if id == "" { 999 return nil, ErrInvalidID(id) 1000 } 1001 c.mu.Lock() 1002 s, ok := c.sandboxes[id] 1003 c.mu.Unlock() 1004 if !ok { 1005 return nil, types.NotFoundErrorf("sandbox %s not found", id) 1006 } 1007 return s, nil 1008 } 1009 1010 // SandboxDestroy destroys a sandbox given a container ID. 1011 func (c *Controller) SandboxDestroy(id string) error { 1012 var sb *Sandbox 1013 c.mu.Lock() 1014 for _, s := range c.sandboxes { 1015 if s.containerID == id { 1016 sb = s 1017 break 1018 } 1019 } 1020 c.mu.Unlock() 1021 1022 // It is not an error if sandbox is not available 1023 if sb == nil { 1024 return nil 1025 } 1026 1027 return sb.Delete() 1028 } 1029 1030 func (c *Controller) loadDriver(networkType string) error { 1031 var err error 1032 1033 if pg := c.GetPluginGetter(); pg != nil { 1034 _, err = pg.Get(networkType, driverapi.NetworkPluginEndpointType, plugingetter.Lookup) 1035 } else { 1036 _, err = plugins.Get(networkType, driverapi.NetworkPluginEndpointType) 1037 } 1038 1039 if err != nil { 1040 if errors.Cause(err) == plugins.ErrNotFound { 1041 return types.NotFoundErrorf(err.Error()) 1042 } 1043 return err 1044 } 1045 1046 return nil 1047 } 1048 1049 func (c *Controller) loadIPAMDriver(name string) error { 1050 var err error 1051 1052 if pg := c.GetPluginGetter(); pg != nil { 1053 _, err = pg.Get(name, ipamapi.PluginEndpointType, plugingetter.Lookup) 1054 } else { 1055 _, err = plugins.Get(name, ipamapi.PluginEndpointType) 1056 } 1057 1058 if err != nil { 1059 if errors.Cause(err) == plugins.ErrNotFound { 1060 return types.NotFoundErrorf(err.Error()) 1061 } 1062 return err 1063 } 1064 1065 return nil 1066 } 1067 1068 func (c *Controller) getIPAMDriver(name string) (ipamapi.Ipam, *ipamapi.Capability, error) { 1069 id, caps := c.ipamRegistry.IPAM(name) 1070 if id == nil { 1071 // Might be a plugin name. Try loading it 1072 if err := c.loadIPAMDriver(name); err != nil { 1073 return nil, nil, err 1074 } 1075 1076 // Now that we resolved the plugin, try again looking up the registry 1077 id, caps = c.ipamRegistry.IPAM(name) 1078 if id == nil { 1079 return nil, nil, types.InvalidParameterErrorf("invalid ipam driver: %q", name) 1080 } 1081 } 1082 1083 return id, caps, nil 1084 } 1085 1086 // Stop stops the network controller. 1087 func (c *Controller) Stop() { 1088 c.closeStores() 1089 c.stopExternalKeyListener() 1090 osl.GC() 1091 } 1092 1093 // StartDiagnostic starts the network diagnostic server listening on port. 1094 func (c *Controller) StartDiagnostic(port int) { 1095 c.mu.Lock() 1096 if !c.DiagnosticServer.IsDiagnosticEnabled() { 1097 c.DiagnosticServer.EnableDiagnostic("127.0.0.1", port) 1098 } 1099 c.mu.Unlock() 1100 } 1101 1102 // StopDiagnostic stops the network diagnostic server. 1103 func (c *Controller) StopDiagnostic() { 1104 c.mu.Lock() 1105 if c.DiagnosticServer.IsDiagnosticEnabled() { 1106 c.DiagnosticServer.DisableDiagnostic() 1107 } 1108 c.mu.Unlock() 1109 } 1110 1111 // IsDiagnosticEnabled returns true if the diagnostic server is running. 1112 func (c *Controller) IsDiagnosticEnabled() bool { 1113 c.mu.Lock() 1114 defer c.mu.Unlock() 1115 return c.DiagnosticServer.IsDiagnosticEnabled() 1116 }