Rewrite bpf spec before loading to avoid bpf map lookup during runtime (#376)

This commit is contained in:
/gray 2024-01-01 17:20:28 +08:00 committed by GitHub
parent fa69b4cbe8
commit e7c4473da1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 45 deletions

View File

@ -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 "

View File

@ -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

View File

@ -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(&param_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(&param_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(&param_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 *)&ethh.h_source[4]);
if (*(__u32 *)&ethh.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(&param_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(&param_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;
}