1 /*
2 * UseExternalMap shows how to access an external map through
3 * C++ interface. The external map could be a pinned map.
4 * This example simulates the pinned map through a locally
5 * created map by calling libbpf bcc_create_map.
6 *
7 * Copyright (c) Facebook, Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License")
9 */
10
11 #include <stdint.h>
12 #include <iostream>
13
14 #include "BPF.h"
15
16 // Used by C++ get hash_table
17 struct sched_switch_info {
18 int prev_pid;
19 int next_pid;
20 char prev_comm[16];
21 char next_comm[16];
22 };
23
24 #define CHECK(condition, msg) \
25 ({ \
26 if (condition) { \
27 std::cerr << msg << std::endl; \
28 return 1; \
29 } \
30 })
31
32 const std::string BPF_PROGRAM = R"(
33 #include <linux/sched.h>
34
35 struct sched_switch_info {
36 int prev_pid;
37 int next_pid;
38 char prev_comm[16];
39 char next_comm[16];
40 };
41
42 BPF_TABLE("extern", u32, u32, control, 1);
43 BPF_HASH(counts, struct sched_switch_info, u32);
44 int on_sched_switch(struct tracepoint__sched__sched_switch *args) {
45 struct sched_switch_info key = {};
46 u32 zero = 0, *val;
47
48 /* only do something when control is on */
49 val = control.lookup(&zero);
50 if (!val || *val == 0)
51 return 0;
52
53 /* record sched_switch info in counts table */
54 key.prev_pid = args->prev_pid;
55 key.next_pid = args->next_pid;
56 __builtin_memcpy(&key.prev_comm, args->prev_comm, 16);
57 __builtin_memcpy(&key.next_comm, args->next_comm, 16);
58 val = counts.lookup_or_try_init(&key, &zero);
59 if (val) {
60 (*val)++;
61 }
62
63 return 0;
64 }
65 )";
66
print_counts(ebpf::BPF * bpfp,std::string msg)67 static void print_counts(ebpf::BPF *bpfp, std::string msg) {
68 auto counts_table_hdl =
69 bpfp->get_hash_table<struct sched_switch_info, uint32_t>("counts");
70 printf("%s\n", msg.c_str());
71 printf("%-8s %-16s %-8s %-16s %-4s\n", "PREV_PID", "PREV_COMM",
72 "CURR_PID", "CURR_COMM", "CNT");
73 for (auto it : counts_table_hdl.get_table_offline()) {
74 printf("%-8d (%-16s) ==> %-8d (%-16s): %-4d\n", it.first.prev_pid,
75 it.first.prev_comm, it.first.next_pid, it.first.next_comm,
76 it.second);
77 }
78 }
79
main()80 int main() {
81 int ctrl_map_fd;
82 uint32_t val;
83
84 // create a map through bcc_create_map, bcc knows nothing about this map.
85 ctrl_map_fd = bcc_create_map(BPF_MAP_TYPE_ARRAY, "control", sizeof(uint32_t),
86 sizeof(uint32_t), 1, 0);
87 CHECK(ctrl_map_fd < 0, "bcc_create_map failure");
88
89 // populate control map into TableStorage
90 std::unique_ptr<ebpf::TableStorage> local_ts =
91 ebpf::createSharedTableStorage();
92 ebpf::Path global_path({"control"});
93 ebpf::TableDesc table_desc("control", ebpf::FileDesc(ctrl_map_fd),
94 BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
95 sizeof(uint32_t), 1, 0);
96 local_ts->Insert(global_path, std::move(table_desc));
97
98 // constructor with the pre-populated table storage
99 ebpf::BPF bpf(0, &*local_ts);
100 auto res = bpf.init(BPF_PROGRAM);
101 CHECK(res.code(), res.msg());
102
103 // attach to the tracepoint sched:sched_switch
104 res = bpf.attach_tracepoint("sched:sched_switch", "on_sched_switch");
105 CHECK(res.code(), res.msg());
106
107 // wait for some scheduling events
108 sleep(1);
109
110 auto control_table_hdl = bpf.get_array_table<uint32_t>("control");
111 res = control_table_hdl.get_value(0, val);
112 CHECK(res.code() || val != 0, res.msg());
113
114 // we should not see any events here
115 print_counts(&bpf, "events with control off:");
116
117 printf("\n");
118
119 // change the control to on so bpf program starts to count events
120 val = 1;
121 res = control_table_hdl.update_value(0, val);
122 CHECK(res.code(), res.msg());
123
124 // verify we get the control on back
125 val = 0;
126 res = control_table_hdl.get_value(0, val);
127 CHECK(res.code() || val != 1, res.msg());
128
129 // wait for some scheduling events
130 sleep(1);
131
132 // we should see a bunch of events here
133 print_counts(&bpf, "events with control on:");
134
135 return 0;
136 }
137