github.com/cilium/cilium@v1.16.2/pkg/maps/lbmap/maglev.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package lbmap 5 6 import ( 7 "errors" 8 "fmt" 9 "os" 10 11 "github.com/cilium/cilium/pkg/bpf" 12 "github.com/cilium/cilium/pkg/ebpf" 13 "github.com/cilium/cilium/pkg/loadbalancer" 14 ) 15 16 const ( 17 // Both outer maps are pinned though given we need to insert 18 // inner maps into them. 19 MaglevOuter4MapName = "cilium_lb4_maglev" 20 MaglevOuter6MapName = "cilium_lb6_maglev" 21 ) 22 23 var ( 24 maglevOuter4Map *MaglevOuterMap 25 maglevOuter6Map *MaglevOuterMap 26 maglevRecreatedIPv4 bool 27 maglevRecreatedIPv6 bool 28 maglevTableSize uint32 29 ) 30 31 // InitMaglevMaps inits the ipv4 and/or ipv6 maglev outer and inner maps. 32 func InitMaglevMaps(ipv4, ipv6 bool, tableSize uint32) error { 33 // Always try to delete old maps with the wrong M parameter, otherwise 34 // we may end up in a case where there are 2 maps (one for IPv4 and 35 // one for IPv6), one of which is not used, with 2 different table 36 // sizes. 37 // This would confuse the MaybeInitMaglevMaps() function, which would 38 // not be able to figure out the correct table size. 39 r, err := deleteMapIfMNotMatch(MaglevOuter4MapName, tableSize) 40 if err != nil { 41 return err 42 } 43 maglevRecreatedIPv4 = r 44 45 r, err = deleteMapIfMNotMatch(MaglevOuter6MapName, tableSize) 46 if err != nil { 47 return err 48 } 49 maglevRecreatedIPv6 = r 50 51 dummyInnerMapSpec := newMaglevInnerMapSpec(tableSize) 52 if ipv4 { 53 outer, err := NewMaglevOuterMap(MaglevOuter4MapName, MaglevMapMaxEntries, tableSize, dummyInnerMapSpec) 54 if err != nil { 55 return err 56 } 57 maglevOuter4Map = outer 58 } 59 60 if ipv6 { 61 outer, err := NewMaglevOuterMap(MaglevOuter6MapName, MaglevMapMaxEntries, tableSize, dummyInnerMapSpec) 62 if err != nil { 63 return err 64 } 65 maglevOuter6Map = outer 66 } 67 68 maglevTableSize = tableSize 69 70 return nil 71 } 72 73 // deleteMapIfMNotMatch removes the outer maglev maps if it's a legacy map or 74 // the M param (MaglevTableSize) has changed. This is to avoid a verifier 75 // error when loading BPF programs which access the map. 76 func deleteMapIfMNotMatch(mapName string, tableSize uint32) (bool, error) { 77 m, err := ebpf.LoadPinnedMap(bpf.MapPath(mapName)) 78 if errors.Is(err, os.ErrNotExist) { 79 // No existing maglev outer map found. 80 // Return true so the caller will create a new one. 81 return true, nil 82 } 83 if err != nil { 84 return false, err 85 } 86 defer m.Close() 87 88 // Attempt to determine the outer map's table size. 89 size, err := (&MaglevOuterMap{Map: m}).TableSize() 90 if err == nil && size == tableSize { 91 // An outer map with the correct table size already exists. 92 // Return false as there no need to delete and recreate it. 93 return false, nil 94 } 95 96 // An outer map already exists but it has the wrong table size (or we 97 // can't determine it). Delete it. 98 if err := m.Unpin(); err != nil { 99 return false, fmt.Errorf("error unpinning existing outer map: %w", err) 100 } 101 102 return true, nil 103 } 104 105 // updateMaglevTable creates a new inner Maglev map containing the given backend IDs 106 // and sets it as the active lookup table for the given service ID. 107 func updateMaglevTable(ipv6 bool, revNATID uint16, backendIDs []loadbalancer.BackendID) error { 108 outer := maglevOuter4Map 109 if ipv6 { 110 outer = maglevOuter6Map 111 } 112 113 if outer == nil { 114 return errors.New("outer maglev maps not yet initialized") 115 } 116 117 inner, err := createMaglevInnerMap(maglevTableSize) 118 if err != nil { 119 return err 120 } 121 defer inner.Close() 122 123 if err := inner.UpdateBackends(backendIDs); err != nil { 124 return fmt.Errorf("updating backends: %w", err) 125 } 126 127 if err := outer.UpdateService(revNATID, inner); err != nil { 128 return fmt.Errorf("updating service: %w", err) 129 } 130 131 return nil 132 } 133 134 // deleteMaglevTable deletes the inner Maglev lookup table for the given service ID. 135 func deleteMaglevTable(ipv6 bool, revNATID uint16) error { 136 outerMap := maglevOuter4Map 137 if ipv6 { 138 outerMap = maglevOuter6Map 139 } 140 141 outerKey := MaglevOuterKey{RevNatID: revNATID} 142 if err := outerMap.Delete(outerKey.toNetwork()); err != nil { 143 return err 144 } 145 146 return nil 147 }