github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/utils/ipprefix/ipprefix.go (about) 1 package ipprefix 2 3 import ( 4 "encoding/binary" 5 "net" 6 "sync" 7 ) 8 9 // FuncOnLpmIP is the type of func which will operate on the value associated with the lpm ip. 10 type FuncOnLpmIP func(val interface{}) bool 11 12 // FuncOnVals is the type of the func which will operate on each value and will return a new value 13 // for each associated value. 14 type FuncOnVals func(val interface{}) interface{} 15 16 //IPcache is an interface which provides functionality to store ip's and do longest prefix match 17 type IPcache interface { 18 // Put takes an argument an ip address, mask and value. 19 Put(net.IP, int, interface{}) 20 // Get takes an argument the IP address and mask and returns the value that is stored for 21 // that key. 22 Get(net.IP, int) (interface{}, bool) 23 // RunFuncOnLpmIP function takes as an argument an IP address and a function. It finds the 24 // subnet to which this IP belongs with the longest prefix match. It then calls the 25 // function supplied by the user on the value stored and if it succeeds then it returns. 26 RunFuncOnLpmIP(net.IP, FuncOnLpmIP) 27 // RunFuncOnVals takes an argument a function which is called on all the values stored in 28 // the cache. This can be used to update the old values with the new values. If the new 29 // value is nil, it will delete the key. 30 RunFuncOnVals(FuncOnVals) 31 } 32 33 const ( 34 ipv4MaskSize = 32 + 1 35 ipv6MaskSize = 128 + 1 36 ) 37 38 type ipcacheV4 struct { 39 ipv4 []map[uint32]interface{} 40 sync.RWMutex 41 } 42 43 type ipcacheV6 struct { 44 ipv6 []map[[16]byte]interface{} 45 sync.RWMutex 46 } 47 48 type ipcache struct { 49 ipv4 *ipcacheV4 50 ipv6 *ipcacheV6 51 } 52 53 func (cache *ipcacheV4) Put(ip net.IP, mask int, val interface{}) { 54 cache.Lock() 55 defer cache.Unlock() 56 57 if cache.ipv4[mask] == nil { 58 cache.ipv4[mask] = map[uint32]interface{}{} 59 } 60 61 m := cache.ipv4[mask] 62 // the following expression is ANDing the ip with the mask 63 key := binary.BigEndian.Uint32(ip) & binary.BigEndian.Uint32(net.CIDRMask(mask, 32)) 64 if val == nil { 65 delete(m, key) 66 } else { 67 m[key] = val 68 } 69 } 70 71 func (cache *ipcacheV4) Get(ip net.IP, mask int) (interface{}, bool) { 72 cache.RLock() 73 defer cache.RUnlock() 74 75 m := cache.ipv4[mask] 76 if m != nil { 77 val, ok := m[binary.BigEndian.Uint32(ip)&binary.BigEndian.Uint32(net.CIDRMask(mask, 32))] 78 if ok { 79 return val, true 80 } 81 } 82 83 return nil, false 84 } 85 86 func (cache *ipcacheV4) RunFuncOnLpmIP(ip net.IP, f func(val interface{}) bool) { 87 cache.Lock() 88 defer cache.Unlock() 89 90 for i := len(cache.ipv4) - 1; i >= 0; i-- { 91 m := cache.ipv4[i] 92 if m != nil { 93 val, ok := m[binary.BigEndian.Uint32(ip)&binary.BigEndian.Uint32(net.CIDRMask(i, 32))] 94 if ok && f(val) { 95 return 96 } 97 } 98 } 99 100 } 101 102 func (cache *ipcacheV4) RunFuncOnVals(f func(val interface{}) interface{}) { 103 cache.Lock() 104 defer cache.Unlock() 105 106 for mask, m := range cache.ipv4 { 107 if m == nil { 108 continue 109 } 110 111 for ip, val := range m { 112 v := f(val) 113 if v == nil { 114 delete(m, ip) 115 continue 116 } 117 118 m[ip] = v 119 } 120 121 if len(m) == 0 { 122 cache.ipv4[mask] = nil 123 } 124 } 125 126 } 127 128 func (cache *ipcacheV6) Put(ip net.IP, mask int, val interface{}) { 129 cache.Lock() 130 defer cache.Unlock() 131 132 if cache.ipv6[mask] == nil { 133 cache.ipv6[mask] = map[[16]byte]interface{}{} 134 } 135 136 m := cache.ipv6[mask] 137 // the following expression is ANDing the ip with the mask 138 var maskip [16]byte 139 copy(maskip[:], ip.Mask(net.CIDRMask(mask, 128))) 140 141 if val == nil { 142 delete(m, maskip) 143 } else { 144 m[maskip] = val 145 } 146 } 147 148 func (cache *ipcacheV6) Get(ip net.IP, mask int) (interface{}, bool) { 149 cache.RLock() 150 defer cache.RUnlock() 151 152 m := cache.ipv6[mask] 153 if m != nil { 154 var maskip [16]byte 155 copy(maskip[:], ip.Mask(net.CIDRMask(mask, 128))) 156 val, ok := m[maskip] 157 if ok { 158 return val, true 159 } 160 } 161 162 return nil, false 163 } 164 165 func (cache *ipcacheV6) RunFuncOnLpmIP(ip net.IP, f func(val interface{}) bool) { 166 cache.Lock() 167 defer cache.Unlock() 168 169 for i := len(cache.ipv6) - 1; i >= 0; i-- { 170 m := cache.ipv6[i] 171 if m != nil { 172 var maskip [16]byte 173 copy(maskip[:], ip.Mask(net.CIDRMask(i, 128))) 174 val, ok := m[maskip] 175 if ok && f(val) { 176 return 177 } 178 } 179 } 180 } 181 182 func (cache *ipcacheV6) RunFuncOnVals(f func(val interface{}) interface{}) { 183 cache.Lock() 184 defer cache.Unlock() 185 186 for mask, m := range cache.ipv6 { 187 if m == nil { 188 continue 189 } 190 191 for ip, val := range m { 192 v := f(val) 193 if v == nil { 194 delete(m, ip) 195 continue 196 } 197 198 m[ip] = v 199 } 200 201 if len(m) == 0 { 202 cache.ipv6[mask] = nil 203 } 204 } 205 } 206 207 //NewIPCache creates an object which is implementing the interface IPcache 208 func NewIPCache() IPcache { 209 return &ipcache{ 210 ipv4: &ipcacheV4{ipv4: make([]map[uint32]interface{}, ipv4MaskSize)}, 211 ipv6: &ipcacheV6{ipv6: make([]map[[16]byte]interface{}, ipv6MaskSize)}, 212 } 213 } 214 215 func (cache *ipcache) Put(ip net.IP, mask int, val interface{}) { 216 if ip.To4() != nil { 217 cache.ipv4.Put(ip.To4(), mask, val) 218 return 219 } 220 221 cache.ipv6.Put(ip.To16(), mask, val) 222 } 223 224 func (cache *ipcache) Get(ip net.IP, mask int) (interface{}, bool) { 225 226 if ip.To4() != nil { 227 return cache.ipv4.Get(ip.To4(), mask) 228 } 229 230 return cache.ipv6.Get(ip.To16(), mask) 231 } 232 233 func (cache *ipcache) RunFuncOnLpmIP(ip net.IP, f FuncOnLpmIP) { 234 if ip.To4() != nil { 235 cache.ipv4.RunFuncOnLpmIP(ip.To4(), f) 236 return 237 } 238 239 cache.ipv6.RunFuncOnLpmIP(ip.To16(), f) 240 } 241 242 func (cache *ipcache) RunFuncOnVals(f FuncOnVals) { 243 244 cache.ipv4.RunFuncOnVals(f) 245 cache.ipv6.RunFuncOnVals(f) 246 }