From 2f0483eb34ae51dc0dc241409342db021b995856 Mon Sep 17 00:00:00 2001 From: sinanmohd Date: Fri, 5 Jul 2024 21:43:56 +0530 Subject: bpf: use hwaddr for identification --- bpf/bpf_bpfel.o | Bin 5312 -> 6592 bytes bpf/bpf_usage.c | 57 ++++++++++++++++++++++++++++++++++++++++++-------------- bpf/main.go | 27 ++++++++++++++++++--------- db/models.go | 6 +++--- db/query.sql.go | 6 +++--- db/schema.sql | 6 +++--- 6 files changed, 70 insertions(+), 32 deletions(-) diff --git a/bpf/bpf_bpfel.o b/bpf/bpf_bpfel.o index 789c00f..d9a44b4 100644 Binary files a/bpf/bpf_bpfel.o and b/bpf/bpf_bpfel.o differ diff --git a/bpf/bpf_usage.c b/bpf/bpf_usage.c index 5e505da..8b2343a 100644 --- a/bpf/bpf_usage.c +++ b/bpf/bpf_usage.c @@ -12,14 +12,14 @@ char __license[] SEC("license") = "GPL"; struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_MAP_ENTRIES); - __type(key, __u32); // source IPv4 address + __type(key, __u64); // source mac address __type(value, __u64); // no of bytes } ingress_ip4_usage_map SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_MAP_ENTRIES); - __type(key, __u32); // destination IPv4 address + __type(key, __u64); // destination mac address __type(value, __u64); // no of bytes } egress_ip4_usage_map SEC(".maps"); @@ -28,31 +28,60 @@ typedef enum { UPDATE_USAGE_EGRESS, } update_usage_t; +static __always_inline __u64 nchar6_to_u64(unsigned char bytes[6]) +{ + union { + char bytes[6]; + __u64 i; + } ret; + + ret.i = 0; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + ret.bytes[0] = bytes[5]; + ret.bytes[1] = bytes[4]; + ret.bytes[2] = bytes[3]; + ret.bytes[3] = bytes[2]; + ret.bytes[4] = bytes[1]; + ret.bytes[5] = bytes[0]; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + ret.bytes[0] = bytes[0]; + ret.bytes[1] = bytes[1]; + ret.bytes[2] = bytes[2]; + ret.bytes[3] = bytes[3]; + ret.bytes[4] = bytes[4]; + ret.bytes[5] = bytes[5]; +#endif + + return ret.i; +} + static __always_inline int update_usage(void *map, struct __sk_buff *skb, update_usage_t traffic) { - __u32 ip4; - __u64 len, *usage; + __u64 mac, len, *usage; void *data_end = (void *)(long)skb->data_end; - void *data = (void *)(long)skb->data; - struct iphdr *ip = data + sizeof(struct ethhdr); + struct ethhdr *eth = (void *)(long)skb->data; - if (skb->protocol != bpf_htons(ETH_P_IP)) + if ((void *) (eth + 1) > data_end) return TCX_PASS; - else if ((void *)(ip + 1) > data_end) + + if (skb->protocol != bpf_htons(ETH_P_IP) && + skb->protocol != bpf_htons(ETH_P_IPV6)) { return TCX_PASS; + } - if (traffic == UPDATE_USAGE_INGRESS) - ip4 = ip->saddr; - else - ip4 = ip->daddr; len = skb->len - sizeof(struct ethhdr); + if (traffic == UPDATE_USAGE_INGRESS) { + mac = nchar6_to_u64(eth->h_source); + } else { + mac = nchar6_to_u64(eth->h_dest); + } - usage = bpf_map_lookup_elem(map, &ip4); + usage = bpf_map_lookup_elem(map, &mac); if (!usage) { /* no entry in the map for this IP address yet. */ - bpf_map_update_elem(map, &ip4, &len, BPF_ANY); + bpf_map_update_elem(map, &mac, &len, BPF_ANY); } else { __sync_fetch_and_add(usage, len); } diff --git a/bpf/main.go b/bpf/main.go index 4f1360e..c436534 100644 --- a/bpf/main.go +++ b/bpf/main.go @@ -3,7 +3,6 @@ package bpf import ( "context" "errors" - "fmt" "log" "net" "time" @@ -20,7 +19,7 @@ type UsageStat struct { ingress uint64 egress uint64 } -type UsageMap map[uint32]UsageStat +type UsageMap map[uint64]UsageStat func Run(iface *net.Interface, queries *db.Queries, ctxDb context.Context) { usageMap := make(UsageMap) @@ -51,9 +50,9 @@ func Run(iface *net.Interface, queries *db.Queries, ctxDb context.Context) { } defer egressLink.Close() - bpfTicker := time.NewTicker(1 * time.Second) + bpfTicker := time.NewTicker(time.Second) defer bpfTicker.Stop() - dbTicker := time.NewTicker(60 * time.Second) + dbTicker := time.NewTicker(time.Minute) defer dbTicker.Stop() for { select { @@ -95,7 +94,7 @@ func (usageMap UsageMap) updateDb(queries *db.Queries, ctxDb context.Context) er } err := queries.EnterUsage(ctxDb, db.EnterUsageParams{ - Hardwareaddr: int32(key), + Hardwareaddr: int64(key), Starttime: pgtype.Timestamp{ Time: value.lastDbPush, Valid: true, @@ -104,8 +103,8 @@ func (usageMap UsageMap) updateDb(queries *db.Queries, ctxDb context.Context) er Time: value.lastSeen, Valid: true, }, - Egress: int32(value.egress), - Ingress: int32(value.ingress), + Egress: int64(value.egress), + Ingress: int64(value.ingress), }) if err != nil { return err @@ -119,14 +118,19 @@ func (usageMap UsageMap) updateDb(queries *db.Queries, ctxDb context.Context) er func (usageMap UsageMap) update(ingress *ebpf.Map, egress *ebpf.Map) error { timeStart := time.Now() - batchKeys := make([]uint32, 4096) + batchKeys := make([]uint64, 4096) batchValues := make([]uint64, 4096) - var key uint32 + var key uint64 cursor := ebpf.MapBatchCursor{} for { _, err := ingress.BatchLookupAndDelete(&cursor, batchKeys, batchValues, nil) for i := range batchKeys { + /* TODO: maybe BatchLookupAndDelete is not the best idea with mostly empty map */ + if batchValues[i] == 0 { + continue + } + key = batchKeys[i] usage, ok := usageMap[key] if ok { @@ -153,6 +157,11 @@ func (usageMap UsageMap) update(ingress *ebpf.Map, egress *ebpf.Map) error { for { _, err := egress.BatchLookupAndDelete(&cursor, batchKeys, batchValues, nil) for i := range batchKeys { + /* TODO: maybe BatchLookupAndDelete is not the best idea with mostly empty map */ + if batchValues[i] == 0 { + continue + } + key = batchKeys[i] usage, ok := usageMap[key] if ok { diff --git a/db/models.go b/db/models.go index 83e4051..a6da6bf 100644 --- a/db/models.go +++ b/db/models.go @@ -9,9 +9,9 @@ import ( ) type Usage struct { - Hardwareaddr int32 + Hardwareaddr int64 Starttime pgtype.Timestamp Stoptime pgtype.Timestamp - Egress int32 - Ingress int32 + Egress int64 + Ingress int64 } diff --git a/db/query.sql.go b/db/query.sql.go index de68384..7afe159 100644 --- a/db/query.sql.go +++ b/db/query.sql.go @@ -20,11 +20,11 @@ INSERT INTO Usage ( ` type EnterUsageParams struct { - Hardwareaddr int32 + Hardwareaddr int64 Starttime pgtype.Timestamp Stoptime pgtype.Timestamp - Egress int32 - Ingress int32 + Egress int64 + Ingress int64 } func (q *Queries) EnterUsage(ctx context.Context, arg EnterUsageParams) error { diff --git a/db/schema.sql b/db/schema.sql index b8f8540..aece061 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -1,7 +1,7 @@ CREATE TABLE Usage ( - HardwareAddr INTEGER NOT NULL, + HardwareAddr BIGINT NOT NULL, StartTime TIMESTAMP NOT NULL, StopTime TIMESTAMP NOT NULL, - Egress INTEGER NOT NULL, - Ingress INTEGER NOT NULL + Egress BIGINT NOT NULL, + Ingress BIGINT NOT NULL ); -- cgit v1.2.3