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 bpf_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_init(&key, &zero);
59 (*val)++;
60
61 return 0;
62 }
63 )";
64
print_counts(ebpf::BPF * bpfp,std::string msg)65 static void print_counts(ebpf::BPF *bpfp, std::string msg) {
66 auto counts_table_hdl =
67 bpfp->get_hash_table<struct sched_switch_info, uint32_t>("counts");
68 printf("%s\n", msg.c_str());
69 printf("%-8s %-16s %-8s %-16s %-4s\n", "PREV_PID", "PREV_COMM",
70 "CURR_PID", "CURR_COMM", "CNT");
71 for (auto it : counts_table_hdl.get_table_offline()) {
72 printf("%-8d (%-16s) ==> %-8d (%-16s): %-4d\n", it.first.prev_pid,
73 it.first.prev_comm, it.first.next_pid, it.first.next_comm,
74 it.second);
75 }
76 }
77
main()78 int main() {
79 int ctrl_map_fd;
80 uint32_t val;
81
82 // create a map through bpf_create_map, bcc knows nothing about this map.
83 ctrl_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, "control", sizeof(uint32_t),
84 sizeof(uint32_t), 1, 0);
85 CHECK(ctrl_map_fd < 0, "bpf_create_map failure");
86
87 // populate control map into TableStorage
88 std::unique_ptr<ebpf::TableStorage> local_ts =
89 ebpf::createSharedTableStorage();
90 ebpf::Path global_path({"control"});
91 ebpf::TableDesc table_desc("control", ebpf::FileDesc(ctrl_map_fd),
92 BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
93 sizeof(uint32_t), 1, 0);
94 local_ts->Insert(global_path, std::move(table_desc));
95
96 // constructor with the pre-populated table storage
97 ebpf::BPF bpf(0, &*local_ts);
98 auto res = bpf.init(BPF_PROGRAM);
99 CHECK(res.code(), res.msg());
100
101 // attach to the tracepoint sched:sched_switch
102 res = bpf.attach_tracepoint("sched:sched_switch", "on_sched_switch");
103 CHECK(res.code(), res.msg());
104
105 // wait for some scheduling events
106 sleep(1);
107
108 auto control_table_hdl = bpf.get_array_table<uint32_t>("control");
109 res = control_table_hdl.get_value(0, val);
110 CHECK(res.code() || val != 0, res.msg());
111
112 // we should not see any events here
113 print_counts(&bpf, "events with control off:");
114
115 printf("\n");
116
117 // change the control to on so bpf program starts to count events
118 val = 1;
119 res = control_table_hdl.update_value(0, val);
120 CHECK(res.code(), res.msg());
121
122 // verify we get the control on back
123 val = 0;
124 res = control_table_hdl.get_value(0, val);
125 CHECK(res.code() || val != 1, res.msg());
126
127 // wait for some scheduling events
128 sleep(1);
129
130 // we should see a bunch of events here
131 print_counts(&bpf, "events with control on:");
132
133 return 0;
134 }
135