github.com/datadog/cilium@v1.6.12/pkg/counter/prefixes.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 counter 16 17 import ( 18 "fmt" 19 "net" 20 21 "github.com/cilium/cilium/pkg/lock" 22 ) 23 24 // PrefixLengthCounter tracks references to prefix lengths, limited by the 25 // maxUniquePrefixes count. Neither of the IPv4 or IPv6 counters nested within 26 // may contain more keys than the specified maximum number of unique prefixes. 27 type PrefixLengthCounter struct { 28 lock.RWMutex 29 30 v4 IntCounter 31 v6 IntCounter 32 33 maxUniquePrefixes4 int 34 maxUniquePrefixes6 int 35 } 36 37 // NewPrefixLengthCounter returns a new PrefixLengthCounter which limits 38 // insertions to the specified maximum number of unique prefix lengths. 39 func NewPrefixLengthCounter(maxUniquePrefixes6, maxUniquePrefixes4 int) *PrefixLengthCounter { 40 return &PrefixLengthCounter{ 41 v4: make(IntCounter), 42 v6: make(IntCounter), 43 maxUniquePrefixes4: maxUniquePrefixes4, 44 maxUniquePrefixes6: maxUniquePrefixes6, 45 } 46 } 47 48 // checkLimits checks whether the specified new count of prefixes would exceed 49 // the specified limit on the maximum number of unique keys, and returns an 50 // error if it would exceed the limit. 51 func checkLimits(current, newCount, max int) error { 52 if newCount > max { 53 return fmt.Errorf("adding specified prefixes would result in too many prefix lengths (current: %d, result: %d, max: %d)", 54 current, newCount, max) 55 } 56 return nil 57 } 58 59 // Add increments references to prefix lengths for the specified IPNets to the 60 // counter. If the maximum number of unique prefix lengths would be exceeded, 61 // returns an error. 62 // 63 // Returns true if adding these prefixes results in an increase in the total 64 // number of unique prefix lengths in the counter. 65 func (p *PrefixLengthCounter) Add(prefixes []*net.IPNet) (bool, error) { 66 p.Lock() 67 defer p.Unlock() 68 69 // Assemble a map of references that need to be added 70 newV4Counter := p.v4.DeepCopy() 71 newV6Counter := p.v6.DeepCopy() 72 newV4Prefixes := false 73 newV6Prefixes := false 74 for _, prefix := range prefixes { 75 ones, bits := prefix.Mask.Size() 76 77 switch bits { 78 case net.IPv4len * 8: 79 if newV4Counter.Add(ones) { 80 newV4Prefixes = true 81 } 82 case net.IPv6len * 8: 83 if newV6Counter.Add(ones) { 84 newV6Prefixes = true 85 } 86 default: 87 return false, fmt.Errorf("unsupported IPAddr bitlength %d", bits) 88 } 89 } 90 91 // Check if they can be added given the limit in place 92 if newV4Prefixes { 93 if err := checkLimits(len(p.v4), len(newV4Counter), p.maxUniquePrefixes4); err != nil { 94 return false, err 95 } 96 } 97 if newV6Prefixes { 98 if err := checkLimits(len(p.v6), len(newV6Counter), p.maxUniquePrefixes6); err != nil { 99 return false, err 100 } 101 } 102 103 // Set and return whether anything changed 104 p.v4 = newV4Counter 105 p.v6 = newV6Counter 106 return newV4Prefixes || newV6Prefixes, nil 107 } 108 109 // Delete reduces references to prefix lengths in the the specified IPNets from 110 // the counter. Returns true if removing references to these prefix lengths 111 // would result in a decrese in the total number of unique prefix lengths in 112 // the counter. 113 func (p *PrefixLengthCounter) Delete(prefixes []*net.IPNet) (changed bool) { 114 p.Lock() 115 defer p.Unlock() 116 117 for _, prefix := range prefixes { 118 ones, bits := prefix.Mask.Size() 119 switch bits { 120 case net.IPv4len * 8: 121 if p.v4.Delete(ones) { 122 changed = true 123 } 124 case net.IPv6len * 8: 125 if p.v6.Delete(ones) { 126 changed = true 127 } 128 } 129 } 130 131 return changed 132 } 133 134 // ToBPFData converts the counter into a set of prefix lengths that the BPF 135 // datapath can use for LPM lookup. 136 func (p *PrefixLengthCounter) ToBPFData() (s6, s4 []int) { 137 p.RLock() 138 defer p.RUnlock() 139 140 return p.v6.ToBPFData(), p.v4.ToBPFData() 141 }