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