mirror of
https://github.com/daeuniverse/dae.git
synced 2025-02-02 04:14:31 +07:00
Rewrite bpf spec before loading to avoid bpf map lookup during runtime (#376)
This commit is contained in:
parent
fa69b4cbe8
commit
e7c4473da1
@ -195,8 +195,20 @@ func (p bpfIfParams) CheckVersionRequirement(version *internal.Version) (err err
|
||||
}
|
||||
|
||||
type loadBpfOptions struct {
|
||||
PinPath string
|
||||
CollectionOptions *ebpf.CollectionOptions
|
||||
PinPath string
|
||||
BigEndianTproxyPort uint32
|
||||
CollectionOptions *ebpf.CollectionOptions
|
||||
}
|
||||
|
||||
func loadBpfObjectsWithConstants(obj interface{}, opts *ebpf.CollectionOptions, constants map[string]interface{}) error {
|
||||
spec, err := loadBpf()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := spec.RewriteConstants(constants); err != nil {
|
||||
return err
|
||||
}
|
||||
return spec.LoadAndAssign(obj, opts)
|
||||
}
|
||||
|
||||
func fullLoadBpfObjects(
|
||||
@ -205,7 +217,16 @@ func fullLoadBpfObjects(
|
||||
opts *loadBpfOptions,
|
||||
) (err error) {
|
||||
retryLoadBpf:
|
||||
if err = loadBpfObjects(bpf, opts.CollectionOptions); err != nil {
|
||||
constants := map[string]interface{}{
|
||||
"PARAM": struct {
|
||||
tproxyPort uint32
|
||||
controlPlanePid uint32
|
||||
}{
|
||||
tproxyPort: uint32(opts.BigEndianTproxyPort),
|
||||
controlPlanePid: uint32(os.Getpid()),
|
||||
},
|
||||
}
|
||||
if err = loadBpfObjectsWithConstants(bpf, opts.CollectionOptions, constants); err != nil {
|
||||
if errors.Is(err, ebpf.ErrMapIncompatible) {
|
||||
// Map property is incompatible. Remove the old map and try again.
|
||||
prefix := "use pinned map "
|
||||
|
@ -165,8 +165,9 @@ func NewControlPlane(
|
||||
} else {
|
||||
bpf = new(bpfObjects)
|
||||
if err = fullLoadBpfObjects(log, bpf, &loadBpfOptions{
|
||||
PinPath: pinPath,
|
||||
CollectionOptions: collectionOpts,
|
||||
PinPath: pinPath,
|
||||
BigEndianTproxyPort: uint32(common.Htons(global.TproxyPort)),
|
||||
CollectionOptions: collectionOpts,
|
||||
}); err != nil {
|
||||
if log.Level == logrus.PanicLevel {
|
||||
log.Panicln(err)
|
||||
@ -192,11 +193,6 @@ func NewControlPlane(
|
||||
}
|
||||
}()
|
||||
|
||||
// Write params.
|
||||
if err = core.bpf.ParamMap.Update(consts.ControlPlanePidKey, uint32(os.Getpid()), ebpf.UpdateAny); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/// Bind to links. Binding should be advance of dialerGroups to avoid un-routable old connection.
|
||||
// Bind to LAN
|
||||
if len(global.LanInterface) > 0 {
|
||||
@ -685,10 +681,6 @@ func (c *ControlPlane) Serve(readyChan chan<- bool, listener *Listener) (err err
|
||||
if err := c.core.bpf.ListenSocketMap.Update(consts.OneKey, uint64(udpFile.Fd()), ebpf.UpdateAny); err != nil {
|
||||
return err
|
||||
}
|
||||
// Port.
|
||||
if err := c.core.bpf.ParamMap.Update(consts.BigEndianTproxyPortKey, uint32(common.Htons(listener.port)), ebpf.UpdateAny); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sentReady = true
|
||||
readyChan <- true
|
||||
|
@ -83,17 +83,7 @@ enum {
|
||||
|
||||
// Param keys:
|
||||
static const __u32 zero_key = 0;
|
||||
static const __u32 tproxy_port_key = 1;
|
||||
static const __u32 one_key = 1;
|
||||
static const __u32 disable_l4_tx_checksum_key
|
||||
__attribute__((unused, deprecated)) = 2;
|
||||
static const __u32 disable_l4_rx_checksum_key
|
||||
__attribute__((unused, deprecated)) = 3;
|
||||
static const __u32 control_plane_pid_key = 4;
|
||||
static const __u32 control_plane_nat_direct_key
|
||||
__attribute__((unused, deprecated)) = 5;
|
||||
static const __u32 control_plane_dns_routing_key
|
||||
__attribute__((unused, deprecated)) = 6;
|
||||
|
||||
// Outbound Connectivity Map:
|
||||
|
||||
@ -163,6 +153,13 @@ struct tuples {
|
||||
__u8 dscp;
|
||||
};
|
||||
|
||||
struct dae_param {
|
||||
__u32 tproxy_port;
|
||||
__u32 control_plane_pid;
|
||||
};
|
||||
|
||||
static volatile const struct dae_param PARAM = {};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||
__type(key,
|
||||
@ -196,15 +193,6 @@ struct {
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} routing_tuples_map SEC(".maps");
|
||||
|
||||
// Params:
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
__uint(max_entries, MAX_PARAM_LEN);
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} param_map SEC(".maps");
|
||||
|
||||
// Link to type:
|
||||
#define LinkType_None 0
|
||||
#define LinkType_Ethernet 1
|
||||
@ -1279,13 +1267,13 @@ int tproxy_lan_egress(struct __sk_buff *skb) {
|
||||
return TC_ACT_PIPE;
|
||||
}
|
||||
|
||||
__be16 *tproxy_port = bpf_map_lookup_elem(¶m_map, &tproxy_port_key);
|
||||
__be16 tproxy_port = PARAM.tproxy_port;
|
||||
if (!tproxy_port) {
|
||||
return TC_ACT_PIPE;
|
||||
}
|
||||
struct tuples tuples;
|
||||
get_tuples(skb, &tuples, &iph, &ipv6h, &tcph, &udph, l4proto);
|
||||
if (*tproxy_port != tuples.five.sport) {
|
||||
if (tproxy_port != tuples.five.sport) {
|
||||
return TC_ACT_PIPE;
|
||||
}
|
||||
|
||||
@ -1540,13 +1528,12 @@ static __always_inline bool pid_is_control_plane(struct __sk_buff *skb,
|
||||
*p = pid_pname;
|
||||
}
|
||||
// Get tproxy pid and compare if they are equal.
|
||||
__u32 *pid_tproxy;
|
||||
if (!(pid_tproxy =
|
||||
bpf_map_lookup_elem(¶m_map, &control_plane_pid_key))) {
|
||||
__u32 pid_tproxy;
|
||||
if (!(pid_tproxy = PARAM.control_plane_pid)) {
|
||||
bpf_printk("control_plane_pid is not set.");
|
||||
return false;
|
||||
}
|
||||
return pid_pname->pid == *pid_tproxy;
|
||||
return pid_pname->pid == pid_tproxy;
|
||||
} else {
|
||||
if (p) {
|
||||
*p = NULL;
|
||||
@ -1621,11 +1608,11 @@ int tproxy_wan_egress(struct __sk_buff *skb) {
|
||||
// We should know if this packet is from tproxy.
|
||||
// We do not need to check the source ip because we have skipped packets not
|
||||
// from localhost.
|
||||
__be16 *tproxy_port = bpf_map_lookup_elem(¶m_map, &tproxy_port_key);
|
||||
__be16 tproxy_port = PARAM.tproxy_port;
|
||||
if (!tproxy_port) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
bool tproxy_response = *tproxy_port == tuples.five.sport;
|
||||
bool tproxy_response = tproxy_port == tuples.five.sport;
|
||||
// Double check to avoid conflicts when binding wan and lan to the same
|
||||
// interface.
|
||||
if (tproxy_response && l4proto == IPPROTO_TCP) {
|
||||
@ -1965,11 +1952,11 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
|
||||
__u16 tproxy_typ = bpf_ntohs(*(__u16 *)ðh.h_source[4]);
|
||||
if (*(__u32 *)ðh.h_source[0] != bpf_htonl(0x02000203) || tproxy_typ > 1) {
|
||||
// Check for security. Reject packets that is UDP and sent to tproxy port.
|
||||
__be16 *tproxy_port = bpf_map_lookup_elem(¶m_map, &tproxy_port_key);
|
||||
__be16 tproxy_port = PARAM.tproxy_port;
|
||||
if (!tproxy_port) {
|
||||
goto accept;
|
||||
}
|
||||
if (unlikely(*tproxy_port == tuples.five.dport)) {
|
||||
if (unlikely(tproxy_port == tuples.five.dport)) {
|
||||
struct bpf_sock_tuple tuple = {0};
|
||||
__u32 tuple_size;
|
||||
|
||||
@ -2103,7 +2090,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
|
||||
// saddr should be tproxy ip.
|
||||
__be32 *tproxy_ip = tuples.five.sip.u6_addr32;
|
||||
// __builtin_memcpy(tproxy_ip, saddr, sizeof(tproxy_ip));
|
||||
__be16 *tproxy_port = bpf_map_lookup_elem(¶m_map, &tproxy_port_key);
|
||||
__be16 tproxy_port = PARAM.tproxy_port;
|
||||
if (!tproxy_port) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
@ -2118,7 +2105,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) {
|
||||
|
||||
// Rewrite dst port.
|
||||
if ((ret = rewrite_port(skb, link_h_len, l4proto, ihl, tuples.five.dport,
|
||||
*tproxy_port, true, true))) {
|
||||
tproxy_port, true, true))) {
|
||||
bpf_printk("Shot Port: %d", ret);
|
||||
return TC_ACT_SHOT;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user