github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/map_xsk.go (about) 1 package gobpfld 2 3 import ( 4 "fmt" 5 "unsafe" 6 7 "github.com/dylandreimerink/gobpfld/bpfsys" 8 "github.com/dylandreimerink/gobpfld/bpftypes" 9 ) 10 11 var _ BPFMap = (*XSKMap)(nil) 12 13 // XSKMap is a specialized map type designed to work in conjunction with XSKSocket's. 14 type XSKMap struct { 15 AbstractMap 16 17 // we record the pointers to the XSKSockets seperatly since the kernel doesn't 18 // allow us to 'get' from the map after setting values 19 userspaceMap map[uint32]*XSKSocket 20 } 21 22 func (m *XSKMap) Load() error { 23 if m.Definition.Type != bpftypes.BPF_MAP_TYPE_XSKMAP { 24 return fmt.Errorf("map type in definition must be BPF_MAP_TYPE_XSKMAP when using an XSKMap") 25 } 26 27 m.userspaceMap = make(map[uint32]*XSKSocket) 28 err := m.load(nil) 29 if err != nil { 30 return err 31 } 32 33 err = mapRegister.add(m) 34 if err != nil { 35 return fmt.Errorf("map register: %w", err) 36 } 37 38 return nil 39 } 40 41 // Close closes the file descriptor associate with the map, this will cause the map to unload from the kernel 42 // if it is not still in use by a eBPF program, bpf FS, or a userspace program still holding a fd to the map. 43 func (m *XSKMap) Close() error { 44 err := mapRegister.delete(m) 45 if err != nil { 46 return fmt.Errorf("map register: %w", err) 47 } 48 49 return m.close() 50 } 51 52 // Get performs a lookup in the xskmap based on the key and returns the file descriptor of the socket 53 func (m *XSKMap) Get(key uint32) (*XSKSocket, error) { 54 if !m.loaded { 55 return nil, fmt.Errorf("can't read from an unloaded map") 56 } 57 58 return m.userspaceMap[key], nil 59 } 60 61 func (m *XSKMap) Set(key uint32, value *XSKSocket) error { 62 if !m.loaded { 63 return fmt.Errorf("can't write to an unloaded map") 64 } 65 66 if value == nil { 67 return fmt.Errorf("can't write a nil socket to the map") 68 } 69 70 attr := &bpfsys.BPFAttrMapElem{ 71 MapFD: m.fd, 72 Key: uintptr(unsafe.Pointer(&key)), 73 Value_NextKey: uintptr(unsafe.Pointer(&value.fd)), 74 } 75 76 err := bpfsys.MapUpdateElem(attr) 77 if err != nil { 78 return fmt.Errorf("bpf syscall error: %w", err) 79 } 80 81 m.userspaceMap[key] = value 82 83 return nil 84 } 85 86 func (m *XSKMap) Delete(key uint32) error { 87 if !m.loaded { 88 return fmt.Errorf("can't delete elements in an unloaded map") 89 } 90 91 attr := &bpfsys.BPFAttrMapElem{ 92 MapFD: m.fd, 93 Key: uintptr(unsafe.Pointer(&key)), 94 } 95 96 err := bpfsys.MapDeleteElem(attr) 97 if err != nil { 98 return fmt.Errorf("bpf syscall error: %w", err) 99 } 100 101 delete(m.userspaceMap, key) 102 103 return nil 104 } 105 106 func (m *XSKMap) Iterator() MapIterator { 107 return &XSKIterator{ 108 xskMap: m, 109 } 110 } 111 112 type XSKIterator struct { 113 xskMap *XSKMap 114 115 key *uint32 116 value **XSKSocket 117 118 keyArray []uint32 119 index int 120 121 done bool 122 } 123 124 func (xi *XSKIterator) Init(key, value interface{}) error { 125 var ok bool 126 xi.key, ok = key.(*uint32) 127 if !ok { 128 return fmt.Errorf("key must be a pointer to a uint32") 129 } 130 131 xi.value, ok = value.(**XSKSocket) 132 if !ok { 133 return fmt.Errorf("key must be a double pointer to a gobpfld.XSKSocket") 134 } 135 136 for key := range xi.xskMap.userspaceMap { 137 xi.keyArray = append(xi.keyArray, key) 138 } 139 140 return nil 141 } 142 143 // Next gets the key and value at the current location and writes them to the pointers given to the iterator 144 // during initialization. It then advances the internal pointer to the next key and value. 145 // If the iterator can't get the key and value at the current location since we are done iterating or an error 146 // was encountered 'updated' is false. 147 func (xi *XSKIterator) Next() (updated bool, err error) { 148 // TODO change iterator so we do use the next_key syscall but lookup the value using the userspace map 149 if xi.done { 150 return false, fmt.Errorf("iterator is done") 151 } 152 153 if len(xi.keyArray) == 0 { 154 xi.done = true 155 return false, nil 156 } 157 158 if xi.index >= len(xi.keyArray) { 159 xi.done = true 160 return false, nil 161 } 162 163 key := xi.keyArray[uint32(xi.index)] 164 value := xi.xskMap.userspaceMap[key] 165 166 *xi.key = key 167 *xi.value = value 168 169 xi.index++ 170 171 return true, nil 172 }