1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <stdint.h>
17#include <linux/bpf.h>
18
19#define SEC(NAME) __attribute__((section(NAME), used))
20
21static const int APP_STATS_MAP_SIZE = 5000;
22static const int IFACE_STATS_MAP_SIZE = 1000;
23static const int IFACE_NAM_MAP_SIZE = 1000;
24static const int IFNAM_SIZE = 16;
25
26typedef struct {
27    unsigned int type; // actual bpf_map_type
28    unsigned int key_size;
29    unsigned int value_size;
30    unsigned int max_entries;
31    unsigned int map_flags;
32    unsigned int inner_map_idx;
33    unsigned int numa_node;
34} bpf_map_def;
35
36typedef struct {
37    uint64_t rx_packets;
38    uint64_t rx_bytes;
39    uint64_t tx_packets;
40    uint64_t tx_bytes;
41} stats_value;
42
43typedef struct {
44    char name[IFNAM_SIZE];
45} iface_name;
46
47bpf_map_def SEC("maps") iface_stats_map = {
48    .type = BPF_MAP_TYPE_HASH,
49    .key_size = sizeof(uint32_t),
50    .value_size = sizeof(stats_value),
51    .max_entries = IFACE_STATS_MAP_SIZE,
52    .map_flags = 0,
53    .inner_map_idx = 0,
54    .numa_node = 0,
55};
56
57bpf_map_def SEC("maps") iface_name_map = {
58    .type = BPF_MAP_TYPE_HASH,
59    .key_size = sizeof(uint32_t),
60    .value_size = sizeof(iface_name),
61    .max_entries = IFACE_NAM_MAP_SIZE,
62    .map_flags = 0,
63    .inner_map_idx = 0,
64    .numa_node = 0,
65};
66
67bpf_map_def SEC("maps") app_uid_stats_map = {
68    .type = BPF_MAP_TYPE_HASH,
69    .key_size = sizeof(uint32_t),
70    .value_size = sizeof(stats_value),
71    .max_entries = APP_STATS_MAP_SIZE,
72    .map_flags = 0,
73    .inner_map_idx = 0,
74    .numa_node = 0,
75};
76
77static SEC("cgroup_skb/uid/ingress") int bpf_cgroup_skb_uid_ingress(struct __sk_buff *skb)
78{
79    uint32_t sock_uid = bpf_get_socket_uid(skb);
80
81    stats_value *value = bpf_map_lookup_elem(&app_uid_stats_map, &sock_uid);
82    if (!value) {
83        stats_value newValue = {};
84        bpf_map_update_elem(&app_uid_stats_map, &sock_uid, &newValue, BPF_NOEXIST);
85        value = bpf_map_lookup_elem(&app_uid_stats_map, &sock_uid);
86    }
87
88    if (value) {
89        __sync_fetch_and_add(&value->rx_packets, 1);
90        __sync_fetch_and_add(&value->rx_bytes, skb->len);
91
92        const char log[] = "[Uid ingress] sock_uid = %d, value->rx_packets = %d, value->rx_bytes = %d";
93        bpf_trace_printk(log, sizeof(log), sock_uid, value->rx_packets, value->rx_bytes);
94    }
95    return 1;
96}
97
98static SEC("cgroup_skb/uid/egress") int bpf_cgroup_skb_uid_egress(struct __sk_buff *skb)
99{
100    uint32_t sock_uid = bpf_get_socket_uid(skb);
101
102    stats_value *value = bpf_map_lookup_elem(&app_uid_stats_map, &sock_uid);
103    if (!value) {
104        stats_value newValue = {};
105        bpf_map_update_elem(&app_uid_stats_map, &sock_uid, &newValue, BPF_NOEXIST);
106        value = bpf_map_lookup_elem(&app_uid_stats_map, &sock_uid);
107    }
108
109    if (value) {
110        __sync_fetch_and_add(&value->tx_packets, 1);
111        __sync_fetch_and_add(&value->tx_bytes, skb->len);
112
113        const char log[] = "[Uid egress] sock_uid = %d, value->tx_packets = %d, value->tx_bytes = %d";
114        bpf_trace_printk(log, sizeof(log), sock_uid, value->tx_packets, value->tx_bytes);
115    }
116    return 1;
117}
118
119static SEC("socket/iface/ingress") void bpf_socket_iface_ingress(struct __sk_buff *skb)
120{
121    uint32_t key = skb->ifindex;
122
123    stats_value *value = bpf_map_lookup_elem(&iface_stats_map, &key);
124    if (!value) {
125        stats_value newValue = {};
126        bpf_map_update_elem(&iface_stats_map, &key, &newValue, BPF_NOEXIST);
127        value = bpf_map_lookup_elem(&iface_stats_map, &key);
128    }
129
130    if (value) {
131        __sync_fetch_and_add(&value->rx_packets, 1);
132        __sync_fetch_and_add(&value->rx_bytes, skb->len);
133
134        const char log[] = "[Iface ingress] ifindex = %d, value->rx_packets = %d, value->rx_bytes = %d";
135        bpf_trace_printk(log, sizeof(log), key, value->rx_packets, value->rx_bytes);
136    }
137}
138
139static SEC("socket/iface/egress") void bpf_socket_iface_egress(struct __sk_buff *skb)
140{
141    uint32_t key = skb->ifindex;
142
143    stats_value *value = bpf_map_lookup_elem(&iface_stats_map, &key);
144    if (!value) {
145        stats_value newValue = {};
146        bpf_map_update_elem(&iface_stats_map, &key, &newValue, BPF_NOEXIST);
147        value = bpf_map_lookup_elem(&iface_stats_map, &key);
148    }
149
150    if (value) {
151        __sync_fetch_and_add(&value->tx_packets, 1);
152        __sync_fetch_and_add(&value->tx_bytes, skb->len);
153
154        const char log[] = "[Iface egress] ifindex = %d, value->tx_packets = %d, value->tx_bytes = %d";
155        bpf_trace_printk(log, sizeof(log), key, value->tx_packets, value->tx_bytes);
156    }
157}
158
159char _license[] SEC("license") = "GPL";