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 
21 static const int APP_STATS_MAP_SIZE = 5000;
22 static const int IFACE_STATS_MAP_SIZE = 1000;
23 static const int IFACE_NAM_MAP_SIZE = 1000;
24 static const int IFNAM_SIZE = 16;
25 
26 typedef 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 
36 typedef 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 
43 typedef struct {
44     char name[IFNAM_SIZE];
45 } iface_name;
46 
47 bpf_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 
57 bpf_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 
67 bpf_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 
bpf_cgroup_skb_uid_ingress(struct __sk_buff * skb)77 static 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 
bpf_cgroup_skb_uid_egress(struct __sk_buff * skb)98 static 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 
bpf_socket_iface_ingress(struct __sk_buff * skb)119 static 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 
bpf_socket_iface_egress(struct __sk_buff * skb)139 static 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 
159 char _license[] SEC("license") = "GPL";