github.com/cilium/cilium@v1.16.2/pkg/maps/lbmap/skip_lb_map.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package lbmap 5 6 import ( 7 "fmt" 8 "net" 9 "unsafe" 10 11 "github.com/sirupsen/logrus" 12 13 "github.com/cilium/cilium/pkg/bpf" 14 "github.com/cilium/cilium/pkg/byteorder" 15 "github.com/cilium/cilium/pkg/ebpf" 16 "github.com/cilium/cilium/pkg/logging/logfields" 17 "github.com/cilium/cilium/pkg/option" 18 "github.com/cilium/cilium/pkg/types" 19 ) 20 21 const ( 22 // SkipLB4MapName is the name of the IPv4 BPF map that stores entries to skip LB. 23 SkipLB4MapName = "cilium_skip_lb4" 24 25 // SkipLB6MapName is the name of the IPv6 BPF map that stores entries to skip LB. 26 SkipLB6MapName = "cilium_skip_lb6" 27 28 // SkipLBMapMaxEntries is the maximum number of entries in the skip LB BPF maps. 29 SkipLBMapMaxEntries = 100 30 ) 31 32 // SkipLBMap provides access to the eBPF map that stores entries for which load-balancing is skipped. 33 type SkipLBMap interface { 34 AddLB4(netnsCookie uint64, ip net.IP, port uint16) error 35 AddLB6(netnsCookie uint64, ip net.IP, port uint16) error 36 DeleteLB4ByAddrPort(ip net.IP, port uint16) 37 DeleteLB6ByAddrPort(ip net.IP, port uint16) 38 DeleteLB4ByNetnsCookie(cookie uint64) 39 DeleteLB6ByNetnsCookie(cookie uint64) 40 } 41 42 func NewSkipLBMap() (SkipLBMap, error) { 43 skipLBMap := &skipLBMap{} 44 45 if option.Config.EnableIPv4 { 46 skipLBMap.bpfMap4 = ebpf.NewMap(&ebpf.MapSpec{ 47 Name: SkipLB4MapName, 48 Type: ebpf.Hash, 49 KeySize: uint32(unsafe.Sizeof(SkipLB4Key{})), 50 ValueSize: uint32(unsafe.Sizeof(SkipLB4Value{})), 51 MaxEntries: SkipLBMapMaxEntries, 52 Flags: bpf.BPF_F_NO_PREALLOC, 53 Pinning: ebpf.PinByName}, 54 ) 55 if err := skipLBMap.bpfMap4.OpenOrCreate(); err != nil { 56 return nil, fmt.Errorf("failed to open or create %s: %w", SkipLB4MapName, err) 57 } 58 } 59 if option.Config.EnableIPv6 { 60 skipLBMap.bpfMap6 = ebpf.NewMap(&ebpf.MapSpec{ 61 Name: SkipLB6MapName, 62 Type: ebpf.Hash, 63 KeySize: uint32(unsafe.Sizeof(SkipLB6Key{})), 64 ValueSize: uint32(unsafe.Sizeof(SkipLB6Value{})), 65 MaxEntries: SkipLBMapMaxEntries, 66 Flags: bpf.BPF_F_NO_PREALLOC, 67 Pinning: ebpf.PinByName}, 68 ) 69 if err := skipLBMap.bpfMap6.OpenOrCreate(); err != nil { 70 return nil, fmt.Errorf("failed to open or create %s: %w", SkipLB6MapName, err) 71 } 72 } 73 74 return skipLBMap, nil 75 } 76 77 // AddLB4 adds the given tuple to skip LB for to the BPF v4 map. 78 func (m *skipLBMap) AddLB4(netnsCookie uint64, ip net.IP, port uint16) error { 79 return m.bpfMap4.Update( 80 NewSkipLB4Key(netnsCookie, ip.To4(), port), 81 &SkipLB4Value{}, 0) 82 } 83 84 // AddLB6 adds the given tuple to skip LB for to the BPF v6 map. 85 func (m *skipLBMap) AddLB6(netnsCookie uint64, ip net.IP, port uint16) error { 86 return m.bpfMap6.Update( 87 NewSkipLB6Key(netnsCookie, ip.To16(), port), 88 &SkipLB6Value{}, 0) 89 } 90 91 // DeleteLB4ByAddrPort deletes entries associated with the passed address and port from the v4 map. 92 func (m *skipLBMap) DeleteLB4ByAddrPort(ip net.IP, port uint16) { 93 deleted := 0 94 errors := 0 95 deleteEntry := func(key *SkipLB4Key, _ *SkipLB4Value) { 96 if key == nil { 97 return 98 } 99 if ip.To4().Equal(key.Address.IP()) && byteorder.NetworkToHost16(key.Port) == port { 100 if err := m.bpfMap4.Delete(key); err != nil { 101 errors++ 102 log.WithError(err).WithFields(logrus.Fields{ 103 "key": key, 104 "map": SkipLB4MapName, 105 }).Error("error deleting entry from map") 106 return 107 } 108 deleted++ 109 } 110 } 111 if err := m.bpfMap4.IterateWithCallback(&SkipLB4Key{}, &SkipLB4Value{}, 112 func(k, v interface{}) { 113 key := k.(*SkipLB4Key) 114 value := v.(*SkipLB4Value) 115 deleteEntry(key, value) 116 }); err != nil { 117 log.WithError(err).Error("error iterating over skip_lb4 map") 118 } 119 scopedLog := log.WithFields(logrus.Fields{ 120 logfields.Address: ip, 121 logfields.Port: port, 122 }) 123 scopedLog.WithFields(logrus.Fields{ 124 "deleted": deleted, 125 "errors": errors, 126 }).Info("DeleteLB4ByAddrPort") 127 } 128 129 // DeleteLB4ByNetnsCookie deletes entries associated with the passed netns cookie from the v4 map. 130 func (m *skipLBMap) DeleteLB4ByNetnsCookie(cookie uint64) { 131 deleted := 0 132 errors := 0 133 deleteEntry := func(key *SkipLB4Key, _ *SkipLB4Value) { 134 if key == nil { 135 return 136 } 137 if key.NetnsCookie == cookie { 138 if err := m.bpfMap4.Delete(key); err != nil { 139 errors++ 140 log.WithFields(logrus.Fields{ 141 "key": key, 142 "map": SkipLB4MapName, 143 }).Error("error deleting entry from map") 144 return 145 } 146 deleted++ 147 } 148 } 149 if err := m.bpfMap4.IterateWithCallback(&SkipLB4Key{}, &SkipLB4Value{}, 150 func(k, v interface{}) { 151 key := k.(*SkipLB4Key) 152 value := v.(*SkipLB4Value) 153 deleteEntry(key, value) 154 }); err != nil { 155 log.WithError(err).Error("error iterating over skip_lb4 map") 156 } 157 scopedLog := log.WithFields(logrus.Fields{ 158 "netns_cookie": cookie, 159 }) 160 scopedLog.WithFields(logrus.Fields{ 161 "deleted": deleted, 162 "errors": errors, 163 }).Info("DeleteLB4ByNetnsCookie") 164 } 165 166 // DeleteLB6ByAddrPort deletes entries associated with the passed address and port from the v6 map. 167 func (m *skipLBMap) DeleteLB6ByAddrPort(ip net.IP, port uint16) { 168 deleted := 0 169 errors := 0 170 deleteEntry := func(key *SkipLB6Key, _ *SkipLB6Value) { 171 if key == nil { 172 return 173 } 174 if ip.To16().Equal(key.Address.IP()) && byteorder.NetworkToHost16(key.Port) == port { 175 if err := m.bpfMap6.Delete(key); err != nil { 176 errors++ 177 log.WithFields(logrus.Fields{ 178 "key": key, 179 "map": SkipLB6MapName, 180 }).Error("error deleting entry from map") 181 return 182 } 183 deleted++ 184 } 185 } 186 if err := m.bpfMap6.IterateWithCallback(&SkipLB6Key{}, &SkipLB6Value{}, 187 func(k, v interface{}) { 188 key := k.(*SkipLB6Key) 189 value := v.(*SkipLB6Value) 190 deleteEntry(key, value) 191 }); err != nil { 192 log.WithError(err).Error("error iterating over skip_lb6 map") 193 } 194 scopedLog := log.WithFields(logrus.Fields{ 195 logfields.Address: ip, 196 logfields.Port: port, 197 }) 198 scopedLog.WithFields(logrus.Fields{ 199 "deleted": deleted, 200 "errors": errors, 201 }).Info("DeleteLB6ByAddrPort") 202 } 203 204 // DeleteLB6ByNetnsCookie deletes entries associated with the passed netns cookie from the v6 map. 205 func (m *skipLBMap) DeleteLB6ByNetnsCookie(cookie uint64) { 206 deleted := 0 207 errors := 0 208 deleteEntry := func(key *SkipLB6Key, _ *SkipLB6Value) { 209 if key == nil { 210 return 211 } 212 if key.NetnsCookie == cookie { 213 if err := m.bpfMap6.Delete(key); err != nil { 214 errors++ 215 log.WithError(err).WithFields(logrus.Fields{ 216 "key": key, 217 "map": SkipLB6MapName, 218 }).Error("error deleting entry from map") 219 return 220 } 221 deleted++ 222 } 223 } 224 if err := m.bpfMap6.IterateWithCallback(&SkipLB6Key{}, &SkipLB6Value{}, 225 func(k, v interface{}) { 226 key := k.(*SkipLB6Key) 227 value := v.(*SkipLB6Value) 228 deleteEntry(key, value) 229 }); err != nil { 230 log.WithError(err).Error("error iterating over skip_lb6 map") 231 } 232 scopedLog := log.WithFields(logrus.Fields{ 233 logfields.NetnsCookie: cookie, 234 }) 235 scopedLog.WithFields(logrus.Fields{ 236 "deleted": deleted, 237 "errors": errors, 238 }).Info("DeleteLB6ByNetnsCookie") 239 } 240 241 // SkipLB4Key is the tuple with netns cookie, address and port and used as key in 242 // the skip LB4 map. 243 type SkipLB4Key struct { 244 NetnsCookie uint64 `align:"netns_cookie"` 245 Address types.IPv4 `align:"address"` 246 Port uint16 `align:"port"` 247 Pad int16 `align:"pad"` 248 } 249 250 type SkipLB4Value struct { 251 Pad uint8 `align:"pad"` 252 } 253 254 // NewSkipLB4Key creates the SkipLB4Key 255 func NewSkipLB4Key(netnsCookie uint64, address net.IP, port uint16) *SkipLB4Key { 256 key := SkipLB4Key{ 257 NetnsCookie: netnsCookie, 258 Port: byteorder.HostToNetwork16(port), 259 } 260 copy(key.Address[:], address.To4()) 261 262 return &key 263 } 264 265 func (k *SkipLB4Key) New() bpf.MapKey { return &SkipLB4Key{} } 266 267 // GetValuePtr returns the unsafe pointer to the BPF value 268 func (v *SkipLB4Value) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) } 269 270 // String converts the key into a human-readable string format. 271 func (k *SkipLB4Key) String() string { 272 return fmt.Sprintf("[%d]:%d, %d", k.NetnsCookie, k.Address, k.Port) 273 } 274 275 func (v *SkipLB4Value) New() bpf.MapValue { return &SkipLB4Value{} } 276 277 // String converts the value into a human-readable string format. 278 func (v *SkipLB4Value) String() string { 279 return "" 280 } 281 282 // SkipLB6Key is the tuple with netns cookie, address and port and used as key in 283 // the skip LB6 map. 284 type SkipLB6Key struct { 285 NetnsCookie uint64 `align:"netns_cookie"` 286 Address types.IPv6 `align:"address"` 287 Pad uint32 `align:"pad"` 288 Port uint16 `align:"port"` 289 Pad2 uint16 `align:"pad2"` 290 } 291 292 type SkipLB6Value struct { 293 Pad uint8 `align:"pad"` 294 } 295 296 // NewSkipLB6Key creates the SkipLB6Key 297 func NewSkipLB6Key(netnsCookie uint64, address net.IP, port uint16) *SkipLB6Key { 298 key := SkipLB6Key{ 299 NetnsCookie: netnsCookie, 300 Port: port, 301 } 302 copy(key.Address[:], address.To16()) 303 304 return &key 305 } 306 307 func (k *SkipLB6Key) New() bpf.MapKey { return &SkipLB6Key{} } 308 309 // GetKeyPtr returns the unsafe pointer to the BPF key 310 func (k *SkipLB6Key) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) } 311 312 // GetValuePtr returns the unsafe pointer to the BPF value 313 func (v *SkipLB6Value) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) } 314 315 // String converts the key into a human-readable string format. 316 func (k *SkipLB6Key) String() string { 317 return fmt.Sprintf("[%d]:%d, %d", k.NetnsCookie, k.Address, k.Port) 318 } 319 320 func (v *SkipLB6Value) New() bpf.MapValue { return &SkipLB6Value{} } 321 322 // String converts the value into a human-readable string format. 323 func (v *SkipLB6Value) String() string { 324 return "" 325 } 326 327 // NewValue returns a new empty instance of the structure representing the BPF 328 // map value 329 func (k *SkipLB6Key) NewValue() bpf.MapValue { return &SkipLB6Value{} } 330 331 type skipLBMap struct { 332 bpfMap4 *ebpf.Map 333 bpfMap6 *ebpf.Map 334 }