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