github.com/moby/docker@v26.1.3+incompatible/libnetwork/cnmallocator/networkallocator.go (about) 1 package cnmallocator 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "strings" 8 9 "github.com/containerd/log" 10 "github.com/docker/docker/libnetwork/driverapi" 11 "github.com/docker/docker/libnetwork/drivers/remote" 12 "github.com/docker/docker/libnetwork/drvregistry" 13 "github.com/docker/docker/libnetwork/ipamapi" 14 remoteipam "github.com/docker/docker/libnetwork/ipams/remote" 15 "github.com/docker/docker/libnetwork/netlabel" 16 "github.com/docker/docker/libnetwork/scope" 17 "github.com/docker/docker/pkg/plugingetter" 18 "github.com/moby/swarmkit/v2/api" 19 "github.com/moby/swarmkit/v2/manager/allocator/networkallocator" 20 "github.com/pkg/errors" 21 ) 22 23 const ( 24 // DefaultDriver defines the name of the driver to be used by 25 // default if a network without any driver name specified is 26 // created. 27 DefaultDriver = "overlay" 28 ) 29 30 // cnmNetworkAllocator acts as the controller for all network related operations 31 // like managing network and IPAM drivers and also creating and 32 // deleting networks and the associated resources. 33 type cnmNetworkAllocator struct { 34 // The plugin getter instance used to get network and IPAM driver plugins. 35 pg plugingetter.PluginGetter 36 37 // The driver registry for all internal and external IPAM drivers. 38 ipamRegistry drvregistry.IPAMs 39 40 // The driver registry for all internal and external network drivers. 41 networkRegistry drvregistry.Networks 42 43 // Local network state used by cnmNetworkAllocator to do network management. 44 networks map[string]*network 45 46 // Allocator state to indicate if allocation has been 47 // successfully completed for this service. 48 services map[string]struct{} 49 50 // Allocator state to indicate if allocation has been 51 // successfully completed for this task. 52 tasks map[string]struct{} 53 54 // Allocator state to indicate if allocation has been 55 // successfully completed for this node on this network. 56 // outer map key: node id 57 // inner map key: network id 58 nodes map[string]map[string]struct{} 59 } 60 61 // Local in-memory state related to network that need to be tracked by cnmNetworkAllocator 62 type network struct { 63 // A local cache of the store object. 64 nw *api.Network 65 66 // pools is used to save the internal poolIDs needed when 67 // releasing the pool. 68 pools map[string]string 69 70 // endpoints is a map of endpoint IP to the poolID from which it 71 // was allocated. 72 endpoints map[string]string 73 74 // isNodeLocal indicates whether the scope of the network's resources 75 // is local to the node. If true, it means the resources can only be 76 // allocated locally by the node where the network will be deployed. 77 // In this the swarm manager will skip the allocations. 78 isNodeLocal bool 79 } 80 81 type networkDriver struct { 82 driver driverapi.Driver 83 name string 84 capability *driverapi.Capability 85 } 86 87 // NewAllocator returns a new NetworkAllocator handle 88 func (p *Provider) NewAllocator(netConfig *networkallocator.Config) (networkallocator.NetworkAllocator, error) { 89 na := &cnmNetworkAllocator{ 90 networks: make(map[string]*network), 91 services: make(map[string]struct{}), 92 tasks: make(map[string]struct{}), 93 nodes: make(map[string]map[string]struct{}), 94 pg: p.pg, 95 } 96 97 for ntype, i := range initializers { 98 if err := i(&na.networkRegistry); err != nil { 99 return nil, fmt.Errorf("failed to register %q network driver: %w", ntype, err) 100 } 101 } 102 if err := remote.Register(&na.networkRegistry, p.pg); err != nil { 103 return nil, fmt.Errorf("failed to initialize network driver plugins: %w", err) 104 } 105 106 if err := initIPAMDrivers(&na.ipamRegistry, netConfig); err != nil { 107 return nil, err 108 } 109 if err := remoteipam.Register(&na.ipamRegistry, p.pg); err != nil { 110 return nil, fmt.Errorf("failed to initialize IPAM driver plugins: %w", err) 111 } 112 113 return na, nil 114 } 115 116 // Allocate allocates all the necessary resources both general 117 // and driver-specific which may be specified in the NetworkSpec 118 func (na *cnmNetworkAllocator) Allocate(n *api.Network) error { 119 if _, ok := na.networks[n.ID]; ok { 120 return fmt.Errorf("network %s already allocated", n.ID) 121 } 122 123 d, err := na.resolveDriver(n) 124 if err != nil { 125 return err 126 } 127 128 nw := &network{ 129 nw: n, 130 endpoints: make(map[string]string), 131 isNodeLocal: d.capability.DataScope == scope.Local, 132 } 133 134 // No swarm-level allocation can be provided by the network driver for 135 // node-local networks. Only thing needed is populating the driver's name 136 // in the driver's state. 137 if nw.isNodeLocal { 138 n.DriverState = &api.Driver{ 139 Name: d.name, 140 } 141 // In order to support backward compatibility with older daemon 142 // versions which assumes the network attachment to contains 143 // non nil IPAM attribute, passing an empty object 144 n.IPAM = &api.IPAMOptions{Driver: &api.Driver{}} 145 } else { 146 nw.pools, err = na.allocatePools(n) 147 if err != nil { 148 return errors.Wrapf(err, "failed allocating pools and gateway IP for network %s", n.ID) 149 } 150 151 if err := na.allocateDriverState(n); err != nil { 152 na.freePools(n, nw.pools) 153 return errors.Wrapf(err, "failed while allocating driver state for network %s", n.ID) 154 } 155 } 156 157 na.networks[n.ID] = nw 158 159 return nil 160 } 161 162 func (na *cnmNetworkAllocator) getNetwork(id string) *network { 163 return na.networks[id] 164 } 165 166 // Deallocate frees all the general and driver specific resources 167 // which were assigned to the passed network. 168 func (na *cnmNetworkAllocator) Deallocate(n *api.Network) error { 169 localNet := na.getNetwork(n.ID) 170 if localNet == nil { 171 return fmt.Errorf("could not get networker state for network %s", n.ID) 172 } 173 174 // No swarm-level resource deallocation needed for node-local networks 175 if localNet.isNodeLocal { 176 delete(na.networks, n.ID) 177 return nil 178 } 179 180 if err := na.freeDriverState(n); err != nil { 181 return errors.Wrapf(err, "failed to free driver state for network %s", n.ID) 182 } 183 184 delete(na.networks, n.ID) 185 186 return na.freePools(n, localNet.pools) 187 } 188 189 // AllocateService allocates all the network resources such as virtual 190 // IP needed by the service. 191 func (na *cnmNetworkAllocator) AllocateService(s *api.Service) (err error) { 192 defer func() { 193 if err != nil { 194 na.DeallocateService(s) 195 } 196 }() 197 198 if s.Endpoint == nil { 199 s.Endpoint = &api.Endpoint{} 200 } 201 s.Endpoint.Spec = s.Spec.Endpoint.Copy() 202 203 // If ResolutionMode is DNSRR do not try allocating VIPs, but 204 // free any VIP from previous state. 205 if s.Spec.Endpoint != nil && s.Spec.Endpoint.Mode == api.ResolutionModeDNSRoundRobin { 206 for _, vip := range s.Endpoint.VirtualIPs { 207 if err := na.deallocateVIP(vip); err != nil { 208 // don't bail here, deallocate as many as possible. 209 log.L.WithError(err). 210 WithField("vip.network", vip.NetworkID). 211 WithField("vip.addr", vip.Addr).Error("error deallocating vip") 212 } 213 } 214 215 s.Endpoint.VirtualIPs = nil 216 217 delete(na.services, s.ID) 218 return nil 219 } 220 221 specNetworks := serviceNetworks(s) 222 223 // Allocate VIPs for all the pre-populated endpoint attachments 224 eVIPs := s.Endpoint.VirtualIPs[:0] 225 226 vipLoop: 227 for _, eAttach := range s.Endpoint.VirtualIPs { 228 if na.IsVIPOnIngressNetwork(eAttach) && networkallocator.IsIngressNetworkNeeded(s) { 229 if err = na.allocateVIP(eAttach); err != nil { 230 return err 231 } 232 eVIPs = append(eVIPs, eAttach) 233 continue vipLoop 234 235 } 236 for _, nAttach := range specNetworks { 237 if nAttach.Target == eAttach.NetworkID { 238 log.L.WithFields(log.Fields{"service_id": s.ID, "vip": eAttach.Addr}).Debug("allocate vip") 239 if err = na.allocateVIP(eAttach); err != nil { 240 return err 241 } 242 eVIPs = append(eVIPs, eAttach) 243 continue vipLoop 244 } 245 } 246 // If the network of the VIP is not part of the service spec, 247 // deallocate the vip 248 na.deallocateVIP(eAttach) 249 } 250 251 networkLoop: 252 for _, nAttach := range specNetworks { 253 for _, vip := range s.Endpoint.VirtualIPs { 254 if vip.NetworkID == nAttach.Target { 255 continue networkLoop 256 } 257 } 258 259 vip := &api.Endpoint_VirtualIP{NetworkID: nAttach.Target} 260 if err = na.allocateVIP(vip); err != nil { 261 return err 262 } 263 264 eVIPs = append(eVIPs, vip) 265 } 266 267 if len(eVIPs) > 0 { 268 na.services[s.ID] = struct{}{} 269 } else { 270 delete(na.services, s.ID) 271 } 272 273 s.Endpoint.VirtualIPs = eVIPs 274 return nil 275 } 276 277 // DeallocateService de-allocates all the network resources such as 278 // virtual IP associated with the service. 279 func (na *cnmNetworkAllocator) DeallocateService(s *api.Service) error { 280 if s.Endpoint == nil { 281 return nil 282 } 283 284 for _, vip := range s.Endpoint.VirtualIPs { 285 if err := na.deallocateVIP(vip); err != nil { 286 // don't bail here, deallocate as many as possible. 287 log.L.WithError(err). 288 WithField("vip.network", vip.NetworkID). 289 WithField("vip.addr", vip.Addr).Error("error deallocating vip") 290 } 291 } 292 s.Endpoint.VirtualIPs = nil 293 294 delete(na.services, s.ID) 295 296 return nil 297 } 298 299 // IsAllocated returns if the passed network has been allocated or not. 300 func (na *cnmNetworkAllocator) IsAllocated(n *api.Network) bool { 301 _, ok := na.networks[n.ID] 302 return ok 303 } 304 305 // IsTaskAllocated returns if the passed task has its network resources allocated or not. 306 func (na *cnmNetworkAllocator) IsTaskAllocated(t *api.Task) bool { 307 // If the task is not found in the allocated set, then it is 308 // not allocated. 309 if _, ok := na.tasks[t.ID]; !ok { 310 return false 311 } 312 313 // If Networks is empty there is no way this Task is allocated. 314 if len(t.Networks) == 0 { 315 return false 316 } 317 318 // To determine whether the task has its resources allocated, 319 // we just need to look at one global scope network (in case of 320 // multi-network attachment). This is because we make sure we 321 // allocate for every network or we allocate for none. 322 323 // Find the first global scope network 324 for _, nAttach := range t.Networks { 325 // If the network is not allocated, the task cannot be allocated. 326 localNet, ok := na.networks[nAttach.Network.ID] 327 if !ok { 328 return false 329 } 330 331 // Nothing else to check for local scope network 332 if localNet.isNodeLocal { 333 continue 334 } 335 336 // Addresses empty. Task is not allocated. 337 if len(nAttach.Addresses) == 0 { 338 return false 339 } 340 341 // The allocated IP address not found in local endpoint state. Not allocated. 342 if _, ok := localNet.endpoints[nAttach.Addresses[0]]; !ok { 343 return false 344 } 345 } 346 347 return true 348 } 349 350 // IsServiceAllocated returns false if the passed service needs to have network resources allocated/updated. 351 func (na *cnmNetworkAllocator) IsServiceAllocated(s *api.Service, flags ...func(*networkallocator.ServiceAllocationOpts)) bool { 352 specNetworks := serviceNetworks(s) 353 354 // If endpoint mode is VIP and allocator does not have the 355 // service in VIP allocated set then it needs to be allocated. 356 if len(specNetworks) != 0 && 357 (s.Spec.Endpoint == nil || 358 s.Spec.Endpoint.Mode == api.ResolutionModeVirtualIP) { 359 360 if _, ok := na.services[s.ID]; !ok { 361 return false 362 } 363 364 if s.Endpoint == nil || len(s.Endpoint.VirtualIPs) == 0 { 365 return false 366 } 367 368 // If the spec has networks which don't have a corresponding VIP, 369 // the service needs to be allocated. 370 networkLoop: 371 for _, net := range specNetworks { 372 for _, vip := range s.Endpoint.VirtualIPs { 373 if vip.NetworkID == net.Target { 374 continue networkLoop 375 } 376 } 377 return false 378 } 379 } 380 381 // If the spec no longer has networks attached and has a vip allocated 382 // from previous spec the service needs to allocated. 383 if s.Endpoint != nil { 384 vipLoop: 385 for _, vip := range s.Endpoint.VirtualIPs { 386 if na.IsVIPOnIngressNetwork(vip) && networkallocator.IsIngressNetworkNeeded(s) { 387 // This checks the condition when ingress network is needed 388 // but allocation has not been done. 389 if _, ok := na.services[s.ID]; !ok { 390 return false 391 } 392 continue vipLoop 393 } 394 for _, net := range specNetworks { 395 if vip.NetworkID == net.Target { 396 continue vipLoop 397 } 398 } 399 return false 400 } 401 } 402 403 // If the endpoint mode is DNSRR and allocator has the service 404 // in VIP allocated set then we return to be allocated to make 405 // sure the allocator triggers networkallocator to free up the 406 // resources if any. 407 if s.Spec.Endpoint != nil && s.Spec.Endpoint.Mode == api.ResolutionModeDNSRoundRobin { 408 if _, ok := na.services[s.ID]; ok { 409 return false 410 } 411 } 412 413 return true 414 } 415 416 // AllocateTask allocates all the endpoint resources for all the 417 // networks that a task is attached to. 418 func (na *cnmNetworkAllocator) AllocateTask(t *api.Task) error { 419 for i, nAttach := range t.Networks { 420 if localNet := na.getNetwork(nAttach.Network.ID); localNet != nil && localNet.isNodeLocal { 421 continue 422 } 423 if err := na.allocateNetworkIPs(nAttach); err != nil { 424 if err := na.releaseEndpoints(t.Networks[:i]); err != nil { 425 log.G(context.TODO()).WithError(err).Errorf("failed to release IP addresses while rolling back allocation for task %s network %s", t.ID, nAttach.Network.ID) 426 } 427 return errors.Wrapf(err, "failed to allocate network IP for task %s network %s", t.ID, nAttach.Network.ID) 428 } 429 } 430 431 na.tasks[t.ID] = struct{}{} 432 433 return nil 434 } 435 436 // DeallocateTask releases all the endpoint resources for all the 437 // networks that a task is attached to. 438 func (na *cnmNetworkAllocator) DeallocateTask(t *api.Task) error { 439 delete(na.tasks, t.ID) 440 return na.releaseEndpoints(t.Networks) 441 } 442 443 // IsAttachmentAllocated returns if the passed node and network has resources allocated or not. 444 func (na *cnmNetworkAllocator) IsAttachmentAllocated(node *api.Node, networkAttachment *api.NetworkAttachment) bool { 445 if node == nil { 446 return false 447 } 448 449 if networkAttachment == nil || networkAttachment.Network == nil { 450 return false 451 } 452 453 // If the node is not found in the allocated set, then it is 454 // not allocated. 455 if _, ok := na.nodes[node.ID]; !ok { 456 return false 457 } 458 459 // If the network is not found in the allocated set, then it is 460 // not allocated. 461 if _, ok := na.nodes[node.ID][networkAttachment.Network.ID]; !ok { 462 return false 463 } 464 465 // If the network is not allocated, the node cannot be allocated. 466 localNet, ok := na.networks[networkAttachment.Network.ID] 467 if !ok { 468 return false 469 } 470 471 // Addresses empty, not allocated. 472 if len(networkAttachment.Addresses) == 0 { 473 return false 474 } 475 476 // The allocated IP address not found in local endpoint state. Not allocated. 477 if _, ok := localNet.endpoints[networkAttachment.Addresses[0]]; !ok { 478 return false 479 } 480 481 return true 482 } 483 484 // AllocateAttachment allocates the IP addresses for a LB in a network 485 // on a given node 486 func (na *cnmNetworkAllocator) AllocateAttachment(node *api.Node, networkAttachment *api.NetworkAttachment) error { 487 488 if err := na.allocateNetworkIPs(networkAttachment); err != nil { 489 return err 490 } 491 492 if na.nodes[node.ID] == nil { 493 na.nodes[node.ID] = make(map[string]struct{}) 494 } 495 na.nodes[node.ID][networkAttachment.Network.ID] = struct{}{} 496 497 return nil 498 } 499 500 // DeallocateAttachment deallocates the IP addresses for a LB in a network to 501 // which the node is attached. 502 func (na *cnmNetworkAllocator) DeallocateAttachment(node *api.Node, networkAttachment *api.NetworkAttachment) error { 503 504 delete(na.nodes[node.ID], networkAttachment.Network.ID) 505 if len(na.nodes[node.ID]) == 0 { 506 delete(na.nodes, node.ID) 507 } 508 509 return na.releaseEndpoints([]*api.NetworkAttachment{networkAttachment}) 510 } 511 512 func (na *cnmNetworkAllocator) releaseEndpoints(networks []*api.NetworkAttachment) error { 513 for _, nAttach := range networks { 514 localNet := na.getNetwork(nAttach.Network.ID) 515 if localNet == nil { 516 return fmt.Errorf("could not find network allocator state for network %s", nAttach.Network.ID) 517 } 518 519 if localNet.isNodeLocal { 520 continue 521 } 522 523 ipam, _, _, err := na.resolveIPAM(nAttach.Network) 524 if err != nil { 525 return errors.Wrap(err, "failed to resolve IPAM while releasing") 526 } 527 528 // Do not fail and bail out if we fail to release IP 529 // address here. Keep going and try releasing as many 530 // addresses as possible. 531 for _, addr := range nAttach.Addresses { 532 // Retrieve the poolID and immediately nuke 533 // out the mapping. 534 poolID := localNet.endpoints[addr] 535 delete(localNet.endpoints, addr) 536 537 ip, _, err := net.ParseCIDR(addr) 538 if err != nil { 539 log.G(context.TODO()).Errorf("Could not parse IP address %s while releasing", addr) 540 continue 541 } 542 543 if err := ipam.ReleaseAddress(poolID, ip); err != nil { 544 log.G(context.TODO()).WithError(err).Errorf("IPAM failure while releasing IP address %s", addr) 545 } 546 } 547 548 // Clear out the address list when we are done with 549 // this network. 550 nAttach.Addresses = nil 551 } 552 553 return nil 554 } 555 556 // allocate virtual IP for a single endpoint attachment of the service. 557 func (na *cnmNetworkAllocator) allocateVIP(vip *api.Endpoint_VirtualIP) error { 558 var opts map[string]string 559 localNet := na.getNetwork(vip.NetworkID) 560 if localNet == nil { 561 return errors.New("networkallocator: could not find local network state") 562 } 563 564 if localNet.isNodeLocal { 565 return nil 566 } 567 568 // If this IP is already allocated in memory we don't need to 569 // do anything. 570 if _, ok := localNet.endpoints[vip.Addr]; ok { 571 return nil 572 } 573 574 ipam, _, _, err := na.resolveIPAM(localNet.nw) 575 if err != nil { 576 return errors.Wrap(err, "failed to resolve IPAM while allocating") 577 } 578 579 var addr net.IP 580 if vip.Addr != "" { 581 var err error 582 583 addr, _, err = net.ParseCIDR(vip.Addr) 584 if err != nil { 585 return err 586 } 587 } 588 if localNet.nw.IPAM != nil && localNet.nw.IPAM.Driver != nil { 589 // set ipam allocation method to serial 590 opts = setIPAMSerialAlloc(localNet.nw.IPAM.Driver.Options) 591 } 592 593 for _, poolID := range localNet.pools { 594 ip, _, err := ipam.RequestAddress(poolID, addr, opts) 595 if err != nil && err != ipamapi.ErrNoAvailableIPs && err != ipamapi.ErrIPOutOfRange { 596 return errors.Wrap(err, "could not allocate VIP from IPAM") 597 } 598 599 // If we got an address then we are done. 600 if err == nil { 601 ipStr := ip.String() 602 localNet.endpoints[ipStr] = poolID 603 vip.Addr = ipStr 604 return nil 605 } 606 } 607 608 return errors.New("could not find an available IP while allocating VIP") 609 } 610 611 func (na *cnmNetworkAllocator) deallocateVIP(vip *api.Endpoint_VirtualIP) error { 612 localNet := na.getNetwork(vip.NetworkID) 613 if localNet == nil { 614 return errors.New("networkallocator: could not find local network state") 615 } 616 if localNet.isNodeLocal { 617 return nil 618 } 619 ipam, _, _, err := na.resolveIPAM(localNet.nw) 620 if err != nil { 621 return errors.Wrap(err, "failed to resolve IPAM while allocating") 622 } 623 624 // Retrieve the poolID and immediately nuke 625 // out the mapping. 626 poolID := localNet.endpoints[vip.Addr] 627 delete(localNet.endpoints, vip.Addr) 628 629 ip, _, err := net.ParseCIDR(vip.Addr) 630 if err != nil { 631 log.G(context.TODO()).Errorf("Could not parse VIP address %s while releasing", vip.Addr) 632 return err 633 } 634 635 if err := ipam.ReleaseAddress(poolID, ip); err != nil { 636 log.G(context.TODO()).WithError(err).Errorf("IPAM failure while releasing VIP address %s", vip.Addr) 637 return err 638 } 639 640 return nil 641 } 642 643 // allocate the IP addresses for a single network attachment of the task. 644 func (na *cnmNetworkAllocator) allocateNetworkIPs(nAttach *api.NetworkAttachment) error { 645 var ip *net.IPNet 646 var opts map[string]string 647 648 ipam, _, _, err := na.resolveIPAM(nAttach.Network) 649 if err != nil { 650 return errors.Wrap(err, "failed to resolve IPAM while allocating") 651 } 652 653 localNet := na.getNetwork(nAttach.Network.ID) 654 if localNet == nil { 655 return fmt.Errorf("could not find network allocator state for network %s", nAttach.Network.ID) 656 } 657 658 addresses := nAttach.Addresses 659 if len(addresses) == 0 { 660 addresses = []string{""} 661 } 662 663 for i, rawAddr := range addresses { 664 var addr net.IP 665 if rawAddr != "" { 666 var err error 667 addr, _, err = net.ParseCIDR(rawAddr) 668 if err != nil { 669 addr = net.ParseIP(rawAddr) 670 671 if addr == nil { 672 return errors.Wrapf(err, "could not parse address string %s", rawAddr) 673 } 674 } 675 } 676 // Set the ipam options if the network has an ipam driver. 677 if localNet.nw.IPAM != nil && localNet.nw.IPAM.Driver != nil { 678 // set ipam allocation method to serial 679 opts = setIPAMSerialAlloc(localNet.nw.IPAM.Driver.Options) 680 } 681 682 for _, poolID := range localNet.pools { 683 var err error 684 685 ip, _, err = ipam.RequestAddress(poolID, addr, opts) 686 if err != nil && err != ipamapi.ErrNoAvailableIPs && err != ipamapi.ErrIPOutOfRange { 687 return errors.Wrap(err, "could not allocate IP from IPAM") 688 } 689 690 // If we got an address then we are done. 691 if err == nil { 692 ipStr := ip.String() 693 localNet.endpoints[ipStr] = poolID 694 addresses[i] = ipStr 695 nAttach.Addresses = addresses 696 return nil 697 } 698 } 699 } 700 701 return errors.New("could not find an available IP") 702 } 703 704 func (na *cnmNetworkAllocator) freeDriverState(n *api.Network) error { 705 d, err := na.resolveDriver(n) 706 if err != nil { 707 return err 708 } 709 710 return d.driver.NetworkFree(n.ID) 711 } 712 713 func (na *cnmNetworkAllocator) allocateDriverState(n *api.Network) error { 714 d, err := na.resolveDriver(n) 715 if err != nil { 716 return err 717 } 718 719 options := make(map[string]string) 720 // reconcile the driver specific options from the network spec 721 // and from the operational state retrieved from the store 722 if n.Spec.DriverConfig != nil { 723 for k, v := range n.Spec.DriverConfig.Options { 724 options[k] = v 725 } 726 } 727 if n.DriverState != nil { 728 for k, v := range n.DriverState.Options { 729 options[k] = v 730 } 731 } 732 733 // Construct IPAM data for driver consumption. 734 ipv4Data := make([]driverapi.IPAMData, 0, len(n.IPAM.Configs)) 735 for _, ic := range n.IPAM.Configs { 736 if ic.Family == api.IPAMConfig_IPV6 { 737 continue 738 } 739 740 _, subnet, err := net.ParseCIDR(ic.Subnet) 741 if err != nil { 742 return errors.Wrapf(err, "error parsing subnet %s while allocating driver state", ic.Subnet) 743 } 744 745 gwIP := net.ParseIP(ic.Gateway) 746 gwNet := &net.IPNet{ 747 IP: gwIP, 748 Mask: subnet.Mask, 749 } 750 751 data := driverapi.IPAMData{ 752 Pool: subnet, 753 Gateway: gwNet, 754 } 755 756 ipv4Data = append(ipv4Data, data) 757 } 758 759 ds, err := d.driver.NetworkAllocate(n.ID, options, ipv4Data, nil) 760 if err != nil { 761 return err 762 } 763 764 // Update network object with the obtained driver state. 765 n.DriverState = &api.Driver{ 766 Name: d.name, 767 Options: ds, 768 } 769 770 return nil 771 } 772 773 // Resolve network driver 774 func (na *cnmNetworkAllocator) resolveDriver(n *api.Network) (*networkDriver, error) { 775 dName := DefaultDriver 776 if n.Spec.DriverConfig != nil && n.Spec.DriverConfig.Name != "" { 777 dName = n.Spec.DriverConfig.Name 778 } 779 780 d, drvcap := na.networkRegistry.Driver(dName) 781 if d == nil { 782 err := na.loadDriver(dName) 783 if err != nil { 784 return nil, err 785 } 786 787 d, drvcap = na.networkRegistry.Driver(dName) 788 if d == nil { 789 return nil, fmt.Errorf("could not resolve network driver %s", dName) 790 } 791 } 792 793 return &networkDriver{driver: d, capability: &drvcap, name: dName}, nil 794 } 795 796 func (na *cnmNetworkAllocator) loadDriver(name string) error { 797 if na.pg == nil { 798 return errors.New("plugin store is uninitialized") 799 } 800 _, err := na.pg.Get(name, driverapi.NetworkPluginEndpointType, plugingetter.Lookup) 801 return err 802 } 803 804 // Resolve the IPAM driver 805 func (na *cnmNetworkAllocator) resolveIPAM(n *api.Network) (ipamapi.Ipam, string, map[string]string, error) { 806 dName := ipamapi.DefaultIPAM 807 if n.Spec.IPAM != nil && n.Spec.IPAM.Driver != nil && n.Spec.IPAM.Driver.Name != "" { 808 dName = n.Spec.IPAM.Driver.Name 809 } 810 811 var dOptions map[string]string 812 if n.Spec.IPAM != nil && n.Spec.IPAM.Driver != nil && len(n.Spec.IPAM.Driver.Options) != 0 { 813 dOptions = n.Spec.IPAM.Driver.Options 814 } 815 816 ipam, _ := na.ipamRegistry.IPAM(dName) 817 if ipam == nil { 818 return nil, "", nil, fmt.Errorf("could not resolve IPAM driver %s", dName) 819 } 820 821 return ipam, dName, dOptions, nil 822 } 823 824 func (na *cnmNetworkAllocator) freePools(n *api.Network, pools map[string]string) error { 825 ipam, _, _, err := na.resolveIPAM(n) 826 if err != nil { 827 return errors.Wrapf(err, "failed to resolve IPAM while freeing pools for network %s", n.ID) 828 } 829 830 releasePools(ipam, n.IPAM.Configs, pools) 831 return nil 832 } 833 834 func releasePools(ipam ipamapi.Ipam, icList []*api.IPAMConfig, pools map[string]string) { 835 for _, ic := range icList { 836 if err := ipam.ReleaseAddress(pools[ic.Subnet], net.ParseIP(ic.Gateway)); err != nil { 837 log.G(context.TODO()).WithError(err).Errorf("Failed to release address %s", ic.Subnet) 838 } 839 } 840 841 for k, p := range pools { 842 if err := ipam.ReleasePool(p); err != nil { 843 log.G(context.TODO()).WithError(err).Errorf("Failed to release pool %s", k) 844 } 845 } 846 } 847 848 func (na *cnmNetworkAllocator) allocatePools(n *api.Network) (map[string]string, error) { 849 ipam, dName, dOptions, err := na.resolveIPAM(n) 850 if err != nil { 851 return nil, err 852 } 853 854 // We don't support user defined address spaces yet so just 855 // retrieve default address space names for the driver. 856 _, asName, err := ipam.GetDefaultAddressSpaces() 857 if err != nil { 858 return nil, err 859 } 860 861 pools := make(map[string]string) 862 863 var ipamConfigs []*api.IPAMConfig 864 865 // If there is non-nil IPAM state always prefer those subnet 866 // configs over Spec configs. 867 if n.IPAM != nil { 868 ipamConfigs = n.IPAM.Configs 869 } else if n.Spec.IPAM != nil { 870 ipamConfigs = make([]*api.IPAMConfig, len(n.Spec.IPAM.Configs)) 871 copy(ipamConfigs, n.Spec.IPAM.Configs) 872 } 873 874 // Append an empty slot for subnet allocation if there are no 875 // IPAM configs from either spec or state. 876 if len(ipamConfigs) == 0 { 877 ipamConfigs = append(ipamConfigs, &api.IPAMConfig{Family: api.IPAMConfig_IPV4}) 878 } 879 880 // Update the runtime IPAM configurations with initial state 881 n.IPAM = &api.IPAMOptions{ 882 Driver: &api.Driver{Name: dName, Options: dOptions}, 883 Configs: ipamConfigs, 884 } 885 886 for i, ic := range ipamConfigs { 887 poolID, poolIP, meta, err := ipam.RequestPool(asName, ic.Subnet, ic.Range, dOptions, false) 888 if err != nil { 889 // Rollback by releasing all the resources allocated so far. 890 releasePools(ipam, ipamConfigs[:i], pools) 891 return nil, err 892 } 893 pools[poolIP.String()] = poolID 894 895 // The IPAM contract allows the IPAM driver to autonomously 896 // provide a network gateway in response to the pool request. 897 // But if the network spec contains a gateway, we will allocate 898 // it irrespective of whether the ipam driver returned one already. 899 // If none of the above is true, we need to allocate one now, and 900 // let the driver know this request is for the network gateway. 901 var ( 902 gwIP *net.IPNet 903 ip net.IP 904 ) 905 if gws, ok := meta[netlabel.Gateway]; ok { 906 if ip, gwIP, err = net.ParseCIDR(gws); err != nil { 907 return nil, fmt.Errorf("failed to parse gateway address (%v) returned by ipam driver: %v", gws, err) 908 } 909 gwIP.IP = ip 910 } 911 if dOptions == nil { 912 dOptions = make(map[string]string) 913 } 914 dOptions[ipamapi.RequestAddressType] = netlabel.Gateway 915 // set ipam allocation method to serial 916 dOptions = setIPAMSerialAlloc(dOptions) 917 defer delete(dOptions, ipamapi.RequestAddressType) 918 919 if ic.Gateway != "" || gwIP == nil { 920 gwIP, _, err = ipam.RequestAddress(poolID, net.ParseIP(ic.Gateway), dOptions) 921 if err != nil { 922 // Rollback by releasing all the resources allocated so far. 923 releasePools(ipam, ipamConfigs[:i], pools) 924 return nil, err 925 } 926 } 927 928 if ic.Subnet == "" { 929 ic.Subnet = poolIP.String() 930 } 931 932 if ic.Gateway == "" { 933 ic.Gateway = gwIP.IP.String() 934 } 935 936 } 937 938 return pools, nil 939 } 940 941 func serviceNetworks(s *api.Service) []*api.NetworkAttachmentConfig { 942 // Always prefer NetworkAttachmentConfig in the TaskSpec 943 if len(s.Spec.Task.Networks) == 0 && len(s.Spec.Networks) != 0 { 944 return s.Spec.Networks 945 } 946 return s.Spec.Task.Networks 947 } 948 949 // IsVIPOnIngressNetwork check if the vip is in ingress network 950 func (na *cnmNetworkAllocator) IsVIPOnIngressNetwork(vip *api.Endpoint_VirtualIP) bool { 951 if vip == nil { 952 return false 953 } 954 955 localNet := na.getNetwork(vip.NetworkID) 956 if localNet != nil && localNet.nw != nil { 957 return networkallocator.IsIngressNetwork(localNet.nw) 958 } 959 return false 960 } 961 962 // IsBuiltInDriver returns whether the passed driver is an internal network driver 963 func IsBuiltInDriver(name string) bool { 964 n := strings.ToLower(name) 965 _, ok := initializers[n] 966 return ok 967 } 968 969 // setIPAMSerialAlloc sets the ipam allocation method to serial 970 func setIPAMSerialAlloc(opts map[string]string) map[string]string { 971 if opts == nil { 972 opts = make(map[string]string) 973 } 974 if _, ok := opts[ipamapi.AllocSerialPrefix]; !ok { 975 opts[ipamapi.AllocSerialPrefix] = "true" 976 } 977 return opts 978 }