2023-01-23 18:54:21 +07:00
|
|
|
/*
|
|
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
2023-01-28 12:56:06 +07:00
|
|
|
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
2023-01-23 18:54:21 +07:00
|
|
|
*/
|
|
|
|
|
|
|
|
package control
|
|
|
|
|
|
|
|
import (
|
2023-01-29 06:31:52 +07:00
|
|
|
"encoding/binary"
|
2023-01-28 12:27:54 +07:00
|
|
|
"fmt"
|
2023-01-23 18:54:21 +07:00
|
|
|
"github.com/cilium/ebpf"
|
2023-01-24 15:27:19 +07:00
|
|
|
"github.com/v2rayA/dae/common"
|
2023-01-28 12:27:54 +07:00
|
|
|
"github.com/v2rayA/dae/pkg/ebpf_internal"
|
2023-01-23 18:54:21 +07:00
|
|
|
"net/netip"
|
2023-01-28 12:27:54 +07:00
|
|
|
"reflect"
|
2023-01-23 18:54:21 +07:00
|
|
|
)
|
|
|
|
|
2023-01-28 10:47:02 +07:00
|
|
|
type _bpfLpmKey struct {
|
2023-01-23 18:54:21 +07:00
|
|
|
PrefixLen uint32
|
|
|
|
Data [4]uint32
|
|
|
|
}
|
|
|
|
|
2023-01-29 06:31:52 +07:00
|
|
|
type _bpfPortRange struct {
|
|
|
|
PortStart uint16
|
|
|
|
PortEnd uint16
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r _bpfPortRange) Encode() uint32 {
|
|
|
|
var b [4]byte
|
2023-01-29 10:19:58 +07:00
|
|
|
binary.BigEndian.PutUint16(b[:2], r.PortStart)
|
|
|
|
binary.BigEndian.PutUint16(b[2:], r.PortEnd)
|
2023-01-29 06:31:52 +07:00
|
|
|
return binary.BigEndian.Uint32(b[:])
|
|
|
|
}
|
|
|
|
|
2023-01-28 10:47:02 +07:00
|
|
|
func (o *bpfObjects) newLpmMap(keys []_bpfLpmKey, values []uint32) (m *ebpf.Map, err error) {
|
2023-01-24 15:27:19 +07:00
|
|
|
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(),
|
|
|
|
})
|
2023-01-23 18:54:21 +07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-01-28 12:27:54 +07:00
|
|
|
if _, err = BatchUpdate(m, keys, values, &ebpf.BatchOptions{
|
2023-01-23 18:54:21 +07:00
|
|
|
ElemFlags: uint64(ebpf.UpdateAny),
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return m, nil
|
|
|
|
}
|
|
|
|
|
2023-01-28 10:47:02 +07:00
|
|
|
func cidrToBpfLpmKey(prefix netip.Prefix) _bpfLpmKey {
|
2023-01-23 18:54:21 +07:00
|
|
|
bits := prefix.Bits()
|
|
|
|
if prefix.Addr().Is4() {
|
|
|
|
bits += 96
|
|
|
|
}
|
2023-01-24 15:27:19 +07:00
|
|
|
ip := prefix.Addr().As16()
|
2023-01-28 10:47:02 +07:00
|
|
|
return _bpfLpmKey{
|
2023-01-23 18:54:21 +07:00
|
|
|
PrefixLen: uint32(bits),
|
|
|
|
Data: common.Ipv6ByteSliceToUint32Array(ip[:]),
|
|
|
|
}
|
|
|
|
}
|
2023-01-28 12:27:54 +07:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|