8 "github.com/docker/docker/pkg/plugingetter"
9 "github.com/docker/libnetwork/datastore"
10 "github.com/docker/libnetwork/driverapi"
11 "github.com/docker/libnetwork/drvregistry"
12 "github.com/docker/libnetwork/ipamapi"
13 "github.com/docker/libnetwork/netlabel"
14 "github.com/docker/swarmkit/api"
15 "github.com/docker/swarmkit/log"
16 "github.com/docker/swarmkit/manager/allocator/networkallocator"
17 "github.com/pkg/errors"
18 "golang.org/x/net/context"
22 // DefaultDriver defines the name of the driver to be used by
23 // default if a network without any driver name specified is
25 DefaultDriver = "overlay"
28 // cnmNetworkAllocator acts as the controller for all network related operations
29 // like managing network and IPAM drivers and also creating and
30 // deleting networks and the associated resources.
31 type cnmNetworkAllocator struct {
32 // The driver register which manages all internal and external
33 // IPAM and network drivers.
34 drvRegistry *drvregistry.DrvRegistry
36 // The port allocator instance for allocating node ports
37 portAllocator *portAllocator
39 // Local network state used by cnmNetworkAllocator to do network management.
40 networks map[string]*network
42 // Allocator state to indicate if allocation has been
43 // successfully completed for this service.
44 services map[string]struct{}
46 // Allocator state to indicate if allocation has been
47 // successfully completed for this task.
48 tasks map[string]struct{}
50 // Allocator state to indicate if allocation has been
51 // successfully completed for this node.
52 nodes map[string]struct{}
55 // Local in-memory state related to network that need to be tracked by cnmNetworkAllocator
57 // A local cache of the store object.
60 // pools is used to save the internal poolIDs needed when
61 // releasing the pool.
62 pools map[string]string
64 // endpoints is a map of endpoint IP to the poolID from which it
66 endpoints map[string]string
68 // isNodeLocal indicates whether the scope of the network's resources
69 // is local to the node. If true, it means the resources can only be
70 // allocated locally by the node where the network will be deployed.
71 // In this the swarm manager will skip the allocations.
75 type networkDriver struct {
76 driver driverapi.Driver
78 capability *driverapi.Capability
81 type initializer struct {
82 fn drvregistry.InitFunc
86 // New returns a new NetworkAllocator handle
87 func New(pg plugingetter.PluginGetter) (networkallocator.NetworkAllocator, error) {
88 na := &cnmNetworkAllocator{
89 networks: make(map[string]*network),
90 services: make(map[string]struct{}),
91 tasks: make(map[string]struct{}),
92 nodes: make(map[string]struct{}),
95 // There are no driver configurations and notification
96 // functions as of now.
97 reg, err := drvregistry.New(nil, nil, nil, nil, pg)
102 if err := initializeDrivers(reg); err != nil {
106 if err = initIPAMDrivers(reg); err != nil {
110 pa, err := newPortAllocator()
115 na.portAllocator = pa
120 // Allocate allocates all the necessary resources both general
121 // and driver-specific which may be specified in the NetworkSpec
122 func (na *cnmNetworkAllocator) Allocate(n *api.Network) error {
123 if _, ok := na.networks[n.ID]; ok {
124 return fmt.Errorf("network %s already allocated", n.ID)
127 d, err := na.resolveDriver(n)
134 endpoints: make(map[string]string),
135 isNodeLocal: d.capability.DataScope == datastore.LocalScope,
138 // No swarm-level allocation can be provided by the network driver for
139 // node-local networks. Only thing needed is populating the driver's name
140 // in the driver's state.
142 n.DriverState = &api.Driver{
145 // In order to support backward compatibility with older daemon
146 // versions which assumes the network attachment to contains
147 // non nil IPAM attribute, passing an empty object
148 n.IPAM = &api.IPAMOptions{Driver: &api.Driver{}}
150 nw.pools, err = na.allocatePools(n)
152 return errors.Wrapf(err, "failed allocating pools and gateway IP for network %s", n.ID)
155 if err := na.allocateDriverState(n); err != nil {
156 na.freePools(n, nw.pools)
157 return errors.Wrapf(err, "failed while allocating driver state for network %s", n.ID)
161 na.networks[n.ID] = nw
166 func (na *cnmNetworkAllocator) getNetwork(id string) *network {
167 return na.networks[id]
170 // Deallocate frees all the general and driver specific resources
171 // which were assigned to the passed network.
172 func (na *cnmNetworkAllocator) Deallocate(n *api.Network) error {
173 localNet := na.getNetwork(n.ID)
175 return fmt.Errorf("could not get networker state for network %s", n.ID)
178 // No swarm-level resource deallocation needed for node-local networks
179 if localNet.isNodeLocal {
180 delete(na.networks, n.ID)
184 if err := na.freeDriverState(n); err != nil {
185 return errors.Wrapf(err, "failed to free driver state for network %s", n.ID)
188 delete(na.networks, n.ID)
190 return na.freePools(n, localNet.pools)
193 // AllocateService allocates all the network resources such as virtual
194 // IP and ports needed by the service.
195 func (na *cnmNetworkAllocator) AllocateService(s *api.Service) (err error) {
196 if err = na.portAllocator.serviceAllocatePorts(s); err != nil {
201 na.DeallocateService(s)
205 if s.Endpoint == nil {
206 s.Endpoint = &api.Endpoint{}
208 s.Endpoint.Spec = s.Spec.Endpoint.Copy()
210 // If ResolutionMode is DNSRR do not try allocating VIPs, but
211 // free any VIP from previous state.
212 if s.Spec.Endpoint != nil && s.Spec.Endpoint.Mode == api.ResolutionModeDNSRoundRobin {
213 for _, vip := range s.Endpoint.VirtualIPs {
214 if err := na.deallocateVIP(vip); err != nil {
215 // don't bail here, deallocate as many as possible.
216 log.L.WithError(err).
217 WithField("vip.network", vip.NetworkID).
218 WithField("vip.addr", vip.Addr).Error("error deallocating vip")
222 s.Endpoint.VirtualIPs = nil
224 delete(na.services, s.ID)
228 specNetworks := serviceNetworks(s)
230 // Allocate VIPs for all the pre-populated endpoint attachments
231 eVIPs := s.Endpoint.VirtualIPs[:0]
234 for _, eAttach := range s.Endpoint.VirtualIPs {
235 if na.IsVIPOnIngressNetwork(eAttach) && networkallocator.IsIngressNetworkNeeded(s) {
236 if err = na.allocateVIP(eAttach); err != nil {
239 eVIPs = append(eVIPs, eAttach)
243 for _, nAttach := range specNetworks {
244 if nAttach.Target == eAttach.NetworkID {
245 if err = na.allocateVIP(eAttach); err != nil {
248 eVIPs = append(eVIPs, eAttach)
252 // If the network of the VIP is not part of the service spec,
253 // deallocate the vip
254 na.deallocateVIP(eAttach)
258 for _, nAttach := range specNetworks {
259 for _, vip := range s.Endpoint.VirtualIPs {
260 if vip.NetworkID == nAttach.Target {
265 vip := &api.Endpoint_VirtualIP{NetworkID: nAttach.Target}
266 if err = na.allocateVIP(vip); err != nil {
270 eVIPs = append(eVIPs, vip)
274 na.services[s.ID] = struct{}{}
276 delete(na.services, s.ID)
279 s.Endpoint.VirtualIPs = eVIPs
283 // DeallocateService de-allocates all the network resources such as
284 // virtual IP and ports associated with the service.
285 func (na *cnmNetworkAllocator) DeallocateService(s *api.Service) error {
286 if s.Endpoint == nil {
290 for _, vip := range s.Endpoint.VirtualIPs {
291 if err := na.deallocateVIP(vip); err != nil {
292 // don't bail here, deallocate as many as possible.
293 log.L.WithError(err).
294 WithField("vip.network", vip.NetworkID).
295 WithField("vip.addr", vip.Addr).Error("error deallocating vip")
298 s.Endpoint.VirtualIPs = nil
300 na.portAllocator.serviceDeallocatePorts(s)
301 delete(na.services, s.ID)
306 // IsAllocated returns if the passed network has been allocated or not.
307 func (na *cnmNetworkAllocator) IsAllocated(n *api.Network) bool {
308 _, ok := na.networks[n.ID]
312 // IsTaskAllocated returns if the passed task has its network resources allocated or not.
313 func (na *cnmNetworkAllocator) IsTaskAllocated(t *api.Task) bool {
314 // If the task is not found in the allocated set, then it is
316 if _, ok := na.tasks[t.ID]; !ok {
320 // If Networks is empty there is no way this Task is allocated.
321 if len(t.Networks) == 0 {
325 // To determine whether the task has its resources allocated,
326 // we just need to look at one global scope network (in case of
327 // multi-network attachment). This is because we make sure we
328 // allocate for every network or we allocate for none.
330 // Find the first global scope network
331 for _, nAttach := range t.Networks {
332 // If the network is not allocated, the task cannot be allocated.
333 localNet, ok := na.networks[nAttach.Network.ID]
338 // Nothing else to check for local scope network
339 if localNet.isNodeLocal {
343 // Addresses empty. Task is not allocated.
344 if len(nAttach.Addresses) == 0 {
348 // The allocated IP address not found in local endpoint state. Not allocated.
349 if _, ok := localNet.endpoints[nAttach.Addresses[0]]; !ok {
357 // HostPublishPortsNeedUpdate returns true if the passed service needs
358 // allocations for its published ports in host (non ingress) mode
359 func (na *cnmNetworkAllocator) HostPublishPortsNeedUpdate(s *api.Service) bool {
360 return na.portAllocator.hostPublishPortsNeedUpdate(s)
363 // IsServiceAllocated returns false if the passed service needs to have network resources allocated/updated.
364 func (na *cnmNetworkAllocator) IsServiceAllocated(s *api.Service, flags ...func(*networkallocator.ServiceAllocationOpts)) bool {
365 var options networkallocator.ServiceAllocationOpts
366 for _, flag := range flags {
370 specNetworks := serviceNetworks(s)
372 // If endpoint mode is VIP and allocator does not have the
373 // service in VIP allocated set then it needs to be allocated.
374 if len(specNetworks) != 0 &&
375 (s.Spec.Endpoint == nil ||
376 s.Spec.Endpoint.Mode == api.ResolutionModeVirtualIP) {
378 if _, ok := na.services[s.ID]; !ok {
382 if s.Endpoint == nil || len(s.Endpoint.VirtualIPs) == 0 {
386 // If the spec has networks which don't have a corresponding VIP,
387 // the service needs to be allocated.
389 for _, net := range specNetworks {
390 for _, vip := range s.Endpoint.VirtualIPs {
391 if vip.NetworkID == net.Target {
399 // If the spec no longer has networks attached and has a vip allocated
400 // from previous spec the service needs to allocated.
401 if s.Endpoint != nil {
403 for _, vip := range s.Endpoint.VirtualIPs {
404 if na.IsVIPOnIngressNetwork(vip) && networkallocator.IsIngressNetworkNeeded(s) {
407 for _, net := range specNetworks {
408 if vip.NetworkID == net.Target {
416 // If the endpoint mode is DNSRR and allocator has the service
417 // in VIP allocated set then we return to be allocated to make
418 // sure the allocator triggers networkallocator to free up the
420 if s.Spec.Endpoint != nil && s.Spec.Endpoint.Mode == api.ResolutionModeDNSRoundRobin {
421 if _, ok := na.services[s.ID]; ok {
426 if (s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0) ||
427 (s.Endpoint != nil && len(s.Endpoint.Ports) != 0) {
428 return na.portAllocator.isPortsAllocatedOnInit(s, options.OnInit)
433 // IsNodeAllocated returns if the passed node has its network resources allocated or not.
434 func (na *cnmNetworkAllocator) IsNodeAllocated(node *api.Node) bool {
435 // If the node is not found in the allocated set, then it is
437 if _, ok := na.nodes[node.ID]; !ok {
441 // If no attachment, not allocated.
442 if node.Attachment == nil {
446 // If the network is not allocated, the node cannot be allocated.
447 localNet, ok := na.networks[node.Attachment.Network.ID]
452 // Addresses empty, not allocated.
453 if len(node.Attachment.Addresses) == 0 {
457 // The allocated IP address not found in local endpoint state. Not allocated.
458 if _, ok := localNet.endpoints[node.Attachment.Addresses[0]]; !ok {
465 // AllocateNode allocates the IP addresses for the network to which
466 // the node is attached.
467 func (na *cnmNetworkAllocator) AllocateNode(node *api.Node) error {
468 if err := na.allocateNetworkIPs(node.Attachment); err != nil {
472 na.nodes[node.ID] = struct{}{}
476 // DeallocateNode deallocates the IP addresses for the network to
477 // which the node is attached.
478 func (na *cnmNetworkAllocator) DeallocateNode(node *api.Node) error {
479 delete(na.nodes, node.ID)
480 return na.releaseEndpoints([]*api.NetworkAttachment{node.Attachment})
483 // AllocateTask allocates all the endpoint resources for all the
484 // networks that a task is attached to.
485 func (na *cnmNetworkAllocator) AllocateTask(t *api.Task) error {
486 for i, nAttach := range t.Networks {
487 if localNet := na.getNetwork(nAttach.Network.ID); localNet != nil && localNet.isNodeLocal {
490 if err := na.allocateNetworkIPs(nAttach); err != nil {
491 if err := na.releaseEndpoints(t.Networks[:i]); err != nil {
492 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)
494 return errors.Wrapf(err, "failed to allocate network IP for task %s network %s", t.ID, nAttach.Network.ID)
498 na.tasks[t.ID] = struct{}{}
503 // DeallocateTask releases all the endpoint resources for all the
504 // networks that a task is attached to.
505 func (na *cnmNetworkAllocator) DeallocateTask(t *api.Task) error {
506 delete(na.tasks, t.ID)
507 return na.releaseEndpoints(t.Networks)
510 func (na *cnmNetworkAllocator) releaseEndpoints(networks []*api.NetworkAttachment) error {
511 for _, nAttach := range networks {
512 localNet := na.getNetwork(nAttach.Network.ID)
514 return fmt.Errorf("could not find network allocator state for network %s", nAttach.Network.ID)
517 if localNet.isNodeLocal {
521 ipam, _, _, err := na.resolveIPAM(nAttach.Network)
523 return errors.Wrap(err, "failed to resolve IPAM while releasing")
526 // Do not fail and bail out if we fail to release IP
527 // address here. Keep going and try releasing as many
528 // addresses as possible.
529 for _, addr := range nAttach.Addresses {
530 // Retrieve the poolID and immediately nuke
532 poolID := localNet.endpoints[addr]
533 delete(localNet.endpoints, addr)
535 ip, _, err := net.ParseCIDR(addr)
537 log.G(context.TODO()).Errorf("Could not parse IP address %s while releasing", addr)
541 if err := ipam.ReleaseAddress(poolID, ip); err != nil {
542 log.G(context.TODO()).WithError(err).Errorf("IPAM failure while releasing IP address %s", addr)
546 // Clear out the address list when we are done with
548 nAttach.Addresses = nil
554 // allocate virtual IP for a single endpoint attachment of the service.
555 func (na *cnmNetworkAllocator) allocateVIP(vip *api.Endpoint_VirtualIP) error {
556 localNet := na.getNetwork(vip.NetworkID)
558 return errors.New("networkallocator: could not find local network state")
561 if localNet.isNodeLocal {
565 // If this IP is already allocated in memory we don't need to
567 if _, ok := localNet.endpoints[vip.Addr]; ok {
571 ipam, _, _, err := na.resolveIPAM(localNet.nw)
573 return errors.Wrap(err, "failed to resolve IPAM while allocating")
580 addr, _, err = net.ParseCIDR(vip.Addr)
586 for _, poolID := range localNet.pools {
587 ip, _, err := ipam.RequestAddress(poolID, addr, nil)
588 if err != nil && err != ipamapi.ErrNoAvailableIPs && err != ipamapi.ErrIPOutOfRange {
589 return errors.Wrap(err, "could not allocate VIP from IPAM")
592 // If we got an address then we are done.
595 localNet.endpoints[ipStr] = poolID
601 return errors.New("could not find an available IP while allocating VIP")
604 func (na *cnmNetworkAllocator) deallocateVIP(vip *api.Endpoint_VirtualIP) error {
605 localNet := na.getNetwork(vip.NetworkID)
607 return errors.New("networkallocator: could not find local network state")
609 if localNet.isNodeLocal {
612 ipam, _, _, err := na.resolveIPAM(localNet.nw)
614 return errors.Wrap(err, "failed to resolve IPAM while allocating")
617 // Retrieve the poolID and immediately nuke
619 poolID := localNet.endpoints[vip.Addr]
620 delete(localNet.endpoints, vip.Addr)
622 ip, _, err := net.ParseCIDR(vip.Addr)
624 log.G(context.TODO()).Errorf("Could not parse VIP address %s while releasing", vip.Addr)
628 if err := ipam.ReleaseAddress(poolID, ip); err != nil {
629 log.G(context.TODO()).WithError(err).Errorf("IPAM failure while releasing VIP address %s", vip.Addr)
636 // allocate the IP addresses for a single network attachment of the task.
637 func (na *cnmNetworkAllocator) allocateNetworkIPs(nAttach *api.NetworkAttachment) error {
640 ipam, _, _, err := na.resolveIPAM(nAttach.Network)
642 return errors.Wrap(err, "failed to resolve IPAM while allocating")
645 localNet := na.getNetwork(nAttach.Network.ID)
647 return fmt.Errorf("could not find network allocator state for network %s", nAttach.Network.ID)
650 addresses := nAttach.Addresses
651 if len(addresses) == 0 {
652 addresses = []string{""}
655 for i, rawAddr := range addresses {
659 addr, _, err = net.ParseCIDR(rawAddr)
661 addr = net.ParseIP(rawAddr)
664 return errors.Wrapf(err, "could not parse address string %s", rawAddr)
669 for _, poolID := range localNet.pools {
672 ip, _, err = ipam.RequestAddress(poolID, addr, nil)
673 if err != nil && err != ipamapi.ErrNoAvailableIPs && err != ipamapi.ErrIPOutOfRange {
674 return errors.Wrap(err, "could not allocate IP from IPAM")
677 // If we got an address then we are done.
680 localNet.endpoints[ipStr] = poolID
682 nAttach.Addresses = addresses
688 return errors.New("could not find an available IP")
691 func (na *cnmNetworkAllocator) freeDriverState(n *api.Network) error {
692 d, err := na.resolveDriver(n)
697 return d.driver.NetworkFree(n.ID)
700 func (na *cnmNetworkAllocator) allocateDriverState(n *api.Network) error {
701 d, err := na.resolveDriver(n)
706 options := make(map[string]string)
707 // reconcile the driver specific options from the network spec
708 // and from the operational state retrieved from the store
709 if n.Spec.DriverConfig != nil {
710 for k, v := range n.Spec.DriverConfig.Options {
714 if n.DriverState != nil {
715 for k, v := range n.DriverState.Options {
720 // Construct IPAM data for driver consumption.
721 ipv4Data := make([]driverapi.IPAMData, 0, len(n.IPAM.Configs))
722 for _, ic := range n.IPAM.Configs {
723 if ic.Family == api.IPAMConfig_IPV6 {
727 _, subnet, err := net.ParseCIDR(ic.Subnet)
729 return errors.Wrapf(err, "error parsing subnet %s while allocating driver state", ic.Subnet)
732 gwIP := net.ParseIP(ic.Gateway)
738 data := driverapi.IPAMData{
743 ipv4Data = append(ipv4Data, data)
746 ds, err := d.driver.NetworkAllocate(n.ID, options, ipv4Data, nil)
751 // Update network object with the obtained driver state.
752 n.DriverState = &api.Driver{
760 // Resolve network driver
761 func (na *cnmNetworkAllocator) resolveDriver(n *api.Network) (*networkDriver, error) {
762 dName := DefaultDriver
763 if n.Spec.DriverConfig != nil && n.Spec.DriverConfig.Name != "" {
764 dName = n.Spec.DriverConfig.Name
767 d, drvcap := na.drvRegistry.Driver(dName)
770 err = na.loadDriver(dName)
775 d, drvcap = na.drvRegistry.Driver(dName)
777 return nil, fmt.Errorf("could not resolve network driver %s", dName)
781 return &networkDriver{driver: d, capability: drvcap, name: dName}, nil
784 func (na *cnmNetworkAllocator) loadDriver(name string) error {
785 pg := na.drvRegistry.GetPluginGetter()
787 return errors.New("plugin store is uninitialized")
789 _, err := pg.Get(name, driverapi.NetworkPluginEndpointType, plugingetter.Lookup)
793 // Resolve the IPAM driver
794 func (na *cnmNetworkAllocator) resolveIPAM(n *api.Network) (ipamapi.Ipam, string, map[string]string, error) {
795 dName := ipamapi.DefaultIPAM
796 if n.Spec.IPAM != nil && n.Spec.IPAM.Driver != nil && n.Spec.IPAM.Driver.Name != "" {
797 dName = n.Spec.IPAM.Driver.Name
800 var dOptions map[string]string
801 if n.Spec.IPAM != nil && n.Spec.IPAM.Driver != nil && len(n.Spec.IPAM.Driver.Options) != 0 {
802 dOptions = n.Spec.IPAM.Driver.Options
805 ipam, _ := na.drvRegistry.IPAM(dName)
807 return nil, "", nil, fmt.Errorf("could not resolve IPAM driver %s", dName)
810 return ipam, dName, dOptions, nil
813 func (na *cnmNetworkAllocator) freePools(n *api.Network, pools map[string]string) error {
814 ipam, _, _, err := na.resolveIPAM(n)
816 return errors.Wrapf(err, "failed to resolve IPAM while freeing pools for network %s", n.ID)
819 releasePools(ipam, n.IPAM.Configs, pools)
823 func releasePools(ipam ipamapi.Ipam, icList []*api.IPAMConfig, pools map[string]string) {
824 for _, ic := range icList {
825 if err := ipam.ReleaseAddress(pools[ic.Subnet], net.ParseIP(ic.Gateway)); err != nil {
826 log.G(context.TODO()).WithError(err).Errorf("Failed to release address %s", ic.Subnet)
830 for k, p := range pools {
831 if err := ipam.ReleasePool(p); err != nil {
832 log.G(context.TODO()).WithError(err).Errorf("Failed to release pool %s", k)
837 func (na *cnmNetworkAllocator) allocatePools(n *api.Network) (map[string]string, error) {
838 ipam, dName, dOptions, err := na.resolveIPAM(n)
843 // We don't support user defined address spaces yet so just
844 // retrieve default address space names for the driver.
845 _, asName, err := na.drvRegistry.IPAMDefaultAddressSpaces(dName)
850 pools := make(map[string]string)
852 var ipamConfigs []*api.IPAMConfig
854 // If there is non-nil IPAM state always prefer those subnet
855 // configs over Spec configs.
857 ipamConfigs = n.IPAM.Configs
858 } else if n.Spec.IPAM != nil {
859 ipamConfigs = make([]*api.IPAMConfig, len(n.Spec.IPAM.Configs))
860 copy(ipamConfigs, n.Spec.IPAM.Configs)
863 // Append an empty slot for subnet allocation if there are no
864 // IPAM configs from either spec or state.
865 if len(ipamConfigs) == 0 {
866 ipamConfigs = append(ipamConfigs, &api.IPAMConfig{Family: api.IPAMConfig_IPV4})
869 // Update the runtime IPAM configurations with initial state
870 n.IPAM = &api.IPAMOptions{
871 Driver: &api.Driver{Name: dName, Options: dOptions},
872 Configs: ipamConfigs,
875 for i, ic := range ipamConfigs {
876 poolID, poolIP, meta, err := ipam.RequestPool(asName, ic.Subnet, ic.Range, dOptions, false)
878 // Rollback by releasing all the resources allocated so far.
879 releasePools(ipam, ipamConfigs[:i], pools)
882 pools[poolIP.String()] = poolID
884 // The IPAM contract allows the IPAM driver to autonomously
885 // provide a network gateway in response to the pool request.
886 // But if the network spec contains a gateway, we will allocate
887 // it irrespective of whether the ipam driver returned one already.
888 // If none of the above is true, we need to allocate one now, and
889 // let the driver know this request is for the network gateway.
894 if gws, ok := meta[netlabel.Gateway]; ok {
895 if ip, gwIP, err = net.ParseCIDR(gws); err != nil {
896 return nil, fmt.Errorf("failed to parse gateway address (%v) returned by ipam driver: %v", gws, err)
900 if ic.Gateway != "" || gwIP == nil {
901 gwIP, _, err = ipam.RequestAddress(poolID, net.ParseIP(ic.Gateway), map[string]string{ipamapi.RequestAddressType: netlabel.Gateway})
903 // Rollback by releasing all the resources allocated so far.
904 releasePools(ipam, ipamConfigs[:i], pools)
910 ic.Subnet = poolIP.String()
913 if ic.Gateway == "" {
914 ic.Gateway = gwIP.IP.String()
922 func initializeDrivers(reg *drvregistry.DrvRegistry) error {
923 for _, i := range initializers {
924 if err := reg.AddDriver(i.ntype, i.fn, nil); err != nil {
931 func serviceNetworks(s *api.Service) []*api.NetworkAttachmentConfig {
932 // Always prefer NetworkAttachmentConfig in the TaskSpec
933 if len(s.Spec.Task.Networks) == 0 && len(s.Spec.Networks) != 0 {
934 return s.Spec.Networks
936 return s.Spec.Task.Networks
939 // IsVIPOnIngressNetwork check if the vip is in ingress network
940 func (na *cnmNetworkAllocator) IsVIPOnIngressNetwork(vip *api.Endpoint_VirtualIP) bool {
945 localNet := na.getNetwork(vip.NetworkID)
946 if localNet != nil && localNet.nw != nil {
947 return networkallocator.IsIngressNetwork(localNet.nw)
952 // IsBuiltInDriver returns whether the passed driver is an internal network driver
953 func IsBuiltInDriver(name string) bool {
954 n := strings.ToLower(name)
955 for _, d := range initializers {