github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/ipcache/ipcache_test.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 // +build !privileged_tests 16 17 package ipcache 18 19 import ( 20 "net" 21 "reflect" 22 "testing" 23 24 "github.com/cilium/cilium/pkg/checker" 25 identityPkg "github.com/cilium/cilium/pkg/identity" 26 "github.com/cilium/cilium/pkg/source" 27 28 . "gopkg.in/check.v1" 29 ) 30 31 // Hook up gocheck into the "go test" runner. 32 type IPCacheTestSuite struct{} 33 34 var _ = Suite(&IPCacheTestSuite{}) 35 36 func Test(t *testing.T) { 37 TestingT(t) 38 } 39 40 func (s *IPCacheTestSuite) TestIPCache(c *C) { 41 endpointIP := "10.0.0.15" 42 identity := (identityPkg.NumericIdentity(68)) 43 44 // Assure sane state at start. 45 c.Assert(len(IPIdentityCache.ipToIdentityCache), Equals, 0) 46 c.Assert(len(IPIdentityCache.identityToIPCache), Equals, 0) 47 48 // Deletion of key that doesn't exist doesn't cause panic. 49 IPIdentityCache.Delete(endpointIP, source.KVStore) 50 51 IPIdentityCache.Upsert(endpointIP, nil, 0, Identity{ 52 ID: identity, 53 Source: source.KVStore, 54 }) 55 56 // Assure both caches are updated.. 57 c.Assert(len(IPIdentityCache.ipToIdentityCache), Equals, 1) 58 c.Assert(len(IPIdentityCache.identityToIPCache), Equals, 1) 59 60 cachedIdentity, exists := IPIdentityCache.LookupByIP(endpointIP) 61 c.Assert(exists, Equals, true) 62 c.Assert(cachedIdentity.ID, Equals, identity) 63 c.Assert(cachedIdentity.Source, Equals, source.KVStore) 64 65 // kubernetes source cannot update kvstore source 66 updated := IPIdentityCache.Upsert(endpointIP, nil, 0, Identity{ 67 ID: identity, 68 Source: source.Kubernetes, 69 }) 70 c.Assert(updated, Equals, false) 71 72 IPIdentityCache.Upsert(endpointIP, nil, 0, Identity{ 73 ID: identity, 74 Source: source.KVStore, 75 }) 76 77 // No duplicates. 78 c.Assert(len(IPIdentityCache.ipToIdentityCache), Equals, 1) 79 c.Assert(len(IPIdentityCache.identityToIPCache), Equals, 1) 80 81 IPIdentityCache.Delete(endpointIP, source.KVStore) 82 83 // Assure deletion occurs across both mappings. 84 c.Assert(len(IPIdentityCache.ipToIdentityCache), Equals, 0) 85 c.Assert(len(IPIdentityCache.identityToIPCache), Equals, 0) 86 87 _, exists = IPIdentityCache.LookupByIP(endpointIP) 88 89 c.Assert(exists, Equals, false) 90 91 IPIdentityCache.Upsert(endpointIP, nil, 0, Identity{ 92 ID: identity, 93 Source: source.KVStore, 94 }) 95 96 newIdentity := identityPkg.NumericIdentity(69) 97 IPIdentityCache.Upsert(endpointIP, nil, 0, Identity{ 98 ID: newIdentity, 99 Source: source.KVStore, 100 }) 101 102 // Ensure that update of cache with new identity doesn't keep old identity-to-ip 103 // mapping around. 104 _, exists = IPIdentityCache.LookupByIdentity(identity) 105 c.Assert(exists, Equals, false) 106 107 cachedIPSet, exists := IPIdentityCache.LookupByIdentity(newIdentity) 108 c.Assert(exists, Equals, true) 109 for cachedIP := range cachedIPSet { 110 c.Assert(cachedIP, Equals, endpointIP) 111 } 112 113 IPIdentityCache.Delete(endpointIP, source.KVStore) 114 115 // Assure deletion occurs across both mappings. 116 c.Assert(len(IPIdentityCache.ipToIdentityCache), Equals, 0) 117 c.Assert(len(IPIdentityCache.identityToIPCache), Equals, 0) 118 119 // Test mapping of multiple IPs to same identity. 120 endpointIPs := []string{"192.168.0.1", "20.3.75.3", "27.2.2.2", "127.0.0.1", "127.0.0.1"} 121 identities := []identityPkg.NumericIdentity{5, 67, 29, 29, 29} 122 123 for index := range endpointIPs { 124 IPIdentityCache.Upsert(endpointIPs[index], nil, 0, Identity{ 125 ID: identities[index], 126 Source: source.KVStore, 127 }) 128 cachedIdentity, _ := IPIdentityCache.LookupByIP(endpointIPs[index]) 129 c.Assert(cachedIdentity.ID, Equals, identities[index]) 130 } 131 132 expectedIPList := map[string]struct{}{ 133 "27.2.2.2": {}, 134 "127.0.0.1": {}, 135 } 136 137 cachedEndpointIPs, _ := IPIdentityCache.LookupByIdentity(29) 138 c.Assert(reflect.DeepEqual(cachedEndpointIPs, expectedIPList), Equals, true) 139 140 IPIdentityCache.Delete("27.2.2.2", source.KVStore) 141 142 expectedIPList = map[string]struct{}{ 143 "127.0.0.1": {}, 144 } 145 146 cachedEndpointIPs, exists = IPIdentityCache.LookupByIdentity(29) 147 c.Assert(exists, Equals, true) 148 c.Assert(reflect.DeepEqual(cachedEndpointIPs, expectedIPList), Equals, true) 149 150 cachedIdentity, exists = IPIdentityCache.LookupByIP("127.0.0.1") 151 c.Assert(exists, Equals, true) 152 c.Assert(cachedIdentity.ID, Equals, identityPkg.NumericIdentity(29)) 153 154 cachedIdentity, exists = IPIdentityCache.LookupByPrefix("127.0.0.1/32") 155 c.Assert(exists, Equals, true) 156 c.Assert(cachedIdentity.ID, Equals, identityPkg.NumericIdentity(29)) 157 158 IPIdentityCache.Delete("127.0.0.1", source.KVStore) 159 160 _, exists = IPIdentityCache.LookupByIdentity(29) 161 c.Assert(exists, Equals, false) 162 163 _, exists = IPIdentityCache.LookupByPrefix("127.0.0.1/32") 164 c.Assert(exists, Equals, false) 165 166 // Clean up. 167 for index := range endpointIPs { 168 IPIdentityCache.Delete(endpointIPs[index], source.KVStore) 169 _, exists = IPIdentityCache.LookupByIP(endpointIPs[index]) 170 c.Assert(exists, Equals, false) 171 172 _, exists = IPIdentityCache.LookupByIdentity(identities[index]) 173 c.Assert(exists, Equals, false) 174 } 175 176 c.Assert(len(IPIdentityCache.ipToIdentityCache), Equals, 0) 177 c.Assert(len(IPIdentityCache.identityToIPCache), Equals, 0) 178 179 } 180 181 func (s *IPCacheTestSuite) TestKeyToIPNet(c *C) { 182 // Valid IPv6. 183 validIPv6Key := "cilium/state/ip/v1/default/f00d::a00:0:0:c164" 184 185 _, expectedIPv6, err := net.ParseCIDR("f00d::a00:0:0:c164/128") 186 c.Assert(err, IsNil) 187 188 ipv6, isHost, err := keyToIPNet(validIPv6Key) 189 c.Assert(ipv6, Not(IsNil)) 190 c.Assert(err, IsNil) 191 c.Assert(isHost, Equals, true) 192 c.Assert(ipv6, checker.DeepEquals, expectedIPv6) 193 194 // Valid IPv6 prefix. 195 validIPv6Key = "cilium/state/ip/v1/default/f00d::a00:0:0:0/64" 196 197 _, expectedIPv6, err = net.ParseCIDR("f00d::a00:0:0:0/64") 198 c.Assert(err, IsNil) 199 200 ipv6, isHost, err = keyToIPNet(validIPv6Key) 201 c.Assert(ipv6, Not(IsNil)) 202 c.Assert(err, IsNil) 203 c.Assert(isHost, Equals, false) 204 c.Assert(ipv6, checker.DeepEquals, expectedIPv6) 205 206 // Valid IPv4. 207 validIPv4Key := "cilium/state/ip/v1/default/10.0.114.197" 208 _, expectedIPv4, err := net.ParseCIDR("10.0.114.197/32") 209 c.Assert(err, IsNil) 210 ipv4, isHost, err := keyToIPNet(validIPv4Key) 211 c.Assert(ipv4, Not(IsNil)) 212 c.Assert(err, IsNil) 213 c.Assert(isHost, Equals, true) 214 c.Assert(ipv4, checker.DeepEquals, expectedIPv4) 215 216 // Valid IPv4 prefix. 217 validIPv4Key = "cilium/state/ip/v1/default/10.0.114.0/24" 218 _, expectedIPv4, err = net.ParseCIDR("10.0.114.0/24") 219 c.Assert(err, IsNil) 220 ipv4, isHost, err = keyToIPNet(validIPv4Key) 221 c.Assert(ipv4, Not(IsNil)) 222 c.Assert(err, IsNil) 223 c.Assert(isHost, Equals, false) 224 c.Assert(ipv4, checker.DeepEquals, expectedIPv4) 225 226 // Invalid prefix. 227 invalidPrefixKey := "cilium/state/foobar/v1/default/f00d::a00:0:0:c164" 228 nilIP, isHost, err := keyToIPNet(invalidPrefixKey) 229 c.Assert(nilIP, IsNil) 230 c.Assert(err, Not(IsNil)) 231 c.Assert(isHost, Equals, false) 232 233 // Invalid IP in key. 234 invalidIPKey := "cilium/state/ip/v1/default/10.abfd.114.197" 235 nilIP, isHost, err = keyToIPNet(invalidIPKey) 236 c.Assert(nilIP, IsNil) 237 c.Assert(err, Not(IsNil)) 238 c.Assert(isHost, Equals, false) 239 240 // Invalid CIDR. 241 invalidIPKey = "cilium/state/ip/v1/default/192.0.2.3/54" 242 nilIP, isHost, err = keyToIPNet(invalidIPKey) 243 c.Assert(nilIP, IsNil) 244 c.Assert(err, Not(IsNil)) 245 c.Assert(isHost, Equals, false) 246 } 247 248 type dummyListener struct { 249 entries map[string]identityPkg.NumericIdentity 250 ipc *IPCache 251 } 252 253 func newDummyListener(ipc *IPCache) *dummyListener { 254 return &dummyListener{ 255 ipc: ipc, 256 } 257 } 258 259 func (dl *dummyListener) OnIPIdentityCacheChange(modType CacheModification, 260 cidr net.IPNet, oldHostIP, newHostIP net.IP, oldID *identityPkg.NumericIdentity, 261 newID identityPkg.NumericIdentity, encryptKey uint8) { 262 263 switch modType { 264 case Upsert: 265 dl.entries[cidr.String()] = newID 266 default: 267 // Ignore, for simplicity we just clear the cache every time 268 } 269 } 270 271 func (dl *dummyListener) OnIPIdentityCacheGC() {} 272 273 func (dl *dummyListener) ExpectMapping(c *C, targetIP string, targetIdentity identityPkg.NumericIdentity) { 274 // Identity lookup directly shows the expected mapping 275 identity, exists := dl.ipc.LookupByPrefix(targetIP) 276 c.Assert(exists, Equals, true) 277 c.Assert(identity.ID, Equals, targetIdentity) 278 279 // Dump reliably supplies the IP once and only the pod identity. 280 dl.entries = make(map[string]identityPkg.NumericIdentity) 281 dl.ipc.DumpToListenerLocked(dl) 282 c.Assert(dl.entries, checker.DeepEquals, 283 map[string]identityPkg.NumericIdentity{ 284 targetIP: targetIdentity, 285 }) 286 } 287 288 func (s *IPCacheTestSuite) TestIPCacheShadowing(c *C) { 289 endpointIP := "10.0.0.15" 290 cidrOverlap := "10.0.0.15/32" 291 epIdentity := (identityPkg.NumericIdentity(68)) 292 cidrIdentity := (identityPkg.NumericIdentity(202)) 293 ipc := NewIPCache() 294 295 // Assure sane state at start. 296 c.Assert(ipc.ipToIdentityCache, checker.DeepEquals, map[string]Identity{}) 297 c.Assert(ipc.identityToIPCache, checker.DeepEquals, map[identityPkg.NumericIdentity]map[string]struct{}{}) 298 299 // Upsert overlapping identities for the IP. Pod identity takes precedence. 300 ipc.Upsert(endpointIP, nil, 0, Identity{ 301 ID: epIdentity, 302 Source: source.KVStore, 303 }) 304 ipc.Upsert(cidrOverlap, nil, 0, Identity{ 305 ID: cidrIdentity, 306 Source: source.Generated, 307 }) 308 ipcache := newDummyListener(ipc) 309 ipcache.ExpectMapping(c, cidrOverlap, epIdentity) 310 311 // Deleting pod identity shows that cidr identity is now used. 312 ipc.Delete(endpointIP, source.KVStore) 313 ipcache.ExpectMapping(c, cidrOverlap, cidrIdentity) 314 315 // Reinsert of pod IP should shadow the CIDR identity again. 316 ipc.Upsert(endpointIP, nil, 0, Identity{ 317 ID: epIdentity, 318 Source: source.KVStore, 319 }) 320 ipcache.ExpectMapping(c, cidrOverlap, epIdentity) 321 322 // Deletion of the shadowed identity should not change the output. 323 ipc.Delete(cidrOverlap, source.Generated) 324 ipcache.ExpectMapping(c, cidrOverlap, epIdentity) 325 326 // Clean up 327 ipc.Delete(endpointIP, source.KVStore) 328 _, exists := ipc.LookupByPrefix(cidrOverlap) 329 c.Assert(exists, Equals, false) 330 }