github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/ipcache/cidr.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ipcache 16 17 import ( 18 "context" 19 "fmt" 20 "net" 21 22 "github.com/cilium/cilium/pkg/identity" 23 "github.com/cilium/cilium/pkg/identity/cache" 24 "github.com/cilium/cilium/pkg/ip" 25 "github.com/cilium/cilium/pkg/labels" 26 "github.com/cilium/cilium/pkg/labels/cidr" 27 "github.com/cilium/cilium/pkg/option" 28 "github.com/cilium/cilium/pkg/source" 29 ) 30 31 // AllocateCIDRs attempts to allocate identities for a list of CIDRs. If any 32 // allocation fails, all allocations are rolled back and the error is returned. 33 // When an identity is freshly allocated for a CIDR, it is added to the 34 // ipcache. 35 func AllocateCIDRs(impl Implementation, prefixes []*net.IPNet) ([]*identity.Identity, error) { 36 // First, if the implementation will complain, exit early. 37 if err := checkPrefixes(impl, prefixes); err != nil { 38 return nil, err 39 } 40 41 return allocateCIDRs(prefixes) 42 } 43 44 // AllocateCIDRsForIPs attempts to allocate identities for a list of CIDRs. If 45 // any allocation fails, all allocations are rolled back and the error is 46 // returned. When an identity is freshly allocated for a CIDR, it is added to 47 // the ipcache. 48 func AllocateCIDRsForIPs(prefixes []net.IP) ([]*identity.Identity, error) { 49 return allocateCIDRs(ip.GetCIDRPrefixesFromIPs(prefixes)) 50 } 51 52 func allocateCIDRs(prefixes []*net.IPNet) ([]*identity.Identity, error) { 53 // maintain list of used identities to undo on error 54 var usedIdentities []*identity.Identity 55 56 // maintain list of newly allocated identities to update ipcache 57 allocatedIdentities := map[string]*identity.Identity{} 58 newlyAllocatedIdentities := map[string]*identity.Identity{} 59 60 for _, prefix := range prefixes { 61 if prefix == nil { 62 continue 63 } 64 65 prefixStr := prefix.String() 66 67 // Figure out if this call needs to be able to update the selector cache synchronously. 68 allocateCtx, cancel := context.WithTimeout(context.Background(), option.Config.IPAllocationTimeout) 69 defer cancel() 70 71 id, isNew, err := cache.AllocateIdentity(allocateCtx, nil, cidr.GetCIDRLabels(prefix)) 72 if err != nil { 73 cache.ReleaseSlice(context.Background(), nil, usedIdentities) 74 return nil, fmt.Errorf("failed to allocate identity for cidr %s: %s", prefixStr, err) 75 } 76 77 id.CIDRLabel = labels.NewLabelsFromModel([]string{labels.LabelSourceCIDR + ":" + prefixStr}) 78 79 usedIdentities = append(usedIdentities, id) 80 allocatedIdentities[prefixStr] = id 81 if isNew { 82 newlyAllocatedIdentities[prefixStr] = id 83 } 84 85 } 86 87 allocatedIdentitiesSlice := make([]*identity.Identity, 0, len(allocatedIdentities)) 88 89 // Only upsert into ipcache if identity wasn't allocated before. 90 for prefixString, id := range newlyAllocatedIdentities { 91 IPIdentityCache.Upsert(prefixString, nil, 0, Identity{ 92 ID: id.ID, 93 Source: source.Generated, 94 }) 95 } 96 97 for _, id := range allocatedIdentities { 98 allocatedIdentitiesSlice = append(allocatedIdentitiesSlice, id) 99 } 100 101 return allocatedIdentitiesSlice, nil 102 } 103 104 // ReleaseCIDRs releases the identities of a list of CIDRs. When the last use 105 // of the identity is released, the ipcache entry is deleted. 106 func ReleaseCIDRs(prefixes []*net.IPNet) { 107 for _, prefix := range prefixes { 108 if prefix == nil { 109 continue 110 } 111 112 if id := cache.LookupIdentity(cidr.GetCIDRLabels(prefix)); id != nil { 113 releaseCtx, cancel := context.WithTimeout(context.Background(), option.Config.KVstoreConnectivityTimeout) 114 defer cancel() 115 116 released, err := cache.Release(releaseCtx, nil, id) 117 if err != nil { 118 log.WithError(err).Warningf("Unable to release identity for CIDR %s. Ignoring error. Identity may be leaked", prefix.String()) 119 } 120 121 if released { 122 IPIdentityCache.Delete(prefix.String(), source.Generated) 123 } 124 } else { 125 log.Errorf("Unable to find identity of previously used CIDR %s", prefix.String()) 126 } 127 } 128 }