dae/component/control/bpf_utils.go
2023-01-29 11:19:58 +08:00

102 lines
2.3 KiB
Go

/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
*/
package control
import (
"encoding/binary"
"fmt"
"github.com/cilium/ebpf"
"github.com/v2rayA/dae/common"
"github.com/v2rayA/dae/pkg/ebpf_internal"
"net/netip"
"reflect"
)
type _bpfLpmKey struct {
PrefixLen uint32
Data [4]uint32
}
type _bpfPortRange struct {
PortStart uint16
PortEnd uint16
}
func (r _bpfPortRange) Encode() uint32 {
var b [4]byte
binary.BigEndian.PutUint16(b[:2], r.PortStart)
binary.BigEndian.PutUint16(b[2:], r.PortEnd)
return binary.BigEndian.Uint32(b[:])
}
func (o *bpfObjects) newLpmMap(keys []_bpfLpmKey, values []uint32) (m *ebpf.Map, err error) {
m, err = ebpf.NewMap(&ebpf.MapSpec{
Type: ebpf.LPMTrie,
Flags: o.UnusedLpmType.Flags(),
MaxEntries: o.UnusedLpmType.MaxEntries(),
KeySize: o.UnusedLpmType.KeySize(),
ValueSize: o.UnusedLpmType.ValueSize(),
})
if err != nil {
return nil, err
}
if _, err = BatchUpdate(m, keys, values, &ebpf.BatchOptions{
ElemFlags: uint64(ebpf.UpdateAny),
}); err != nil {
return nil, err
}
return m, nil
}
func swap16(a uint16) uint16 {
return (a >> 8) + ((a & 0xFF) << 8)
}
func cidrToBpfLpmKey(prefix netip.Prefix) _bpfLpmKey {
bits := prefix.Bits()
if prefix.Addr().Is4() {
bits += 96
}
ip := prefix.Addr().As16()
return _bpfLpmKey{
PrefixLen: uint32(bits),
Data: common.Ipv6ByteSliceToUint32Array(ip[:]),
}
}
func BatchUpdate(m *ebpf.Map, keys interface{}, values interface{}, opts *ebpf.BatchOptions) (n int, err error) {
var old bool
version, e := internal.KernelVersion()
if e != nil || version.Less(internal.Version{5, 6, 0}) {
old = true
}
if !old {
return m.BatchUpdate(keys, values, opts)
} else {
vKeys := reflect.ValueOf(keys)
if vKeys.Kind() != reflect.Slice {
return 0, fmt.Errorf("keys must be slice")
}
vVals := reflect.ValueOf(values)
if vVals.Kind() != reflect.Slice {
return 0, fmt.Errorf("values must be slice")
}
length := vKeys.Len()
if vVals.Len() != length {
return 0, fmt.Errorf("keys and values must have same length")
}
for i := 0; i < length; i++ {
vKey := vKeys.Index(i)
vVal := vVals.Index(i)
if err = m.Update(vKey.Interface(), vVal.Interface(), ebpf.MapUpdateFlags(opts.ElemFlags)); err != nil {
return i, err
}
}
return vKeys.Len(), nil
}
}