syscalls.go (5928B)
1 package ebpf 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 "github.com/cilium/ebpf/asm" 9 "github.com/cilium/ebpf/internal" 10 "github.com/cilium/ebpf/internal/sys" 11 "github.com/cilium/ebpf/internal/unix" 12 ) 13 14 // invalidBPFObjNameChar returns true if char may not appear in 15 // a BPF object name. 16 func invalidBPFObjNameChar(char rune) bool { 17 dotAllowed := objNameAllowsDot() == nil 18 19 switch { 20 case char >= 'A' && char <= 'Z': 21 return false 22 case char >= 'a' && char <= 'z': 23 return false 24 case char >= '0' && char <= '9': 25 return false 26 case dotAllowed && char == '.': 27 return false 28 case char == '_': 29 return false 30 default: 31 return true 32 } 33 } 34 35 func progLoad(insns asm.Instructions, typ ProgramType, license string) (*sys.FD, error) { 36 buf := bytes.NewBuffer(make([]byte, 0, insns.Size())) 37 if err := insns.Marshal(buf, internal.NativeEndian); err != nil { 38 return nil, err 39 } 40 bytecode := buf.Bytes() 41 42 return sys.ProgLoad(&sys.ProgLoadAttr{ 43 ProgType: sys.ProgType(typ), 44 License: sys.NewStringPointer(license), 45 Insns: sys.NewSlicePointer(bytecode), 46 InsnCnt: uint32(len(bytecode) / asm.InstructionSize), 47 }) 48 } 49 50 var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() error { 51 _, err := sys.MapCreate(&sys.MapCreateAttr{ 52 MapType: sys.MapType(ArrayOfMaps), 53 KeySize: 4, 54 ValueSize: 4, 55 MaxEntries: 1, 56 // Invalid file descriptor. 57 InnerMapFd: ^uint32(0), 58 }) 59 if errors.Is(err, unix.EINVAL) { 60 return internal.ErrNotSupported 61 } 62 if errors.Is(err, unix.EBADF) { 63 return nil 64 } 65 return err 66 }) 67 68 var haveMapMutabilityModifiers = internal.FeatureTest("read- and write-only maps", "5.2", func() error { 69 // This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since 70 // BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check. 71 m, err := sys.MapCreate(&sys.MapCreateAttr{ 72 MapType: sys.MapType(Array), 73 KeySize: 4, 74 ValueSize: 4, 75 MaxEntries: 1, 76 MapFlags: unix.BPF_F_RDONLY_PROG, 77 }) 78 if err != nil { 79 return internal.ErrNotSupported 80 } 81 _ = m.Close() 82 return nil 83 }) 84 85 var haveMmapableMaps = internal.FeatureTest("mmapable maps", "5.5", func() error { 86 // This checks BPF_F_MMAPABLE, which appeared in 5.5 for array maps. 87 m, err := sys.MapCreate(&sys.MapCreateAttr{ 88 MapType: sys.MapType(Array), 89 KeySize: 4, 90 ValueSize: 4, 91 MaxEntries: 1, 92 MapFlags: unix.BPF_F_MMAPABLE, 93 }) 94 if err != nil { 95 return internal.ErrNotSupported 96 } 97 _ = m.Close() 98 return nil 99 }) 100 101 var haveInnerMaps = internal.FeatureTest("inner maps", "5.10", func() error { 102 // This checks BPF_F_INNER_MAP, which appeared in 5.10. 103 m, err := sys.MapCreate(&sys.MapCreateAttr{ 104 MapType: sys.MapType(Array), 105 KeySize: 4, 106 ValueSize: 4, 107 MaxEntries: 1, 108 MapFlags: unix.BPF_F_INNER_MAP, 109 }) 110 if err != nil { 111 return internal.ErrNotSupported 112 } 113 _ = m.Close() 114 return nil 115 }) 116 117 var haveNoPreallocMaps = internal.FeatureTest("prealloc maps", "4.6", func() error { 118 // This checks BPF_F_NO_PREALLOC, which appeared in 4.6. 119 m, err := sys.MapCreate(&sys.MapCreateAttr{ 120 MapType: sys.MapType(Hash), 121 KeySize: 4, 122 ValueSize: 4, 123 MaxEntries: 1, 124 MapFlags: unix.BPF_F_NO_PREALLOC, 125 }) 126 if err != nil { 127 return internal.ErrNotSupported 128 } 129 _ = m.Close() 130 return nil 131 }) 132 133 func wrapMapError(err error) error { 134 if err == nil { 135 return nil 136 } 137 138 if errors.Is(err, unix.ENOENT) { 139 return sys.Error(ErrKeyNotExist, unix.ENOENT) 140 } 141 142 if errors.Is(err, unix.EEXIST) { 143 return sys.Error(ErrKeyExist, unix.EEXIST) 144 } 145 146 if errors.Is(err, unix.ENOTSUPP) { 147 return sys.Error(ErrNotSupported, unix.ENOTSUPP) 148 } 149 150 if errors.Is(err, unix.E2BIG) { 151 return fmt.Errorf("key too big for map: %w", err) 152 } 153 154 return err 155 } 156 157 var haveObjName = internal.FeatureTest("object names", "4.15", func() error { 158 attr := sys.MapCreateAttr{ 159 MapType: sys.MapType(Array), 160 KeySize: 4, 161 ValueSize: 4, 162 MaxEntries: 1, 163 MapName: sys.NewObjName("feature_test"), 164 } 165 166 fd, err := sys.MapCreate(&attr) 167 if err != nil { 168 return internal.ErrNotSupported 169 } 170 171 _ = fd.Close() 172 return nil 173 }) 174 175 var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func() error { 176 if err := haveObjName(); err != nil { 177 return err 178 } 179 180 attr := sys.MapCreateAttr{ 181 MapType: sys.MapType(Array), 182 KeySize: 4, 183 ValueSize: 4, 184 MaxEntries: 1, 185 MapName: sys.NewObjName(".test"), 186 } 187 188 fd, err := sys.MapCreate(&attr) 189 if err != nil { 190 return internal.ErrNotSupported 191 } 192 193 _ = fd.Close() 194 return nil 195 }) 196 197 var haveBatchAPI = internal.FeatureTest("map batch api", "5.6", func() error { 198 var maxEntries uint32 = 2 199 attr := sys.MapCreateAttr{ 200 MapType: sys.MapType(Hash), 201 KeySize: 4, 202 ValueSize: 4, 203 MaxEntries: maxEntries, 204 } 205 206 fd, err := sys.MapCreate(&attr) 207 if err != nil { 208 return internal.ErrNotSupported 209 } 210 defer fd.Close() 211 212 keys := []uint32{1, 2} 213 values := []uint32{3, 4} 214 kp, _ := marshalPtr(keys, 8) 215 vp, _ := marshalPtr(values, 8) 216 217 err = sys.MapUpdateBatch(&sys.MapUpdateBatchAttr{ 218 MapFd: fd.Uint(), 219 Keys: kp, 220 Values: vp, 221 Count: maxEntries, 222 }) 223 if err != nil { 224 return internal.ErrNotSupported 225 } 226 return nil 227 }) 228 229 var haveProbeReadKernel = internal.FeatureTest("bpf_probe_read_kernel", "5.5", func() error { 230 insns := asm.Instructions{ 231 asm.Mov.Reg(asm.R1, asm.R10), 232 asm.Add.Imm(asm.R1, -8), 233 asm.Mov.Imm(asm.R2, 8), 234 asm.Mov.Imm(asm.R3, 0), 235 asm.FnProbeReadKernel.Call(), 236 asm.Return(), 237 } 238 239 fd, err := progLoad(insns, Kprobe, "GPL") 240 if err != nil { 241 return internal.ErrNotSupported 242 } 243 _ = fd.Close() 244 return nil 245 }) 246 247 var haveBPFToBPFCalls = internal.FeatureTest("bpf2bpf calls", "4.16", func() error { 248 insns := asm.Instructions{ 249 asm.Call.Label("prog2").WithSymbol("prog1"), 250 asm.Return(), 251 asm.Mov.Imm(asm.R0, 0).WithSymbol("prog2"), 252 asm.Return(), 253 } 254 255 fd, err := progLoad(insns, SocketFilter, "MIT") 256 if errors.Is(err, unix.EINVAL) { 257 return internal.ErrNotSupported 258 } 259 if err != nil { 260 return err 261 } 262 _ = fd.Close() 263 return nil 264 })