github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/libnetwork/network.go (about) 1 // FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: 2 //go:build go1.19 3 4 package libnetwork 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 "net" 11 "runtime" 12 "strings" 13 "sync" 14 "time" 15 16 "github.com/containerd/log" 17 "github.com/docker/docker/libnetwork/datastore" 18 "github.com/docker/docker/libnetwork/driverapi" 19 "github.com/docker/docker/libnetwork/etchosts" 20 "github.com/docker/docker/libnetwork/internal/setmatrix" 21 "github.com/docker/docker/libnetwork/ipamapi" 22 "github.com/docker/docker/libnetwork/netlabel" 23 "github.com/docker/docker/libnetwork/netutils" 24 "github.com/docker/docker/libnetwork/networkdb" 25 "github.com/docker/docker/libnetwork/options" 26 "github.com/docker/docker/libnetwork/scope" 27 "github.com/docker/docker/libnetwork/types" 28 "github.com/docker/docker/pkg/stringid" 29 "go.opentelemetry.io/otel" 30 "go.opentelemetry.io/otel/attribute" 31 "go.opentelemetry.io/otel/trace" 32 ) 33 34 // EndpointWalker is a client provided function which will be used to walk the Endpoints. 35 // When the function returns true, the walk will stop. 36 type EndpointWalker func(ep *Endpoint) bool 37 38 // ipInfo is the reverse mapping from IP to service name to serve the PTR query. 39 // extResolver is set if an external server resolves a service name to this IP. 40 // It's an indication to defer PTR queries also to that external server. 41 type ipInfo struct { 42 name string 43 serviceID string 44 extResolver bool 45 } 46 47 // svcMapEntry is the body of the element into the svcMap 48 // The ip is a string because the SetMatrix does not accept non hashable values 49 type svcMapEntry struct { 50 ip string 51 serviceID string 52 } 53 54 type svcInfo struct { 55 svcMap setmatrix.SetMatrix[svcMapEntry] 56 svcIPv6Map setmatrix.SetMatrix[svcMapEntry] 57 ipMap setmatrix.SetMatrix[ipInfo] 58 service map[string][]servicePorts 59 } 60 61 // backing container or host's info 62 type serviceTarget struct { 63 name string 64 ip net.IP 65 port uint16 66 } 67 68 type servicePorts struct { 69 portName string 70 proto string 71 target []serviceTarget 72 } 73 74 type networkDBTable struct { 75 name string 76 objType driverapi.ObjectType 77 } 78 79 // IpamConf contains all the ipam related configurations for a network 80 // 81 // TODO(aker): use proper net/* structs instead of string literals. 82 type IpamConf struct { 83 // PreferredPool is the master address pool for containers and network interfaces. 84 PreferredPool string 85 // SubPool is a subset of the master pool. If specified, 86 // this becomes the container pool for automatic address allocations. 87 SubPool string 88 // Gateway is the preferred Network Gateway address (optional). 89 Gateway string 90 // AuxAddresses contains auxiliary addresses for network driver. Must be within the master pool. 91 // libnetwork will reserve them if they fall into the container pool. 92 AuxAddresses map[string]string 93 } 94 95 // Validate checks whether the configuration is valid 96 func (c *IpamConf) Validate() error { 97 if c.Gateway != "" && nil == net.ParseIP(c.Gateway) { 98 return types.InvalidParameterErrorf("invalid gateway address %s in Ipam configuration", c.Gateway) 99 } 100 return nil 101 } 102 103 // Contains checks whether the ipam master address pool contains [addr]. 104 func (c *IpamConf) Contains(addr net.IP) bool { 105 if c == nil { 106 return false 107 } 108 if c.PreferredPool == "" { 109 return false 110 } 111 112 _, allowedRange, _ := net.ParseCIDR(c.PreferredPool) 113 114 return allowedRange.Contains(addr) 115 } 116 117 // IsStatic checks whether the subnet was statically allocated (ie. user-defined). 118 func (c *IpamConf) IsStatic() bool { 119 return c != nil && c.PreferredPool != "" 120 } 121 122 // IpamInfo contains all the ipam related operational info for a network 123 type IpamInfo struct { 124 PoolID string 125 Meta map[string]string 126 driverapi.IPAMData 127 } 128 129 // MarshalJSON encodes IpamInfo into json message 130 func (i *IpamInfo) MarshalJSON() ([]byte, error) { 131 m := map[string]interface{}{ 132 "PoolID": i.PoolID, 133 } 134 v, err := json.Marshal(&i.IPAMData) 135 if err != nil { 136 return nil, err 137 } 138 m["IPAMData"] = string(v) 139 140 if i.Meta != nil { 141 m["Meta"] = i.Meta 142 } 143 return json.Marshal(m) 144 } 145 146 // UnmarshalJSON decodes json message into PoolData 147 func (i *IpamInfo) UnmarshalJSON(data []byte) error { 148 var ( 149 m map[string]interface{} 150 err error 151 ) 152 if err = json.Unmarshal(data, &m); err != nil { 153 return err 154 } 155 i.PoolID = m["PoolID"].(string) 156 if v, ok := m["Meta"]; ok { 157 b, _ := json.Marshal(v) 158 if err = json.Unmarshal(b, &i.Meta); err != nil { 159 return err 160 } 161 } 162 if v, ok := m["IPAMData"]; ok { 163 if err = json.Unmarshal([]byte(v.(string)), &i.IPAMData); err != nil { 164 return err 165 } 166 } 167 return nil 168 } 169 170 // Network represents a logical connectivity zone that containers may 171 // join using the Link method. A network is managed by a specific driver. 172 type Network struct { 173 ctrlr *Controller 174 name string 175 networkType string // networkType is the name of the netdriver used by this network 176 id string 177 created time.Time 178 scope string // network data scope 179 labels map[string]string 180 ipamType string // ipamType is the name of the IPAM driver 181 ipamOptions map[string]string 182 addrSpace string 183 ipamV4Config []*IpamConf 184 ipamV6Config []*IpamConf 185 ipamV4Info []*IpamInfo 186 ipamV6Info []*IpamInfo 187 enableIPv6 bool 188 postIPv6 bool 189 epCnt *endpointCnt 190 generic options.Generic 191 dbIndex uint64 192 dbExists bool 193 persist bool 194 drvOnce *sync.Once 195 resolverOnce sync.Once //nolint:nolintlint,unused // only used on windows 196 resolver []*Resolver 197 internal bool 198 attachable bool 199 inDelete bool 200 ingress bool 201 driverTables []networkDBTable 202 dynamic bool 203 configOnly bool 204 configFrom string 205 loadBalancerIP net.IP 206 loadBalancerMode string 207 mu sync.Mutex 208 } 209 210 const ( 211 loadBalancerModeNAT = "NAT" 212 loadBalancerModeDSR = "DSR" 213 loadBalancerModeDefault = loadBalancerModeNAT 214 ) 215 216 // Name returns a user chosen name for this network. 217 func (n *Network) Name() string { 218 n.mu.Lock() 219 defer n.mu.Unlock() 220 221 return n.name 222 } 223 224 // ID returns a system generated id for this network. 225 func (n *Network) ID() string { 226 n.mu.Lock() 227 defer n.mu.Unlock() 228 229 return n.id 230 } 231 232 func (n *Network) Created() time.Time { 233 n.mu.Lock() 234 defer n.mu.Unlock() 235 236 return n.created 237 } 238 239 // Type returns the type of network, which corresponds to its managing driver. 240 func (n *Network) Type() string { 241 n.mu.Lock() 242 defer n.mu.Unlock() 243 244 return n.networkType 245 } 246 247 func (n *Network) Key() []string { 248 n.mu.Lock() 249 defer n.mu.Unlock() 250 return []string{datastore.NetworkKeyPrefix, n.id} 251 } 252 253 func (n *Network) KeyPrefix() []string { 254 return []string{datastore.NetworkKeyPrefix} 255 } 256 257 func (n *Network) Value() []byte { 258 n.mu.Lock() 259 defer n.mu.Unlock() 260 b, err := json.Marshal(n) 261 if err != nil { 262 return nil 263 } 264 return b 265 } 266 267 func (n *Network) SetValue(value []byte) error { 268 return json.Unmarshal(value, n) 269 } 270 271 func (n *Network) Index() uint64 { 272 n.mu.Lock() 273 defer n.mu.Unlock() 274 return n.dbIndex 275 } 276 277 func (n *Network) SetIndex(index uint64) { 278 n.mu.Lock() 279 n.dbIndex = index 280 n.dbExists = true 281 n.mu.Unlock() 282 } 283 284 func (n *Network) Exists() bool { 285 n.mu.Lock() 286 defer n.mu.Unlock() 287 return n.dbExists 288 } 289 290 func (n *Network) Skip() bool { 291 n.mu.Lock() 292 defer n.mu.Unlock() 293 return !n.persist 294 } 295 296 func (n *Network) New() datastore.KVObject { 297 n.mu.Lock() 298 defer n.mu.Unlock() 299 300 return &Network{ 301 ctrlr: n.ctrlr, 302 drvOnce: &sync.Once{}, 303 scope: n.scope, 304 } 305 } 306 307 // CopyTo deep copies to the destination IpamConfig 308 func (c *IpamConf) CopyTo(dstC *IpamConf) error { 309 dstC.PreferredPool = c.PreferredPool 310 dstC.SubPool = c.SubPool 311 dstC.Gateway = c.Gateway 312 if c.AuxAddresses != nil { 313 dstC.AuxAddresses = make(map[string]string, len(c.AuxAddresses)) 314 for k, v := range c.AuxAddresses { 315 dstC.AuxAddresses[k] = v 316 } 317 } 318 return nil 319 } 320 321 // CopyTo deep copies to the destination IpamInfo 322 func (i *IpamInfo) CopyTo(dstI *IpamInfo) error { 323 dstI.PoolID = i.PoolID 324 if i.Meta != nil { 325 dstI.Meta = make(map[string]string) 326 for k, v := range i.Meta { 327 dstI.Meta[k] = v 328 } 329 } 330 331 dstI.AddressSpace = i.AddressSpace 332 dstI.Pool = types.GetIPNetCopy(i.Pool) 333 dstI.Gateway = types.GetIPNetCopy(i.Gateway) 334 335 if i.AuxAddresses != nil { 336 dstI.AuxAddresses = make(map[string]*net.IPNet) 337 for k, v := range i.AuxAddresses { 338 dstI.AuxAddresses[k] = types.GetIPNetCopy(v) 339 } 340 } 341 342 return nil 343 } 344 345 func (n *Network) validateConfiguration() error { 346 if n.configOnly { 347 // Only supports network specific configurations. 348 // Network operator configurations are not supported. 349 if n.ingress || n.internal || n.attachable || n.scope != "" { 350 return types.ForbiddenErrorf("configuration network can only contain network " + 351 "specific fields. Network operator fields like " + 352 "[ ingress | internal | attachable | scope ] are not supported.") 353 } 354 } 355 if n.configFrom != "" { 356 if n.configOnly { 357 return types.ForbiddenErrorf("a configuration network cannot depend on another configuration network") 358 } 359 if n.ipamType != "" && 360 n.ipamType != defaultIpamForNetworkType(n.networkType) || 361 n.enableIPv6 || 362 len(n.labels) > 0 || len(n.ipamOptions) > 0 || 363 len(n.ipamV4Config) > 0 || len(n.ipamV6Config) > 0 { 364 return types.ForbiddenErrorf("user specified configurations are not supported if the network depends on a configuration network") 365 } 366 if len(n.generic) > 0 { 367 if data, ok := n.generic[netlabel.GenericData]; ok { 368 var ( 369 driverOptions map[string]string 370 opts interface{} 371 ) 372 switch t := data.(type) { 373 case map[string]interface{}, map[string]string: 374 opts = t 375 } 376 ba, err := json.Marshal(opts) 377 if err != nil { 378 return fmt.Errorf("failed to validate network configuration: %v", err) 379 } 380 if err := json.Unmarshal(ba, &driverOptions); err != nil { 381 return fmt.Errorf("failed to validate network configuration: %v", err) 382 } 383 if len(driverOptions) > 0 { 384 return types.ForbiddenErrorf("network driver options are not supported if the network depends on a configuration network") 385 } 386 } 387 } 388 } 389 return nil 390 } 391 392 // applyConfigurationTo applies network specific configurations. 393 func (n *Network) applyConfigurationTo(to *Network) error { 394 to.enableIPv6 = n.enableIPv6 395 if len(n.labels) > 0 { 396 to.labels = make(map[string]string, len(n.labels)) 397 for k, v := range n.labels { 398 if _, ok := to.labels[k]; !ok { 399 to.labels[k] = v 400 } 401 } 402 } 403 if len(n.ipamType) != 0 { 404 to.ipamType = n.ipamType 405 } 406 if len(n.ipamOptions) > 0 { 407 to.ipamOptions = make(map[string]string, len(n.ipamOptions)) 408 for k, v := range n.ipamOptions { 409 if _, ok := to.ipamOptions[k]; !ok { 410 to.ipamOptions[k] = v 411 } 412 } 413 } 414 if len(n.ipamV4Config) > 0 { 415 to.ipamV4Config = make([]*IpamConf, 0, len(n.ipamV4Config)) 416 to.ipamV4Config = append(to.ipamV4Config, n.ipamV4Config...) 417 } 418 if len(n.ipamV6Config) > 0 { 419 to.ipamV6Config = make([]*IpamConf, 0, len(n.ipamV6Config)) 420 to.ipamV6Config = append(to.ipamV6Config, n.ipamV6Config...) 421 } 422 if len(n.generic) > 0 { 423 to.generic = options.Generic{} 424 for k, v := range n.generic { 425 to.generic[k] = v 426 } 427 } 428 return nil 429 } 430 431 func (n *Network) CopyTo(o datastore.KVObject) error { 432 n.mu.Lock() 433 defer n.mu.Unlock() 434 435 dstN := o.(*Network) 436 dstN.name = n.name 437 dstN.id = n.id 438 dstN.created = n.created 439 dstN.networkType = n.networkType 440 dstN.scope = n.scope 441 dstN.dynamic = n.dynamic 442 dstN.ipamType = n.ipamType 443 dstN.enableIPv6 = n.enableIPv6 444 dstN.persist = n.persist 445 dstN.postIPv6 = n.postIPv6 446 dstN.dbIndex = n.dbIndex 447 dstN.dbExists = n.dbExists 448 dstN.drvOnce = n.drvOnce 449 dstN.internal = n.internal 450 dstN.attachable = n.attachable 451 dstN.inDelete = n.inDelete 452 dstN.ingress = n.ingress 453 dstN.configOnly = n.configOnly 454 dstN.configFrom = n.configFrom 455 dstN.loadBalancerIP = n.loadBalancerIP 456 dstN.loadBalancerMode = n.loadBalancerMode 457 458 // copy labels 459 if dstN.labels == nil { 460 dstN.labels = make(map[string]string, len(n.labels)) 461 } 462 for k, v := range n.labels { 463 dstN.labels[k] = v 464 } 465 466 if n.ipamOptions != nil { 467 dstN.ipamOptions = make(map[string]string, len(n.ipamOptions)) 468 for k, v := range n.ipamOptions { 469 dstN.ipamOptions[k] = v 470 } 471 } 472 473 for _, v4conf := range n.ipamV4Config { 474 dstV4Conf := &IpamConf{} 475 if err := v4conf.CopyTo(dstV4Conf); err != nil { 476 return err 477 } 478 dstN.ipamV4Config = append(dstN.ipamV4Config, dstV4Conf) 479 } 480 481 for _, v4info := range n.ipamV4Info { 482 dstV4Info := &IpamInfo{} 483 if err := v4info.CopyTo(dstV4Info); err != nil { 484 return err 485 } 486 dstN.ipamV4Info = append(dstN.ipamV4Info, dstV4Info) 487 } 488 489 for _, v6conf := range n.ipamV6Config { 490 dstV6Conf := &IpamConf{} 491 if err := v6conf.CopyTo(dstV6Conf); err != nil { 492 return err 493 } 494 dstN.ipamV6Config = append(dstN.ipamV6Config, dstV6Conf) 495 } 496 497 for _, v6info := range n.ipamV6Info { 498 dstV6Info := &IpamInfo{} 499 if err := v6info.CopyTo(dstV6Info); err != nil { 500 return err 501 } 502 dstN.ipamV6Info = append(dstN.ipamV6Info, dstV6Info) 503 } 504 505 dstN.generic = options.Generic{} 506 for k, v := range n.generic { 507 dstN.generic[k] = v 508 } 509 510 return nil 511 } 512 513 func (n *Network) getEpCnt() *endpointCnt { 514 n.mu.Lock() 515 defer n.mu.Unlock() 516 517 return n.epCnt 518 } 519 520 // TODO : Can be made much more generic with the help of reflection (but has some golang limitations) 521 func (n *Network) MarshalJSON() ([]byte, error) { 522 netMap := make(map[string]interface{}) 523 netMap["name"] = n.name 524 netMap["id"] = n.id 525 netMap["created"] = n.created 526 netMap["networkType"] = n.networkType 527 netMap["scope"] = n.scope 528 netMap["labels"] = n.labels 529 netMap["ipamType"] = n.ipamType 530 netMap["ipamOptions"] = n.ipamOptions 531 netMap["addrSpace"] = n.addrSpace 532 netMap["enableIPv6"] = n.enableIPv6 533 if n.generic != nil { 534 netMap["generic"] = n.generic 535 } 536 netMap["persist"] = n.persist 537 netMap["postIPv6"] = n.postIPv6 538 if len(n.ipamV4Config) > 0 { 539 ics, err := json.Marshal(n.ipamV4Config) 540 if err != nil { 541 return nil, err 542 } 543 netMap["ipamV4Config"] = string(ics) 544 } 545 if len(n.ipamV4Info) > 0 { 546 iis, err := json.Marshal(n.ipamV4Info) 547 if err != nil { 548 return nil, err 549 } 550 netMap["ipamV4Info"] = string(iis) 551 } 552 if len(n.ipamV6Config) > 0 { 553 ics, err := json.Marshal(n.ipamV6Config) 554 if err != nil { 555 return nil, err 556 } 557 netMap["ipamV6Config"] = string(ics) 558 } 559 if len(n.ipamV6Info) > 0 { 560 iis, err := json.Marshal(n.ipamV6Info) 561 if err != nil { 562 return nil, err 563 } 564 netMap["ipamV6Info"] = string(iis) 565 } 566 netMap["internal"] = n.internal 567 netMap["attachable"] = n.attachable 568 netMap["inDelete"] = n.inDelete 569 netMap["ingress"] = n.ingress 570 netMap["configOnly"] = n.configOnly 571 netMap["configFrom"] = n.configFrom 572 netMap["loadBalancerIP"] = n.loadBalancerIP 573 netMap["loadBalancerMode"] = n.loadBalancerMode 574 return json.Marshal(netMap) 575 } 576 577 // TODO : Can be made much more generic with the help of reflection (but has some golang limitations) 578 func (n *Network) UnmarshalJSON(b []byte) (err error) { 579 var netMap map[string]interface{} 580 if err := json.Unmarshal(b, &netMap); err != nil { 581 return err 582 } 583 n.name = netMap["name"].(string) 584 n.id = netMap["id"].(string) 585 // "created" is not available in older versions 586 if v, ok := netMap["created"]; ok { 587 // n.created is time.Time but marshalled as string 588 if err = n.created.UnmarshalText([]byte(v.(string))); err != nil { 589 log.G(context.TODO()).Warnf("failed to unmarshal creation time %v: %v", v, err) 590 n.created = time.Time{} 591 } 592 } 593 n.networkType = netMap["networkType"].(string) 594 n.enableIPv6 = netMap["enableIPv6"].(bool) 595 596 // if we weren't unmarshaling to netMap we could simply set n.labels 597 // unfortunately, we can't because map[string]interface{} != map[string]string 598 if labels, ok := netMap["labels"].(map[string]interface{}); ok { 599 n.labels = make(map[string]string, len(labels)) 600 for label, value := range labels { 601 n.labels[label] = value.(string) 602 } 603 } 604 605 if v, ok := netMap["ipamOptions"]; ok { 606 if iOpts, ok := v.(map[string]interface{}); ok { 607 n.ipamOptions = make(map[string]string, len(iOpts)) 608 for k, v := range iOpts { 609 n.ipamOptions[k] = v.(string) 610 } 611 } 612 } 613 614 if v, ok := netMap["generic"]; ok { 615 n.generic = v.(map[string]interface{}) 616 // Restore opts in their map[string]string form 617 if v, ok := n.generic[netlabel.GenericData]; ok { 618 var lmap map[string]string 619 ba, err := json.Marshal(v) 620 if err != nil { 621 return err 622 } 623 if err := json.Unmarshal(ba, &lmap); err != nil { 624 return err 625 } 626 n.generic[netlabel.GenericData] = lmap 627 } 628 } 629 if v, ok := netMap["persist"]; ok { 630 n.persist = v.(bool) 631 } 632 if v, ok := netMap["postIPv6"]; ok { 633 n.postIPv6 = v.(bool) 634 } 635 if v, ok := netMap["ipamType"]; ok { 636 n.ipamType = v.(string) 637 } else { 638 n.ipamType = ipamapi.DefaultIPAM 639 } 640 if v, ok := netMap["addrSpace"]; ok { 641 n.addrSpace = v.(string) 642 } 643 if v, ok := netMap["ipamV4Config"]; ok { 644 if err := json.Unmarshal([]byte(v.(string)), &n.ipamV4Config); err != nil { 645 return err 646 } 647 } 648 if v, ok := netMap["ipamV4Info"]; ok { 649 if err := json.Unmarshal([]byte(v.(string)), &n.ipamV4Info); err != nil { 650 return err 651 } 652 } 653 if v, ok := netMap["ipamV6Config"]; ok { 654 if err := json.Unmarshal([]byte(v.(string)), &n.ipamV6Config); err != nil { 655 return err 656 } 657 } 658 if v, ok := netMap["ipamV6Info"]; ok { 659 if err := json.Unmarshal([]byte(v.(string)), &n.ipamV6Info); err != nil { 660 return err 661 } 662 } 663 if v, ok := netMap["internal"]; ok { 664 n.internal = v.(bool) 665 } 666 if v, ok := netMap["attachable"]; ok { 667 n.attachable = v.(bool) 668 } 669 if s, ok := netMap["scope"]; ok { 670 n.scope = s.(string) 671 } 672 if v, ok := netMap["inDelete"]; ok { 673 n.inDelete = v.(bool) 674 } 675 if v, ok := netMap["ingress"]; ok { 676 n.ingress = v.(bool) 677 } 678 if v, ok := netMap["configOnly"]; ok { 679 n.configOnly = v.(bool) 680 } 681 if v, ok := netMap["configFrom"]; ok { 682 n.configFrom = v.(string) 683 } 684 if v, ok := netMap["loadBalancerIP"]; ok { 685 n.loadBalancerIP = net.ParseIP(v.(string)) 686 } 687 n.loadBalancerMode = loadBalancerModeDefault 688 if v, ok := netMap["loadBalancerMode"]; ok { 689 n.loadBalancerMode = v.(string) 690 } 691 // Reconcile old networks with the recently added `--ipv6` flag 692 if !n.enableIPv6 { 693 n.enableIPv6 = len(n.ipamV6Info) > 0 694 } 695 return nil 696 } 697 698 // NetworkOption is an option setter function type used to pass various options to 699 // NewNetwork method. The various setter functions of type NetworkOption are 700 // provided by libnetwork, they look like NetworkOptionXXXX(...) 701 type NetworkOption func(n *Network) 702 703 // NetworkOptionGeneric function returns an option setter for a Generic option defined 704 // in a Dictionary of Key-Value pair 705 func NetworkOptionGeneric(generic map[string]interface{}) NetworkOption { 706 return func(n *Network) { 707 if n.generic == nil { 708 n.generic = make(map[string]interface{}) 709 } 710 if val, ok := generic[netlabel.EnableIPv6]; ok { 711 n.enableIPv6 = val.(bool) 712 } 713 if val, ok := generic[netlabel.Internal]; ok { 714 n.internal = val.(bool) 715 } 716 for k, v := range generic { 717 n.generic[k] = v 718 } 719 } 720 } 721 722 // NetworkOptionIngress returns an option setter to indicate if a network is 723 // an ingress network. 724 func NetworkOptionIngress(ingress bool) NetworkOption { 725 return func(n *Network) { 726 n.ingress = ingress 727 } 728 } 729 730 // NetworkOptionPersist returns an option setter to set persistence policy for a network 731 func NetworkOptionPersist(persist bool) NetworkOption { 732 return func(n *Network) { 733 n.persist = persist 734 } 735 } 736 737 // NetworkOptionEnableIPv6 returns an option setter to explicitly configure IPv6 738 func NetworkOptionEnableIPv6(enableIPv6 bool) NetworkOption { 739 return func(n *Network) { 740 if n.generic == nil { 741 n.generic = make(map[string]interface{}) 742 } 743 n.enableIPv6 = enableIPv6 744 n.generic[netlabel.EnableIPv6] = enableIPv6 745 } 746 } 747 748 // NetworkOptionInternalNetwork returns an option setter to config the network 749 // to be internal which disables default gateway service 750 func NetworkOptionInternalNetwork() NetworkOption { 751 return func(n *Network) { 752 if n.generic == nil { 753 n.generic = make(map[string]interface{}) 754 } 755 n.internal = true 756 n.generic[netlabel.Internal] = true 757 } 758 } 759 760 // NetworkOptionAttachable returns an option setter to set attachable for a network 761 func NetworkOptionAttachable(attachable bool) NetworkOption { 762 return func(n *Network) { 763 n.attachable = attachable 764 } 765 } 766 767 // NetworkOptionScope returns an option setter to overwrite the network's scope. 768 // By default the network's scope is set to the network driver's datascope. 769 func NetworkOptionScope(scope string) NetworkOption { 770 return func(n *Network) { 771 n.scope = scope 772 } 773 } 774 775 // NetworkOptionIpam function returns an option setter for the ipam configuration for this network 776 func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf, opts map[string]string) NetworkOption { 777 return func(n *Network) { 778 if ipamDriver != "" { 779 n.ipamType = ipamDriver 780 if ipamDriver == ipamapi.DefaultIPAM { 781 n.ipamType = defaultIpamForNetworkType(n.Type()) 782 } 783 } 784 n.ipamOptions = opts 785 n.addrSpace = addrSpace 786 n.ipamV4Config = ipV4 787 n.ipamV6Config = ipV6 788 } 789 } 790 791 // NetworkOptionLBEndpoint function returns an option setter for the configuration of the load balancer endpoint for this network 792 func NetworkOptionLBEndpoint(ip net.IP) NetworkOption { 793 return func(n *Network) { 794 n.loadBalancerIP = ip 795 } 796 } 797 798 // NetworkOptionDriverOpts function returns an option setter for any driver parameter described by a map 799 func NetworkOptionDriverOpts(opts map[string]string) NetworkOption { 800 return func(n *Network) { 801 if n.generic == nil { 802 n.generic = make(map[string]interface{}) 803 } 804 if opts == nil { 805 opts = make(map[string]string) 806 } 807 // Store the options 808 n.generic[netlabel.GenericData] = opts 809 } 810 } 811 812 // NetworkOptionLabels function returns an option setter for labels specific to a network 813 func NetworkOptionLabels(labels map[string]string) NetworkOption { 814 return func(n *Network) { 815 n.labels = labels 816 } 817 } 818 819 // NetworkOptionDynamic function returns an option setter for dynamic option for a network 820 func NetworkOptionDynamic() NetworkOption { 821 return func(n *Network) { 822 n.dynamic = true 823 } 824 } 825 826 // NetworkOptionDeferIPv6Alloc instructs the network to defer the IPV6 address allocation until after the endpoint has been created 827 // It is being provided to support the specific docker daemon flags where user can deterministically assign an IPv6 address 828 // to a container as combination of fixed-cidr-v6 + mac-address 829 // TODO: Remove this option setter once we support endpoint ipam options 830 func NetworkOptionDeferIPv6Alloc(enable bool) NetworkOption { 831 return func(n *Network) { 832 n.postIPv6 = enable 833 } 834 } 835 836 // NetworkOptionConfigOnly tells controller this network is 837 // a configuration only network. It serves as a configuration 838 // for other networks. 839 func NetworkOptionConfigOnly() NetworkOption { 840 return func(n *Network) { 841 n.configOnly = true 842 } 843 } 844 845 // NetworkOptionConfigFrom tells controller to pick the 846 // network configuration from a configuration only network 847 func NetworkOptionConfigFrom(name string) NetworkOption { 848 return func(n *Network) { 849 n.configFrom = name 850 } 851 } 852 853 func (n *Network) processOptions(options ...NetworkOption) { 854 for _, opt := range options { 855 if opt != nil { 856 opt(n) 857 } 858 } 859 } 860 861 type networkDeleteParams struct { 862 rmLBEndpoint bool 863 } 864 865 // NetworkDeleteOption is a type for optional parameters to pass to the 866 // Network.Delete() function. 867 type NetworkDeleteOption func(p *networkDeleteParams) 868 869 // NetworkDeleteOptionRemoveLB informs a Network.Delete() operation that should 870 // remove the load balancer endpoint for this network. Note that the Delete() 871 // method will automatically remove a load balancing endpoint for most networks 872 // when the network is otherwise empty. However, this does not occur for some 873 // networks. In particular, networks marked as ingress (which are supposed to 874 // be more permanent than other overlay networks) won't automatically remove 875 // the LB endpoint on Delete(). This method allows for explicit removal of 876 // such networks provided there are no other endpoints present in the network. 877 // If the network still has non-LB endpoints present, Delete() will not 878 // remove the LB endpoint and will return an error. 879 func NetworkDeleteOptionRemoveLB(p *networkDeleteParams) { 880 p.rmLBEndpoint = true 881 } 882 883 func (n *Network) resolveDriver(name string, load bool) (driverapi.Driver, driverapi.Capability, error) { 884 c := n.getController() 885 886 // Check if a driver for the specified network type is available 887 d, capabilities := c.drvRegistry.Driver(name) 888 if d == nil { 889 if load { 890 err := c.loadDriver(name) 891 if err != nil { 892 return nil, driverapi.Capability{}, err 893 } 894 895 d, capabilities = c.drvRegistry.Driver(name) 896 if d == nil { 897 return nil, driverapi.Capability{}, fmt.Errorf("could not resolve driver %s in registry", name) 898 } 899 } else { 900 // don't fail if driver loading is not required 901 return nil, driverapi.Capability{}, nil 902 } 903 } 904 905 return d, capabilities, nil 906 } 907 908 func (n *Network) driverIsMultihost() bool { 909 _, capabilities, err := n.resolveDriver(n.networkType, true) 910 if err != nil { 911 return false 912 } 913 return capabilities.ConnectivityScope == scope.Global 914 } 915 916 func (n *Network) driver(load bool) (driverapi.Driver, error) { 917 d, capabilities, err := n.resolveDriver(n.networkType, load) 918 if err != nil { 919 return nil, err 920 } 921 922 n.mu.Lock() 923 // If load is not required, driver, cap and err may all be nil 924 if n.scope == "" { 925 n.scope = capabilities.DataScope 926 } 927 if n.dynamic { 928 // If the network is dynamic, then it is swarm 929 // scoped regardless of the backing driver. 930 n.scope = scope.Swarm 931 } 932 n.mu.Unlock() 933 return d, nil 934 } 935 936 // Delete the network. 937 func (n *Network) Delete(options ...NetworkDeleteOption) error { 938 var params networkDeleteParams 939 for _, opt := range options { 940 opt(¶ms) 941 } 942 return n.delete(false, params.rmLBEndpoint) 943 } 944 945 // This function gets called in 3 ways: 946 // - Delete() -- (false, false) 947 // remove if endpoint count == 0 or endpoint count == 1 and 948 // there is a load balancer IP 949 // - Delete(libnetwork.NetworkDeleteOptionRemoveLB) -- (false, true) 950 // remove load balancer and network if endpoint count == 1 951 // - controller.networkCleanup() -- (true, true) 952 // remove the network no matter what 953 func (n *Network) delete(force bool, rmLBEndpoint bool) error { 954 n.mu.Lock() 955 c := n.ctrlr 956 name := n.name 957 id := n.id 958 n.mu.Unlock() 959 960 c.networkLocker.Lock(id) 961 defer c.networkLocker.Unlock(id) //nolint:errcheck 962 963 n, err := c.getNetworkFromStore(id) 964 if err != nil { 965 return &UnknownNetworkError{name: name, id: id} 966 } 967 968 // Only remove ingress on force removal or explicit LB endpoint removal 969 if n.ingress && !force && !rmLBEndpoint { 970 return &ActiveEndpointsError{name: n.name, id: n.id} 971 } 972 973 // Check that the network is empty 974 var emptyCount uint64 975 if n.hasLoadBalancerEndpoint() { 976 emptyCount = 1 977 } 978 if !force && n.getEpCnt().EndpointCnt() > emptyCount { 979 if n.configOnly { 980 return types.ForbiddenErrorf("configuration network %q is in use", n.Name()) 981 } 982 return &ActiveEndpointsError{name: n.name, id: n.id} 983 } 984 985 if n.hasLoadBalancerEndpoint() { 986 // If we got to this point, then the following must hold: 987 // * force is true OR endpoint count == 1 988 if err := n.deleteLoadBalancerSandbox(); err != nil { 989 if !force { 990 return err 991 } 992 // continue deletion when force is true even on error 993 log.G(context.TODO()).Warnf("Error deleting load balancer sandbox: %v", err) 994 } 995 // Reload the network from the store to update the epcnt. 996 n, err = c.getNetworkFromStore(id) 997 if err != nil { 998 return &UnknownNetworkError{name: name, id: id} 999 } 1000 } 1001 1002 // Up to this point, errors that we returned were recoverable. 1003 // From here on, any errors leave us in an inconsistent state. 1004 // This is unfortunate, but there isn't a safe way to 1005 // reconstitute a load-balancer endpoint after removing it. 1006 1007 // Mark the network for deletion 1008 n.inDelete = true 1009 if err = c.updateToStore(n); err != nil { 1010 return fmt.Errorf("error marking network %s (%s) for deletion: %v", n.Name(), n.ID(), err) 1011 } 1012 1013 if n.ConfigFrom() != "" { 1014 if t, err := c.getConfigNetwork(n.ConfigFrom()); err == nil { 1015 if err := t.getEpCnt().DecEndpointCnt(); err != nil { 1016 log.G(context.TODO()).Warnf("Failed to update reference count for configuration network %q on removal of network %q: %v", 1017 t.Name(), n.Name(), err) 1018 } 1019 } else { 1020 log.G(context.TODO()).Warnf("Could not find configuration network %q during removal of network %q", n.configFrom, n.Name()) 1021 } 1022 } 1023 1024 if n.configOnly { 1025 goto removeFromStore 1026 } 1027 1028 n.ipamRelease() 1029 1030 // We are about to delete the network. Leave the gossip 1031 // cluster for the network to stop all incoming network 1032 // specific gossip updates before cleaning up all the service 1033 // bindings for the network. But cleanup service binding 1034 // before deleting the network from the store since service 1035 // bindings cleanup requires the network in the store. 1036 n.cancelDriverWatches() 1037 if err = n.leaveCluster(); err != nil { 1038 log.G(context.TODO()).Errorf("Failed leaving network %s from the agent cluster: %v", n.Name(), err) 1039 } 1040 1041 // Cleanup the service discovery for this network 1042 c.cleanupServiceDiscovery(n.ID()) 1043 1044 // Cleanup the load balancer. On Windows this call is required 1045 // to remove remote loadbalancers in VFP, and must be performed before 1046 // dataplane network deletion. 1047 if runtime.GOOS == "windows" { 1048 c.cleanupServiceBindings(n.ID()) 1049 } 1050 1051 // Delete the network from the dataplane 1052 if err = n.deleteNetwork(); err != nil { 1053 if !force { 1054 return err 1055 } 1056 log.G(context.TODO()).Debugf("driver failed to delete stale network %s (%s): %v", n.Name(), n.ID(), err) 1057 } 1058 1059 removeFromStore: 1060 // deleteFromStore performs an atomic delete operation and the 1061 // Network.epCnt will help prevent any possible 1062 // race between endpoint join and network delete 1063 if err = c.deleteFromStore(n.getEpCnt()); err != nil { 1064 if !force { 1065 return fmt.Errorf("error deleting network endpoint count from store: %v", err) 1066 } 1067 log.G(context.TODO()).Debugf("Error deleting endpoint count from store for stale network %s (%s) for deletion: %v", n.Name(), n.ID(), err) 1068 } 1069 1070 if err = c.deleteFromStore(n); err != nil { 1071 return fmt.Errorf("error deleting network from store: %v", err) 1072 } 1073 1074 return nil 1075 } 1076 1077 func (n *Network) deleteNetwork() error { 1078 d, err := n.driver(true) 1079 if err != nil { 1080 return fmt.Errorf("failed deleting Network: %v", err) 1081 } 1082 1083 if err := d.DeleteNetwork(n.ID()); err != nil { 1084 // Forbidden Errors should be honored 1085 if _, ok := err.(types.ForbiddenError); ok { 1086 return err 1087 } 1088 1089 if _, ok := err.(types.MaskableError); !ok { 1090 log.G(context.TODO()).Warnf("driver error deleting network %s : %v", n.name, err) 1091 } 1092 } 1093 1094 for _, resolver := range n.resolver { 1095 resolver.Stop() 1096 } 1097 return nil 1098 } 1099 1100 func (n *Network) addEndpoint(ep *Endpoint) error { 1101 d, err := n.driver(true) 1102 if err != nil { 1103 return fmt.Errorf("failed to add endpoint: %v", err) 1104 } 1105 1106 err = d.CreateEndpoint(n.id, ep.id, ep.Iface(), ep.generic) 1107 if err != nil { 1108 return types.InternalErrorf("failed to create endpoint %s on network %s: %v", 1109 ep.Name(), n.Name(), err) 1110 } 1111 1112 return nil 1113 } 1114 1115 // CreateEndpoint creates a new endpoint to this network symbolically identified by the 1116 // specified unique name. The options parameter carries driver specific options. 1117 func (n *Network) CreateEndpoint(name string, options ...EndpointOption) (*Endpoint, error) { 1118 var err error 1119 if strings.TrimSpace(name) == "" { 1120 return nil, ErrInvalidName(name) 1121 } 1122 1123 if n.ConfigOnly() { 1124 return nil, types.ForbiddenErrorf("cannot create endpoint on configuration-only network") 1125 } 1126 1127 if _, err = n.EndpointByName(name); err == nil { 1128 return nil, types.ForbiddenErrorf("endpoint with name %s already exists in network %s", name, n.Name()) 1129 } 1130 1131 n.ctrlr.networkLocker.Lock(n.id) 1132 defer n.ctrlr.networkLocker.Unlock(n.id) //nolint:errcheck 1133 1134 return n.createEndpoint(name, options...) 1135 } 1136 1137 func (n *Network) createEndpoint(name string, options ...EndpointOption) (*Endpoint, error) { 1138 var err error 1139 1140 ep := &Endpoint{name: name, generic: make(map[string]interface{}), iface: &EndpointInterface{}} 1141 ep.id = stringid.GenerateRandomID() 1142 1143 // Initialize ep.network with a possibly stale copy of n. We need this to get network from 1144 // store. But once we get it from store we will have the most uptodate copy possibly. 1145 ep.network = n 1146 ep.network, err = ep.getNetworkFromStore() 1147 if err != nil { 1148 log.G(context.TODO()).Errorf("failed to get network during CreateEndpoint: %v", err) 1149 return nil, err 1150 } 1151 n = ep.network 1152 1153 ep.processOptions(options...) 1154 1155 for _, llIPNet := range ep.Iface().LinkLocalAddresses() { 1156 if !llIPNet.IP.IsLinkLocalUnicast() { 1157 return nil, types.InvalidParameterErrorf("invalid link local IP address: %v", llIPNet.IP) 1158 } 1159 } 1160 1161 if opt, ok := ep.generic[netlabel.MacAddress]; ok { 1162 if mac, ok := opt.(net.HardwareAddr); ok { 1163 ep.iface.mac = mac 1164 } 1165 } 1166 1167 ipam, capability, err := n.getController().getIPAMDriver(n.ipamType) 1168 if err != nil { 1169 return nil, err 1170 } 1171 1172 if capability.RequiresMACAddress { 1173 if ep.iface.mac == nil { 1174 ep.iface.mac = netutils.GenerateRandomMAC() 1175 } 1176 if ep.ipamOptions == nil { 1177 ep.ipamOptions = make(map[string]string) 1178 } 1179 ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String() 1180 } 1181 1182 if err = ep.assignAddress(ipam, true, n.enableIPv6 && !n.postIPv6); err != nil { 1183 return nil, err 1184 } 1185 defer func() { 1186 if err != nil { 1187 ep.releaseAddress() 1188 } 1189 }() 1190 1191 if err = n.addEndpoint(ep); err != nil { 1192 return nil, err 1193 } 1194 defer func() { 1195 if err != nil { 1196 if e := ep.deleteEndpoint(false); e != nil { 1197 log.G(context.TODO()).Warnf("cleaning up endpoint failed %s : %v", name, e) 1198 } 1199 } 1200 }() 1201 1202 // We should perform updateToStore call right after addEndpoint 1203 // in order to have iface properly configured 1204 if err = n.getController().updateToStore(ep); err != nil { 1205 return nil, err 1206 } 1207 defer func() { 1208 if err != nil { 1209 if e := n.getController().deleteFromStore(ep); e != nil { 1210 log.G(context.TODO()).Warnf("error rolling back endpoint %s from store: %v", name, e) 1211 } 1212 } 1213 }() 1214 1215 if err = ep.assignAddress(ipam, false, n.enableIPv6 && n.postIPv6); err != nil { 1216 return nil, err 1217 } 1218 1219 if !n.getController().isSwarmNode() || n.Scope() != scope.Swarm || !n.driverIsMultihost() { 1220 n.updateSvcRecord(ep, true) 1221 defer func() { 1222 if err != nil { 1223 n.updateSvcRecord(ep, false) 1224 } 1225 }() 1226 } 1227 1228 // Increment endpoint count to indicate completion of endpoint addition 1229 if err = n.getEpCnt().IncEndpointCnt(); err != nil { 1230 return nil, err 1231 } 1232 1233 return ep, nil 1234 } 1235 1236 // Endpoints returns the list of Endpoint(s) in this network. 1237 func (n *Network) Endpoints() []*Endpoint { 1238 endpoints, err := n.getEndpointsFromStore() 1239 if err != nil { 1240 log.G(context.TODO()).Error(err) 1241 } 1242 return endpoints 1243 } 1244 1245 // WalkEndpoints uses the provided function to walk the Endpoints. 1246 func (n *Network) WalkEndpoints(walker EndpointWalker) { 1247 for _, e := range n.Endpoints() { 1248 if walker(e) { 1249 return 1250 } 1251 } 1252 } 1253 1254 // EndpointByName returns the Endpoint which has the passed name. If not found, 1255 // the error ErrNoSuchEndpoint is returned. 1256 func (n *Network) EndpointByName(name string) (*Endpoint, error) { 1257 if name == "" { 1258 return nil, ErrInvalidName(name) 1259 } 1260 var e *Endpoint 1261 1262 s := func(current *Endpoint) bool { 1263 if current.Name() == name { 1264 e = current 1265 return true 1266 } 1267 return false 1268 } 1269 1270 n.WalkEndpoints(s) 1271 1272 if e == nil { 1273 return nil, ErrNoSuchEndpoint(name) 1274 } 1275 1276 return e, nil 1277 } 1278 1279 // EndpointByID should *never* be called as it's going to create a 2nd instance of an Endpoint. The first one lives in 1280 // the Sandbox the endpoint is attached to. Instead, the endpoint should be retrieved by calling [Sandbox.Endpoints()]. 1281 func (n *Network) EndpointByID(id string) (*Endpoint, error) { 1282 if id == "" { 1283 return nil, ErrInvalidID(id) 1284 } 1285 1286 ep, err := n.getEndpointFromStore(id) 1287 if err != nil { 1288 return nil, ErrNoSuchEndpoint(id) 1289 } 1290 1291 return ep, nil 1292 } 1293 1294 // updateSvcRecord adds or deletes local DNS records for a given Endpoint. 1295 func (n *Network) updateSvcRecord(ep *Endpoint, isAdd bool) { 1296 iface := ep.Iface() 1297 if iface == nil || iface.Address() == nil { 1298 return 1299 } 1300 1301 var ipv6 net.IP 1302 if iface.AddressIPv6() != nil { 1303 ipv6 = iface.AddressIPv6().IP 1304 } 1305 1306 serviceID := ep.svcID 1307 if serviceID == "" { 1308 serviceID = ep.ID() 1309 } 1310 1311 dnsNames := ep.getDNSNames() 1312 if isAdd { 1313 for i, dnsName := range dnsNames { 1314 ipMapUpdate := i == 0 // ipMapUpdate indicates whether PTR records should be updated. 1315 n.addSvcRecords(ep.ID(), dnsName, serviceID, iface.Address().IP, ipv6, ipMapUpdate, "updateSvcRecord") 1316 } 1317 } else { 1318 for i, dnsName := range dnsNames { 1319 ipMapUpdate := i == 0 // ipMapUpdate indicates whether PTR records should be updated. 1320 n.deleteSvcRecords(ep.ID(), dnsName, serviceID, iface.Address().IP, ipv6, ipMapUpdate, "updateSvcRecord") 1321 } 1322 } 1323 } 1324 1325 func addIPToName(ipMap *setmatrix.SetMatrix[ipInfo], name, serviceID string, ip net.IP) { 1326 reverseIP := netutils.ReverseIP(ip.String()) 1327 ipMap.Insert(reverseIP, ipInfo{ 1328 name: name, 1329 serviceID: serviceID, 1330 }) 1331 } 1332 1333 func delIPToName(ipMap *setmatrix.SetMatrix[ipInfo], name, serviceID string, ip net.IP) { 1334 reverseIP := netutils.ReverseIP(ip.String()) 1335 ipMap.Remove(reverseIP, ipInfo{ 1336 name: name, 1337 serviceID: serviceID, 1338 }) 1339 } 1340 1341 func addNameToIP(svcMap *setmatrix.SetMatrix[svcMapEntry], name, serviceID string, epIP net.IP) { 1342 // Since DNS name resolution is case-insensitive, Use the lower-case form 1343 // of the name as the key into svcMap 1344 lowerCaseName := strings.ToLower(name) 1345 svcMap.Insert(lowerCaseName, svcMapEntry{ 1346 ip: epIP.String(), 1347 serviceID: serviceID, 1348 }) 1349 } 1350 1351 func delNameToIP(svcMap *setmatrix.SetMatrix[svcMapEntry], name, serviceID string, epIP net.IP) { 1352 lowerCaseName := strings.ToLower(name) 1353 svcMap.Remove(lowerCaseName, svcMapEntry{ 1354 ip: epIP.String(), 1355 serviceID: serviceID, 1356 }) 1357 } 1358 1359 // TODO(aker): remove ipMapUpdate param and add a proper method dedicated to update PTR records. 1360 func (n *Network) addSvcRecords(eID, name, serviceID string, epIP, epIPv6 net.IP, ipMapUpdate bool, method string) { 1361 // Do not add service names for ingress network as this is a 1362 // routing only network 1363 if n.ingress { 1364 return 1365 } 1366 networkID := n.ID() 1367 log.G(context.TODO()).Debugf("%s (%.7s).addSvcRecords(%s, %s, %s, %t) %s sid:%s", eID, networkID, name, epIP, epIPv6, ipMapUpdate, method, serviceID) 1368 1369 c := n.getController() 1370 c.mu.Lock() 1371 defer c.mu.Unlock() 1372 1373 sr, ok := c.svcRecords[networkID] 1374 if !ok { 1375 sr = &svcInfo{} 1376 c.svcRecords[networkID] = sr 1377 } 1378 1379 if ipMapUpdate { 1380 addIPToName(&sr.ipMap, name, serviceID, epIP) 1381 if epIPv6 != nil { 1382 addIPToName(&sr.ipMap, name, serviceID, epIPv6) 1383 } 1384 } 1385 1386 addNameToIP(&sr.svcMap, name, serviceID, epIP) 1387 if epIPv6 != nil { 1388 addNameToIP(&sr.svcIPv6Map, name, serviceID, epIPv6) 1389 } 1390 } 1391 1392 func (n *Network) deleteSvcRecords(eID, name, serviceID string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool, method string) { 1393 // Do not delete service names from ingress network as this is a 1394 // routing only network 1395 if n.ingress { 1396 return 1397 } 1398 networkID := n.ID() 1399 log.G(context.TODO()).Debugf("%s (%.7s).deleteSvcRecords(%s, %s, %s, %t) %s sid:%s ", eID, networkID, name, epIP, epIPv6, ipMapUpdate, method, serviceID) 1400 1401 c := n.getController() 1402 c.mu.Lock() 1403 defer c.mu.Unlock() 1404 1405 sr, ok := c.svcRecords[networkID] 1406 if !ok { 1407 return 1408 } 1409 1410 if ipMapUpdate { 1411 delIPToName(&sr.ipMap, name, serviceID, epIP) 1412 1413 if epIPv6 != nil { 1414 delIPToName(&sr.ipMap, name, serviceID, epIPv6) 1415 } 1416 } 1417 1418 delNameToIP(&sr.svcMap, name, serviceID, epIP) 1419 1420 if epIPv6 != nil { 1421 delNameToIP(&sr.svcIPv6Map, name, serviceID, epIPv6) 1422 } 1423 } 1424 1425 func (n *Network) getSvcRecords(ep *Endpoint) []etchosts.Record { 1426 n.mu.Lock() 1427 defer n.mu.Unlock() 1428 1429 if ep == nil { 1430 return nil 1431 } 1432 1433 var recs []etchosts.Record 1434 1435 epName := ep.Name() 1436 1437 n.ctrlr.mu.Lock() 1438 defer n.ctrlr.mu.Unlock() 1439 sr, ok := n.ctrlr.svcRecords[n.id] 1440 if !ok { 1441 return nil 1442 } 1443 1444 svcMapKeys := sr.svcMap.Keys() 1445 // Loop on service names on this network 1446 for _, k := range svcMapKeys { 1447 if strings.Split(k, ".")[0] == epName { 1448 continue 1449 } 1450 // Get all the IPs associated to this service 1451 mapEntryList, ok := sr.svcMap.Get(k) 1452 if !ok { 1453 // The key got deleted 1454 continue 1455 } 1456 if len(mapEntryList) == 0 { 1457 log.G(context.TODO()).Warnf("Found empty list of IP addresses for service %s on network %s (%s)", k, n.name, n.id) 1458 continue 1459 } 1460 1461 recs = append(recs, etchosts.Record{ 1462 Hosts: k, 1463 IP: mapEntryList[0].ip, 1464 }) 1465 } 1466 1467 return recs 1468 } 1469 1470 func (n *Network) getController() *Controller { 1471 n.mu.Lock() 1472 defer n.mu.Unlock() 1473 return n.ctrlr 1474 } 1475 1476 func (n *Network) ipamAllocate() error { 1477 if n.hasSpecialDriver() { 1478 return nil 1479 } 1480 1481 ipam, _, err := n.getController().getIPAMDriver(n.ipamType) 1482 if err != nil { 1483 return err 1484 } 1485 1486 if n.addrSpace == "" { 1487 if n.addrSpace, err = n.deriveAddressSpace(); err != nil { 1488 return err 1489 } 1490 } 1491 1492 err = n.ipamAllocateVersion(4, ipam) 1493 if err != nil { 1494 return err 1495 } 1496 1497 defer func() { 1498 if err != nil { 1499 n.ipamReleaseVersion(4, ipam) 1500 } 1501 }() 1502 1503 if !n.enableIPv6 { 1504 return nil 1505 } 1506 1507 err = n.ipamAllocateVersion(6, ipam) 1508 return err 1509 } 1510 1511 func (n *Network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, requestedPool, requestedSubPool string, options map[string]string, v6 bool) (poolID string, pool *net.IPNet, meta map[string]string, err error) { 1512 var tmpPoolLeases []string 1513 defer func() { 1514 // Prevent repeated lock/unlock in the loop. 1515 nwName := n.Name() 1516 // Release all pools we held on to. 1517 for _, pID := range tmpPoolLeases { 1518 if err := ipam.ReleasePool(pID); err != nil { 1519 log.G(context.TODO()).Warnf("Failed to release overlapping pool %s while returning from pool request helper for network %s", pool, nwName) 1520 } 1521 } 1522 }() 1523 1524 for { 1525 poolID, pool, meta, err = ipam.RequestPool(addressSpace, requestedPool, requestedSubPool, options, v6) 1526 if err != nil { 1527 return "", nil, nil, err 1528 } 1529 1530 // If the network pool was explicitly chosen, the network belongs to 1531 // global scope, or it is invalid ("0.0.0.0/0"), then we don't perform 1532 // check for overlaps. 1533 // 1534 // FIXME(thaJeztah): why are we ignoring invalid pools here? 1535 // 1536 // The "invalid" conditions was added in [libnetwork#1095][1], which 1537 // moved code to reduce os-specific dependencies in the ipam package, 1538 // but also introduced a types.IsIPNetValid() function, which considers 1539 // "0.0.0.0/0" invalid, and added it to the conditions below. 1540 // 1541 // Unfortunately review does not mention this change, so there's no 1542 // context why. Possibly this was done to prevent errors further down 1543 // the line (when checking for overlaps), but returning an error here 1544 // instead would likely have avoided that as well, so we can only guess. 1545 // 1546 // [1]: https://github.com/moby/libnetwork/commit/5ca79d6b87873264516323a7b76f0af7d0298492#diff-bdcd879439d041827d334846f9aba01de6e3683ed8fdd01e63917dae6df23846 1547 if requestedPool != "" || n.Scope() == scope.Global || pool.String() == "0.0.0.0/0" { 1548 return poolID, pool, meta, nil 1549 } 1550 1551 // Check for overlap and if none found, we have found the right pool. 1552 if _, err := netutils.FindAvailableNetwork([]*net.IPNet{pool}); err == nil { 1553 return poolID, pool, meta, nil 1554 } 1555 1556 // Pool obtained in this iteration is overlapping. Hold onto the pool 1557 // and don't release it yet, because we don't want IPAM to give us back 1558 // the same pool over again. But make sure we still do a deferred release 1559 // when we have either obtained a non-overlapping pool or ran out of 1560 // pre-defined pools. 1561 tmpPoolLeases = append(tmpPoolLeases, poolID) 1562 } 1563 } 1564 1565 func (n *Network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error { 1566 var ( 1567 cfgList *[]*IpamConf 1568 infoList *[]*IpamInfo 1569 err error 1570 ) 1571 1572 switch ipVer { 1573 case 4: 1574 cfgList = &n.ipamV4Config 1575 infoList = &n.ipamV4Info 1576 case 6: 1577 cfgList = &n.ipamV6Config 1578 infoList = &n.ipamV6Info 1579 default: 1580 return types.InternalErrorf("incorrect ip version passed to ipam allocate: %d", ipVer) 1581 } 1582 1583 if len(*cfgList) == 0 { 1584 *cfgList = []*IpamConf{{}} 1585 } 1586 1587 *infoList = make([]*IpamInfo, len(*cfgList)) 1588 1589 log.G(context.TODO()).Debugf("Allocating IPv%d pools for network %s (%s)", ipVer, n.Name(), n.ID()) 1590 1591 for i, cfg := range *cfgList { 1592 if err = cfg.Validate(); err != nil { 1593 return err 1594 } 1595 d := &IpamInfo{} 1596 (*infoList)[i] = d 1597 1598 d.AddressSpace = n.addrSpace 1599 d.PoolID, d.Pool, d.Meta, err = n.requestPoolHelper(ipam, n.addrSpace, cfg.PreferredPool, cfg.SubPool, n.ipamOptions, ipVer == 6) 1600 if err != nil { 1601 return err 1602 } 1603 1604 defer func() { 1605 if err != nil { 1606 if err := ipam.ReleasePool(d.PoolID); err != nil { 1607 log.G(context.TODO()).Warnf("Failed to release address pool %s after failure to create network %s (%s)", d.PoolID, n.Name(), n.ID()) 1608 } 1609 } 1610 }() 1611 1612 if gws, ok := d.Meta[netlabel.Gateway]; ok { 1613 if d.Gateway, err = types.ParseCIDR(gws); err != nil { 1614 return types.InvalidParameterErrorf("failed to parse gateway address (%v) returned by ipam driver: %v", gws, err) 1615 } 1616 } 1617 1618 // If user requested a specific gateway, libnetwork will allocate it 1619 // irrespective of whether ipam driver returned a gateway already. 1620 // If none of the above is true, libnetwork will allocate one. 1621 if cfg.Gateway != "" || d.Gateway == nil { 1622 gatewayOpts := map[string]string{ 1623 ipamapi.RequestAddressType: netlabel.Gateway, 1624 } 1625 if d.Gateway, _, err = ipam.RequestAddress(d.PoolID, net.ParseIP(cfg.Gateway), gatewayOpts); err != nil { 1626 return types.InternalErrorf("failed to allocate gateway (%v): %v", cfg.Gateway, err) 1627 } 1628 } 1629 1630 // Auxiliary addresses must be part of the master address pool 1631 // If they fall into the container addressable pool, libnetwork will reserve them 1632 if cfg.AuxAddresses != nil { 1633 var ip net.IP 1634 d.IPAMData.AuxAddresses = make(map[string]*net.IPNet, len(cfg.AuxAddresses)) 1635 for k, v := range cfg.AuxAddresses { 1636 if ip = net.ParseIP(v); ip == nil { 1637 return types.InvalidParameterErrorf("non parsable secondary ip address (%s:%s) passed for network %s", k, v, n.Name()) 1638 } 1639 if !d.Pool.Contains(ip) { 1640 return types.ForbiddenErrorf("auxiliary address: (%s:%s) must belong to the master pool: %s", k, v, d.Pool) 1641 } 1642 // Attempt reservation in the container addressable pool, silent the error if address does not belong to that pool 1643 if d.IPAMData.AuxAddresses[k], _, err = ipam.RequestAddress(d.PoolID, ip, nil); err != nil && err != ipamapi.ErrIPOutOfRange { 1644 return types.InternalErrorf("failed to allocate secondary ip address (%s:%s): %v", k, v, err) 1645 } 1646 } 1647 } 1648 } 1649 1650 return nil 1651 } 1652 1653 func (n *Network) ipamRelease() { 1654 if n.hasSpecialDriver() { 1655 return 1656 } 1657 ipam, _, err := n.getController().getIPAMDriver(n.ipamType) 1658 if err != nil { 1659 log.G(context.TODO()).Warnf("Failed to retrieve ipam driver to release address pool(s) on delete of network %s (%s): %v", n.Name(), n.ID(), err) 1660 return 1661 } 1662 n.ipamReleaseVersion(4, ipam) 1663 n.ipamReleaseVersion(6, ipam) 1664 } 1665 1666 func (n *Network) ipamReleaseVersion(ipVer int, ipam ipamapi.Ipam) { 1667 var infoList *[]*IpamInfo 1668 1669 switch ipVer { 1670 case 4: 1671 infoList = &n.ipamV4Info 1672 case 6: 1673 infoList = &n.ipamV6Info 1674 default: 1675 log.G(context.TODO()).Warnf("incorrect ip version passed to ipam release: %d", ipVer) 1676 return 1677 } 1678 1679 if len(*infoList) == 0 { 1680 return 1681 } 1682 1683 log.G(context.TODO()).Debugf("releasing IPv%d pools from network %s (%s)", ipVer, n.Name(), n.ID()) 1684 1685 for _, d := range *infoList { 1686 if d.Gateway != nil { 1687 if err := ipam.ReleaseAddress(d.PoolID, d.Gateway.IP); err != nil { 1688 log.G(context.TODO()).Warnf("Failed to release gateway ip address %s on delete of network %s (%s): %v", d.Gateway.IP, n.Name(), n.ID(), err) 1689 } 1690 } 1691 if d.IPAMData.AuxAddresses != nil { 1692 for k, nw := range d.IPAMData.AuxAddresses { 1693 if d.Pool.Contains(nw.IP) { 1694 if err := ipam.ReleaseAddress(d.PoolID, nw.IP); err != nil && err != ipamapi.ErrIPOutOfRange { 1695 log.G(context.TODO()).Warnf("Failed to release secondary ip address %s (%v) on delete of network %s (%s): %v", k, nw.IP, n.Name(), n.ID(), err) 1696 } 1697 } 1698 } 1699 } 1700 if err := ipam.ReleasePool(d.PoolID); err != nil { 1701 log.G(context.TODO()).Warnf("Failed to release address pool %s on delete of network %s (%s): %v", d.PoolID, n.Name(), n.ID(), err) 1702 } 1703 } 1704 1705 *infoList = nil 1706 } 1707 1708 func (n *Network) getIPInfo(ipVer int) []*IpamInfo { 1709 var info []*IpamInfo 1710 switch ipVer { 1711 case 4: 1712 info = n.ipamV4Info 1713 case 6: 1714 info = n.ipamV6Info 1715 default: 1716 return nil 1717 } 1718 l := make([]*IpamInfo, 0, len(info)) 1719 n.mu.Lock() 1720 l = append(l, info...) 1721 n.mu.Unlock() 1722 return l 1723 } 1724 1725 func (n *Network) getIPData(ipVer int) []driverapi.IPAMData { 1726 var info []*IpamInfo 1727 switch ipVer { 1728 case 4: 1729 info = n.ipamV4Info 1730 case 6: 1731 info = n.ipamV6Info 1732 default: 1733 return nil 1734 } 1735 l := make([]driverapi.IPAMData, 0, len(info)) 1736 n.mu.Lock() 1737 for _, d := range info { 1738 l = append(l, d.IPAMData) 1739 } 1740 n.mu.Unlock() 1741 return l 1742 } 1743 1744 func (n *Network) deriveAddressSpace() (string, error) { 1745 ipam, _ := n.getController().ipamRegistry.IPAM(n.ipamType) 1746 if ipam == nil { 1747 return "", types.NotFoundErrorf("failed to get default address space: unknown ipam type %q", n.ipamType) 1748 } 1749 local, global, err := ipam.GetDefaultAddressSpaces() 1750 if err != nil { 1751 return "", types.NotFoundErrorf("failed to get default address space: %v", err) 1752 } 1753 if n.Scope() == scope.Global { 1754 return global, nil 1755 } 1756 return local, nil 1757 } 1758 1759 // Peers returns a slice of PeerInfo structures which has the information about the peer 1760 // nodes participating in the same overlay network. This is currently the per-network 1761 // gossip cluster. For non-dynamic overlay networks and bridge networks it returns an 1762 // empty slice 1763 func (n *Network) Peers() []networkdb.PeerInfo { 1764 if !n.Dynamic() { 1765 return []networkdb.PeerInfo{} 1766 } 1767 1768 a := n.getController().getAgent() 1769 if a == nil { 1770 return []networkdb.PeerInfo{} 1771 } 1772 1773 return a.networkDB.Peers(n.ID()) 1774 } 1775 1776 func (n *Network) DriverOptions() map[string]string { 1777 n.mu.Lock() 1778 defer n.mu.Unlock() 1779 if n.generic != nil { 1780 if m, ok := n.generic[netlabel.GenericData]; ok { 1781 return m.(map[string]string) 1782 } 1783 } 1784 return map[string]string{} 1785 } 1786 1787 func (n *Network) Scope() string { 1788 n.mu.Lock() 1789 defer n.mu.Unlock() 1790 return n.scope 1791 } 1792 1793 func (n *Network) IpamConfig() (ipamType string, ipamOptions map[string]string, ipamV4Config []*IpamConf, ipamV6Config []*IpamConf) { 1794 n.mu.Lock() 1795 defer n.mu.Unlock() 1796 1797 ipamV4Config = make([]*IpamConf, len(n.ipamV4Config)) 1798 for i, c := range n.ipamV4Config { 1799 cc := &IpamConf{} 1800 if err := c.CopyTo(cc); err != nil { 1801 log.G(context.TODO()).WithError(err).Error("Error copying ipam ipv4 config") 1802 } 1803 ipamV4Config[i] = cc 1804 } 1805 1806 ipamV6Config = make([]*IpamConf, len(n.ipamV6Config)) 1807 for i, c := range n.ipamV6Config { 1808 cc := &IpamConf{} 1809 if err := c.CopyTo(cc); err != nil { 1810 log.G(context.TODO()).WithError(err).Debug("Error copying ipam ipv6 config") 1811 } 1812 ipamV6Config[i] = cc 1813 } 1814 1815 return n.ipamType, n.ipamOptions, ipamV4Config, ipamV6Config 1816 } 1817 1818 func (n *Network) IpamInfo() (ipamV4Info []*IpamInfo, ipamV6Info []*IpamInfo) { 1819 n.mu.Lock() 1820 defer n.mu.Unlock() 1821 1822 ipamV4Info = make([]*IpamInfo, len(n.ipamV4Info)) 1823 for i, info := range n.ipamV4Info { 1824 ic := &IpamInfo{} 1825 if err := info.CopyTo(ic); err != nil { 1826 log.G(context.TODO()).WithError(err).Error("Error copying IPv4 IPAM config") 1827 } 1828 ipamV4Info[i] = ic 1829 } 1830 1831 ipamV6Info = make([]*IpamInfo, len(n.ipamV6Info)) 1832 for i, info := range n.ipamV6Info { 1833 ic := &IpamInfo{} 1834 if err := info.CopyTo(ic); err != nil { 1835 log.G(context.TODO()).WithError(err).Error("Error copying IPv6 IPAM config") 1836 } 1837 ipamV6Info[i] = ic 1838 } 1839 1840 return ipamV4Info, ipamV6Info 1841 } 1842 1843 func (n *Network) Internal() bool { 1844 n.mu.Lock() 1845 defer n.mu.Unlock() 1846 1847 return n.internal 1848 } 1849 1850 func (n *Network) Attachable() bool { 1851 n.mu.Lock() 1852 defer n.mu.Unlock() 1853 1854 return n.attachable 1855 } 1856 1857 func (n *Network) Ingress() bool { 1858 n.mu.Lock() 1859 defer n.mu.Unlock() 1860 1861 return n.ingress 1862 } 1863 1864 func (n *Network) Dynamic() bool { 1865 n.mu.Lock() 1866 defer n.mu.Unlock() 1867 1868 return n.dynamic 1869 } 1870 1871 func (n *Network) IPv6Enabled() bool { 1872 n.mu.Lock() 1873 defer n.mu.Unlock() 1874 1875 return n.enableIPv6 1876 } 1877 1878 func (n *Network) ConfigFrom() string { 1879 n.mu.Lock() 1880 defer n.mu.Unlock() 1881 1882 return n.configFrom 1883 } 1884 1885 func (n *Network) ConfigOnly() bool { 1886 n.mu.Lock() 1887 defer n.mu.Unlock() 1888 1889 return n.configOnly 1890 } 1891 1892 func (n *Network) Labels() map[string]string { 1893 n.mu.Lock() 1894 defer n.mu.Unlock() 1895 1896 lbls := make(map[string]string, len(n.labels)) 1897 for k, v := range n.labels { 1898 lbls[k] = v 1899 } 1900 1901 return lbls 1902 } 1903 1904 func (n *Network) TableEventRegister(tableName string, objType driverapi.ObjectType) error { 1905 if !driverapi.IsValidType(objType) { 1906 return fmt.Errorf("invalid object type %v in registering table, %s", objType, tableName) 1907 } 1908 1909 t := networkDBTable{ 1910 name: tableName, 1911 objType: objType, 1912 } 1913 n.mu.Lock() 1914 defer n.mu.Unlock() 1915 n.driverTables = append(n.driverTables, t) 1916 return nil 1917 } 1918 1919 func (n *Network) UpdateIpamConfig(ipV4Data []driverapi.IPAMData) { 1920 ipamV4Config := make([]*IpamConf, len(ipV4Data)) 1921 1922 for i, data := range ipV4Data { 1923 ic := &IpamConf{} 1924 ic.PreferredPool = data.Pool.String() 1925 ic.Gateway = data.Gateway.IP.String() 1926 ipamV4Config[i] = ic 1927 } 1928 1929 n.mu.Lock() 1930 defer n.mu.Unlock() 1931 n.ipamV4Config = ipamV4Config 1932 } 1933 1934 // Special drivers are ones which do not need to perform any Network plumbing 1935 func (n *Network) hasSpecialDriver() bool { 1936 return n.Type() == "host" || n.Type() == "null" 1937 } 1938 1939 func (n *Network) hasLoadBalancerEndpoint() bool { 1940 return len(n.loadBalancerIP) != 0 1941 } 1942 1943 func (n *Network) ResolveName(ctx context.Context, req string, ipType int) ([]net.IP, bool) { 1944 var ipv6Miss bool 1945 1946 c := n.getController() 1947 networkID := n.ID() 1948 1949 _, span := otel.Tracer("").Start(ctx, "Network.ResolveName", trace.WithAttributes( 1950 attribute.String("libnet.network.name", n.Name()), 1951 attribute.String("libnet.network.id", networkID), 1952 )) 1953 defer span.End() 1954 1955 c.mu.Lock() 1956 // TODO(aker): release the lock earlier 1957 defer c.mu.Unlock() 1958 sr, ok := c.svcRecords[networkID] 1959 1960 if !ok { 1961 return nil, false 1962 } 1963 1964 req = strings.TrimSuffix(req, ".") 1965 req = strings.ToLower(req) 1966 ipSet, ok := sr.svcMap.Get(req) 1967 1968 if ipType == types.IPv6 { 1969 // If the name resolved to v4 address then its a valid name in 1970 // the docker network domain. If the network is not v6 enabled 1971 // set ipv6Miss to filter the DNS query from going to external 1972 // resolvers. 1973 if ok && !n.enableIPv6 { 1974 ipv6Miss = true 1975 } 1976 ipSet, ok = sr.svcIPv6Map.Get(req) 1977 } 1978 1979 if ok && len(ipSet) > 0 { 1980 // this map is to avoid IP duplicates, this can happen during a transition period where 2 services are using the same IP 1981 noDup := make(map[string]bool) 1982 var ipLocal []net.IP 1983 for _, ip := range ipSet { 1984 if _, dup := noDup[ip.ip]; !dup { 1985 noDup[ip.ip] = true 1986 ipLocal = append(ipLocal, net.ParseIP(ip.ip)) 1987 } 1988 } 1989 return ipLocal, ok 1990 } 1991 1992 return nil, ipv6Miss 1993 } 1994 1995 func (n *Network) HandleQueryResp(name string, ip net.IP) { 1996 networkID := n.ID() 1997 c := n.getController() 1998 c.mu.Lock() 1999 defer c.mu.Unlock() 2000 sr, ok := c.svcRecords[networkID] 2001 2002 if !ok { 2003 return 2004 } 2005 2006 ipStr := netutils.ReverseIP(ip.String()) 2007 // If an object with extResolver == true is already in the set this call will fail 2008 // but anyway it means that has already been inserted before 2009 if ok, _ := sr.ipMap.Contains(ipStr, ipInfo{name: name}); ok { 2010 sr.ipMap.Remove(ipStr, ipInfo{name: name}) 2011 sr.ipMap.Insert(ipStr, ipInfo{name: name, extResolver: true}) 2012 } 2013 } 2014 2015 func (n *Network) ResolveIP(_ context.Context, ip string) string { 2016 networkID := n.ID() 2017 c := n.getController() 2018 c.mu.Lock() 2019 defer c.mu.Unlock() 2020 sr, ok := c.svcRecords[networkID] 2021 2022 if !ok { 2023 return "" 2024 } 2025 2026 nwName := n.Name() 2027 2028 elemSet, ok := sr.ipMap.Get(ip) 2029 if !ok || len(elemSet) == 0 { 2030 return "" 2031 } 2032 // NOTE it is possible to have more than one element in the Set, this will happen 2033 // because of interleave of different events from different sources (local container create vs 2034 // network db notifications) 2035 // In such cases the resolution will be based on the first element of the set, and can vary 2036 // during the system stabilitation 2037 elem := elemSet[0] 2038 if elem.extResolver { 2039 return "" 2040 } 2041 2042 return elem.name + "." + nwName 2043 } 2044 2045 func (n *Network) ResolveService(ctx context.Context, name string) ([]*net.SRV, []net.IP) { 2046 c := n.getController() 2047 2048 srv := []*net.SRV{} 2049 ip := []net.IP{} 2050 2051 log.G(ctx).Debugf("Service name To resolve: %v", name) 2052 2053 // There are DNS implementations that allow SRV queries for names not in 2054 // the format defined by RFC 2782. Hence specific validations checks are 2055 // not done 2056 parts := strings.Split(name, ".") 2057 if len(parts) < 3 { 2058 return nil, nil 2059 } 2060 2061 portName := parts[0] 2062 proto := parts[1] 2063 svcName := strings.Join(parts[2:], ".") 2064 2065 networkID := n.ID() 2066 c.mu.Lock() 2067 defer c.mu.Unlock() 2068 sr, ok := c.svcRecords[networkID] 2069 2070 if !ok { 2071 return nil, nil 2072 } 2073 2074 svcs, ok := sr.service[svcName] 2075 if !ok { 2076 return nil, nil 2077 } 2078 2079 for _, svc := range svcs { 2080 if svc.portName != portName { 2081 continue 2082 } 2083 if svc.proto != proto { 2084 continue 2085 } 2086 for _, t := range svc.target { 2087 srv = append(srv, 2088 &net.SRV{ 2089 Target: t.name, 2090 Port: t.port, 2091 }) 2092 2093 ip = append(ip, t.ip) 2094 } 2095 } 2096 2097 return srv, ip 2098 } 2099 2100 func (n *Network) ExecFunc(f func()) error { 2101 return types.NotImplementedErrorf("ExecFunc not supported by network") 2102 } 2103 2104 func (n *Network) NdotsSet() bool { 2105 return false 2106 } 2107 2108 // config-only network is looked up by name 2109 func (c *Controller) getConfigNetwork(name string) (*Network, error) { 2110 var n *Network 2111 c.WalkNetworks(func(current *Network) bool { 2112 if current.ConfigOnly() && current.Name() == name { 2113 n = current 2114 return true 2115 } 2116 return false 2117 }) 2118 2119 if n == nil { 2120 return nil, types.NotFoundErrorf("configuration network %q not found", name) 2121 } 2122 2123 return n, nil 2124 } 2125 2126 func (n *Network) lbSandboxName() string { 2127 name := "lb-" + n.name 2128 if n.ingress { 2129 name = n.name + "-sbox" 2130 } 2131 return name 2132 } 2133 2134 func (n *Network) lbEndpointName() string { 2135 return n.name + "-endpoint" 2136 } 2137 2138 func (n *Network) createLoadBalancerSandbox() (retErr error) { 2139 sandboxName := n.lbSandboxName() 2140 // Mark the sandbox to be a load balancer 2141 sbOptions := []SandboxOption{OptionLoadBalancer(n.id)} 2142 if n.ingress { 2143 sbOptions = append(sbOptions, OptionIngress()) 2144 } 2145 sb, err := n.ctrlr.NewSandbox(sandboxName, sbOptions...) 2146 if err != nil { 2147 return err 2148 } 2149 defer func() { 2150 if retErr != nil { 2151 if e := n.ctrlr.SandboxDestroy(sandboxName); e != nil { 2152 log.G(context.TODO()).Warnf("could not delete sandbox %s on failure on failure (%v): %v", sandboxName, retErr, e) 2153 } 2154 } 2155 }() 2156 2157 endpointName := n.lbEndpointName() 2158 epOptions := []EndpointOption{ 2159 CreateOptionIpam(n.loadBalancerIP, nil, nil, nil), 2160 CreateOptionLoadBalancer(), 2161 } 2162 ep, err := n.createEndpoint(endpointName, epOptions...) 2163 if err != nil { 2164 return err 2165 } 2166 defer func() { 2167 if retErr != nil { 2168 if e := ep.Delete(true); e != nil { 2169 log.G(context.TODO()).Warnf("could not delete endpoint %s on failure on failure (%v): %v", endpointName, retErr, e) 2170 } 2171 } 2172 }() 2173 2174 if err := ep.Join(sb, nil); err != nil { 2175 return err 2176 } 2177 2178 return sb.EnableService() 2179 } 2180 2181 func (n *Network) deleteLoadBalancerSandbox() error { 2182 n.mu.Lock() 2183 c := n.ctrlr 2184 name := n.name 2185 n.mu.Unlock() 2186 2187 sandboxName := n.lbSandboxName() 2188 endpointName := n.lbEndpointName() 2189 2190 endpoint, err := n.EndpointByName(endpointName) 2191 if err != nil { 2192 log.G(context.TODO()).Warnf("Failed to find load balancer endpoint %s on network %s: %v", endpointName, name, err) 2193 } else { 2194 info := endpoint.Info() 2195 if info != nil { 2196 sb := info.Sandbox() 2197 if sb != nil { 2198 if err := sb.DisableService(); err != nil { 2199 log.G(context.TODO()).Warnf("Failed to disable service on sandbox %s: %v", sandboxName, err) 2200 // Ignore error and attempt to delete the load balancer endpoint 2201 } 2202 } 2203 } 2204 2205 if err := endpoint.Delete(true); err != nil { 2206 log.G(context.TODO()).Warnf("Failed to delete endpoint %s (%s) in %s: %v", endpoint.Name(), endpoint.ID(), sandboxName, err) 2207 // Ignore error and attempt to delete the sandbox. 2208 } 2209 } 2210 2211 if err := c.SandboxDestroy(sandboxName); err != nil { 2212 return fmt.Errorf("Failed to delete %s sandbox: %v", sandboxName, err) 2213 } 2214 return nil 2215 }