/
cidr.go
128 lines (105 loc) · 4.24 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
// Copyright 2018 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"
)
// 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(impl Implementation, prefixes []*net.IPNet) ([]*identity.Identity, error) {
// First, if the implementation will complain, exit early.
if err := checkPrefixes(impl, prefixes); err != nil {
return nil, err
}
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
var usedIdentities []*identity.Identity
// maintain list of newly allocated identities to update ipcache
allocatedIdentities := map[string]*identity.Identity{}
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()
id, isNew, err := cache.AllocateIdentity(allocateCtx, nil, cidr.GetCIDRLabels(prefix))
if err != nil {
cache.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, 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 := cache.LookupIdentity(cidr.GetCIDRLabels(prefix)); id != nil {
releaseCtx, cancel := context.WithTimeout(context.Background(), option.Config.KVstoreConnectivityTimeout)
defer cancel()
released, err := cache.Release(releaseCtx, nil, 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())
}
}
}