~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/samples/bpf/xdp_sample.bpf.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*  GPLv2, Copyright(c) 2017 Jesper Dangaard Brouer, Red Hat, Inc. */
  3 #include "xdp_sample.bpf.h"
  4 
  5 #include <bpf/bpf_tracing.h>
  6 #include <bpf/bpf_core_read.h>
  7 #include <bpf/bpf_helpers.h>
  8 
  9 array_map rx_cnt SEC(".maps");
 10 array_map redir_err_cnt SEC(".maps");
 11 array_map cpumap_enqueue_cnt SEC(".maps");
 12 array_map cpumap_kthread_cnt SEC(".maps");
 13 array_map exception_cnt SEC(".maps");
 14 array_map devmap_xmit_cnt SEC(".maps");
 15 
 16 struct {
 17         __uint(type, BPF_MAP_TYPE_PERCPU_HASH);
 18         __uint(max_entries, 32 * 32);
 19         __type(key, u64);
 20         __type(value, struct datarec);
 21 } devmap_xmit_cnt_multi SEC(".maps");
 22 
 23 const volatile int nr_cpus = 0;
 24 
 25 /* These can be set before loading so that redundant comparisons can be DCE'd by
 26  * the verifier, and only actual matches are tried after loading tp_btf program.
 27  * This allows sample to filter tracepoint stats based on net_device.
 28  */
 29 const volatile int from_match[32] = {};
 30 const volatile int to_match[32] = {};
 31 
 32 int cpumap_map_id = 0;
 33 
 34 /* Find if b is part of set a, but if a is empty set then evaluate to true */
 35 #define IN_SET(a, b)                                                 \
 36         ({                                                           \
 37                 bool __res = !(a)[0];                                \
 38                 for (int i = 0; i < ARRAY_SIZE(a) && (a)[i]; i++) { \
 39                         __res = (a)[i] == (b);                       \
 40                         if (__res)                                   \
 41                                 break;                               \
 42                 }                                                    \
 43                 __res;                                               \
 44         })
 45 
 46 static __always_inline __u32 xdp_get_err_key(int err)
 47 {
 48         switch (err) {
 49         case 0:
 50                 return 0;
 51         case -EINVAL:
 52                 return 2;
 53         case -ENETDOWN:
 54                 return 3;
 55         case -EMSGSIZE:
 56                 return 4;
 57         case -EOPNOTSUPP:
 58                 return 5;
 59         case -ENOSPC:
 60                 return 6;
 61         default:
 62                 return 1;
 63         }
 64 }
 65 
 66 static __always_inline int xdp_redirect_collect_stat(int from, int err)
 67 {
 68         u32 cpu = bpf_get_smp_processor_id();
 69         u32 key = XDP_REDIRECT_ERROR;
 70         struct datarec *rec;
 71         u32 idx;
 72 
 73         if (!IN_SET(from_match, from))
 74                 return 0;
 75 
 76         key = xdp_get_err_key(err);
 77 
 78         idx = key * nr_cpus + cpu;
 79         rec = bpf_map_lookup_elem(&redir_err_cnt, &idx);
 80         if (!rec)
 81                 return 0;
 82         if (key)
 83                 NO_TEAR_INC(rec->dropped);
 84         else
 85                 NO_TEAR_INC(rec->processed);
 86         return 0; /* Indicate event was filtered (no further processing)*/
 87         /*
 88          * Returning 1 here would allow e.g. a perf-record tracepoint
 89          * to see and record these events, but it doesn't work well
 90          * in-practice as stopping perf-record also unload this
 91          * bpf_prog.  Plus, there is additional overhead of doing so.
 92          */
 93 }
 94 
 95 SEC("tp_btf/xdp_redirect_err")
 96 int BPF_PROG(tp_xdp_redirect_err, const struct net_device *dev,
 97              const struct bpf_prog *xdp, const void *tgt, int err,
 98              const struct bpf_map *map, u32 index)
 99 {
100         return xdp_redirect_collect_stat(dev->ifindex, err);
101 }
102 
103 SEC("tp_btf/xdp_redirect_map_err")
104 int BPF_PROG(tp_xdp_redirect_map_err, const struct net_device *dev,
105              const struct bpf_prog *xdp, const void *tgt, int err,
106              const struct bpf_map *map, u32 index)
107 {
108         return xdp_redirect_collect_stat(dev->ifindex, err);
109 }
110 
111 SEC("tp_btf/xdp_redirect")
112 int BPF_PROG(tp_xdp_redirect, const struct net_device *dev,
113              const struct bpf_prog *xdp, const void *tgt, int err,
114              const struct bpf_map *map, u32 index)
115 {
116         return xdp_redirect_collect_stat(dev->ifindex, err);
117 }
118 
119 SEC("tp_btf/xdp_redirect_map")
120 int BPF_PROG(tp_xdp_redirect_map, const struct net_device *dev,
121              const struct bpf_prog *xdp, const void *tgt, int err,
122              const struct bpf_map *map, u32 index)
123 {
124         return xdp_redirect_collect_stat(dev->ifindex, err);
125 }
126 
127 SEC("tp_btf/xdp_cpumap_enqueue")
128 int BPF_PROG(tp_xdp_cpumap_enqueue, int map_id, unsigned int processed,
129              unsigned int drops, int to_cpu)
130 {
131         u32 cpu = bpf_get_smp_processor_id();
132         struct datarec *rec;
133         u32 idx;
134 
135         if (cpumap_map_id && cpumap_map_id != map_id)
136                 return 0;
137 
138         idx = to_cpu * nr_cpus + cpu;
139         rec = bpf_map_lookup_elem(&cpumap_enqueue_cnt, &idx);
140         if (!rec)
141                 return 0;
142         NO_TEAR_ADD(rec->processed, processed);
143         NO_TEAR_ADD(rec->dropped, drops);
144         /* Record bulk events, then userspace can calc average bulk size */
145         if (processed > 0)
146                 NO_TEAR_INC(rec->issue);
147         /* Inception: It's possible to detect overload situations, via
148          * this tracepoint.  This can be used for creating a feedback
149          * loop to XDP, which can take appropriate actions to mitigate
150          * this overload situation.
151          */
152         return 0;
153 }
154 
155 SEC("tp_btf/xdp_cpumap_kthread")
156 int BPF_PROG(tp_xdp_cpumap_kthread, int map_id, unsigned int processed,
157              unsigned int drops, int sched, struct xdp_cpumap_stats *xdp_stats)
158 {
159         struct datarec *rec;
160         u32 cpu;
161 
162         if (cpumap_map_id && cpumap_map_id != map_id)
163                 return 0;
164 
165         cpu = bpf_get_smp_processor_id();
166         rec = bpf_map_lookup_elem(&cpumap_kthread_cnt, &cpu);
167         if (!rec)
168                 return 0;
169         NO_TEAR_ADD(rec->processed, processed);
170         NO_TEAR_ADD(rec->dropped, drops);
171         NO_TEAR_ADD(rec->xdp_pass, xdp_stats->pass);
172         NO_TEAR_ADD(rec->xdp_drop, xdp_stats->drop);
173         NO_TEAR_ADD(rec->xdp_redirect, xdp_stats->redirect);
174         /* Count times kthread yielded CPU via schedule call */
175         if (sched)
176                 NO_TEAR_INC(rec->issue);
177         return 0;
178 }
179 
180 SEC("tp_btf/xdp_exception")
181 int BPF_PROG(tp_xdp_exception, const struct net_device *dev,
182              const struct bpf_prog *xdp, u32 act)
183 {
184         u32 cpu = bpf_get_smp_processor_id();
185         struct datarec *rec;
186         u32 key = act, idx;
187 
188         if (!IN_SET(from_match, dev->ifindex))
189                 return 0;
190         if (!IN_SET(to_match, dev->ifindex))
191                 return 0;
192 
193         if (key > XDP_REDIRECT)
194                 key = XDP_REDIRECT + 1;
195 
196         idx = key * nr_cpus + cpu;
197         rec = bpf_map_lookup_elem(&exception_cnt, &idx);
198         if (!rec)
199                 return 0;
200         NO_TEAR_INC(rec->dropped);
201 
202         return 0;
203 }
204 
205 SEC("tp_btf/xdp_devmap_xmit")
206 int BPF_PROG(tp_xdp_devmap_xmit, const struct net_device *from_dev,
207              const struct net_device *to_dev, int sent, int drops, int err)
208 {
209         struct datarec *rec;
210         int idx_in, idx_out;
211         u32 cpu;
212 
213         idx_in = from_dev->ifindex;
214         idx_out = to_dev->ifindex;
215 
216         if (!IN_SET(from_match, idx_in))
217                 return 0;
218         if (!IN_SET(to_match, idx_out))
219                 return 0;
220 
221         cpu = bpf_get_smp_processor_id();
222         rec = bpf_map_lookup_elem(&devmap_xmit_cnt, &cpu);
223         if (!rec)
224                 return 0;
225         NO_TEAR_ADD(rec->processed, sent);
226         NO_TEAR_ADD(rec->dropped, drops);
227         /* Record bulk events, then userspace can calc average bulk size */
228         NO_TEAR_INC(rec->info);
229         /* Record error cases, where no frame were sent */
230         /* Catch API error of drv ndo_xdp_xmit sent more than count */
231         if (err || drops < 0)
232                 NO_TEAR_INC(rec->issue);
233         return 0;
234 }
235 
236 SEC("tp_btf/xdp_devmap_xmit")
237 int BPF_PROG(tp_xdp_devmap_xmit_multi, const struct net_device *from_dev,
238              const struct net_device *to_dev, int sent, int drops, int err)
239 {
240         struct datarec empty = {};
241         struct datarec *rec;
242         int idx_in, idx_out;
243         u64 idx;
244 
245         idx_in = from_dev->ifindex;
246         idx_out = to_dev->ifindex;
247         idx = idx_in;
248         idx = idx << 32 | idx_out;
249 
250         if (!IN_SET(from_match, idx_in))
251                 return 0;
252         if (!IN_SET(to_match, idx_out))
253                 return 0;
254 
255         bpf_map_update_elem(&devmap_xmit_cnt_multi, &idx, &empty, BPF_NOEXIST);
256         rec = bpf_map_lookup_elem(&devmap_xmit_cnt_multi, &idx);
257         if (!rec)
258                 return 0;
259 
260         NO_TEAR_ADD(rec->processed, sent);
261         NO_TEAR_ADD(rec->dropped, drops);
262         NO_TEAR_INC(rec->info);
263         if (err || drops < 0)
264                 NO_TEAR_INC(rec->issue);
265         return 0;
266 }
267 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php