github.com/sagernet/gvisor@v0.0.0-20240428053021-e691de28565f/pkg/bpf/input_bytes.go (about) 1 // Copyright 2018 The gVisor Authors. 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 package bpf 16 17 import ( 18 "encoding/binary" 19 ) 20 21 // Input represents a source of input data for a BPF program. (BPF 22 // documentation sometimes refers to the input data as the "packet" due to its 23 // origins as a packet processing DSL.) 24 // Unaligned loads are supported. 25 type Input []byte 26 27 // These type definitions must have different GC shapes to ensure that 28 // the Go compiler generates distinct code paths for them. 29 // These do not have anything to do with the bit sizes of the loads 30 // later on; all that matters is that these types have distinct sizes 31 // from one another. 32 type ( 33 // BigEndian uses big-endian byte ordering. 34 BigEndian uint8 35 36 // LittleEndian uses little-endian byte ordering. 37 LittleEndian uint16 38 39 // NativeEndian uses native byte ordering. 40 NativeEndian uint32 41 ) 42 43 // Endianness represents a byte order. 44 type Endianness interface { 45 BigEndian | LittleEndian | NativeEndian 46 } 47 48 // load32 loads a 32-bit value. 49 // 50 //go:nosplit 51 func load32[endian Endianness](in Input, off uint32) (uint32, bool) { 52 if uint64(off)+4 > uint64(len(in)) { 53 return 0, false 54 } 55 // Casting to any is needed here to avoid a compilation error: 56 // https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#why-not-permit-type-assertions-on-values-whose-type-is-a-type-parameter 57 var e endian 58 switch any(e).(type) { 59 case BigEndian: 60 return binary.BigEndian.Uint32(in[int(off):]), true 61 case LittleEndian: 62 return binary.LittleEndian.Uint32(in[int(off):]), true 63 case NativeEndian: 64 return binary.NativeEndian.Uint32(in[int(off):]), true 65 default: 66 panic("unreachable") 67 } 68 } 69 70 // load16 loads a 16-bit value. 71 // 72 //go:nosplit 73 func load16[endian Endianness](in Input, off uint32) (uint16, bool) { 74 if uint64(off)+2 > uint64(len(in)) { 75 return 0, false 76 } 77 // Casting to any is needed here to avoid a compilation error: 78 // https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#why-not-permit-type-assertions-on-values-whose-type-is-a-type-parameter 79 var e endian 80 switch any(e).(type) { 81 case BigEndian: 82 return binary.BigEndian.Uint16(in[int(off):]), true 83 case LittleEndian: 84 return binary.LittleEndian.Uint16(in[int(off):]), true 85 case NativeEndian: 86 return binary.NativeEndian.Uint16(in[int(off):]), true 87 default: 88 panic("unreachable") 89 } 90 } 91 92 // load8 loads a single byte. 93 // 94 //go:nosplit 95 func load8(in Input, off uint32) (uint8, bool) { 96 if uint64(off)+1 > uint64(len(in)) { 97 return 0, false 98 } 99 return in[int(off)], true 100 }