| // SPDX-License-Identifier: GPL-2.0 |
| #ifndef _XDP_SAMPLE_BPF_H |
| #define _XDP_SAMPLE_BPF_H |
| |
| #include "vmlinux.h" |
| #include <bpf/bpf_tracing.h> |
| #include <bpf/bpf_core_read.h> |
| #include <bpf/bpf_helpers.h> |
| |
| #include "net_shared.h" |
| #include "xdp_sample_shared.h" |
| |
| #define EINVAL 22 |
| #define ENETDOWN 100 |
| #define EMSGSIZE 90 |
| #define EOPNOTSUPP 95 |
| #define ENOSPC 28 |
| |
| typedef struct { |
| __uint(type, BPF_MAP_TYPE_ARRAY); |
| __uint(map_flags, BPF_F_MMAPABLE); |
| __type(key, unsigned int); |
| __type(value, struct datarec); |
| } array_map; |
| |
| extern array_map rx_cnt; |
| extern const volatile int nr_cpus; |
| |
| enum { |
| XDP_REDIRECT_SUCCESS = 0, |
| XDP_REDIRECT_ERROR = 1 |
| }; |
| |
| static __always_inline void swap_src_dst_mac(void *data) |
| { |
| unsigned short *p = data; |
| unsigned short dst[3]; |
| |
| dst[0] = p[0]; |
| dst[1] = p[1]; |
| dst[2] = p[2]; |
| p[0] = p[3]; |
| p[1] = p[4]; |
| p[2] = p[5]; |
| p[3] = dst[0]; |
| p[4] = dst[1]; |
| p[5] = dst[2]; |
| } |
| |
| /* |
| * Note: including linux/compiler.h or linux/kernel.h for the macros below |
| * conflicts with vmlinux.h include in BPF files, so we define them here. |
| * |
| * Following functions are taken from kernel sources and |
| * break aliasing rules in their original form. |
| * |
| * While kernel is compiled with -fno-strict-aliasing, |
| * perf uses -Wstrict-aliasing=3 which makes build fail |
| * under gcc 4.4. |
| * |
| * Using extra __may_alias__ type to allow aliasing |
| * in this case. |
| */ |
| typedef __u8 __attribute__((__may_alias__)) __u8_alias_t; |
| typedef __u16 __attribute__((__may_alias__)) __u16_alias_t; |
| typedef __u32 __attribute__((__may_alias__)) __u32_alias_t; |
| typedef __u64 __attribute__((__may_alias__)) __u64_alias_t; |
| |
| static __always_inline void __read_once_size(const volatile void *p, void *res, int size) |
| { |
| switch (size) { |
| case 1: *(__u8_alias_t *) res = *(volatile __u8_alias_t *) p; break; |
| case 2: *(__u16_alias_t *) res = *(volatile __u16_alias_t *) p; break; |
| case 4: *(__u32_alias_t *) res = *(volatile __u32_alias_t *) p; break; |
| case 8: *(__u64_alias_t *) res = *(volatile __u64_alias_t *) p; break; |
| default: |
| asm volatile ("" : : : "memory"); |
| __builtin_memcpy((void *)res, (const void *)p, size); |
| asm volatile ("" : : : "memory"); |
| } |
| } |
| |
| static __always_inline void __write_once_size(volatile void *p, void *res, int size) |
| { |
| switch (size) { |
| case 1: *(volatile __u8_alias_t *) p = *(__u8_alias_t *) res; break; |
| case 2: *(volatile __u16_alias_t *) p = *(__u16_alias_t *) res; break; |
| case 4: *(volatile __u32_alias_t *) p = *(__u32_alias_t *) res; break; |
| case 8: *(volatile __u64_alias_t *) p = *(__u64_alias_t *) res; break; |
| default: |
| asm volatile ("" : : : "memory"); |
| __builtin_memcpy((void *)p, (const void *)res, size); |
| asm volatile ("" : : : "memory"); |
| } |
| } |
| |
| #define READ_ONCE(x) \ |
| ({ \ |
| union { typeof(x) __val; char __c[1]; } __u = \ |
| { .__c = { 0 } }; \ |
| __read_once_size(&(x), __u.__c, sizeof(x)); \ |
| __u.__val; \ |
| }) |
| |
| #define WRITE_ONCE(x, val) \ |
| ({ \ |
| union { typeof(x) __val; char __c[1]; } __u = \ |
| { .__val = (val) }; \ |
| __write_once_size(&(x), __u.__c, sizeof(x)); \ |
| __u.__val; \ |
| }) |
| |
| /* Add a value using relaxed read and relaxed write. Less expensive than |
| * fetch_add when there is no write concurrency. |
| */ |
| #define NO_TEAR_ADD(x, val) WRITE_ONCE((x), READ_ONCE(x) + (val)) |
| #define NO_TEAR_INC(x) NO_TEAR_ADD((x), 1) |
| |
| #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
| |
| #endif |