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