Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include <linux/bpf.h>
7 : : #include <linux/bpf_common.h>
8 : :
9 : : #include <stddef.h>
10 : : #include <stdint.h>
11 : :
12 : : #include <bpfilter/flavor.h>
13 : : #include <bpfilter/helper.h>
14 : : #include <bpfilter/logger.h>
15 : : #include <bpfilter/verdict.h>
16 : :
17 : : #include "cgen/packet.h"
18 : : #include "cgen/program.h"
19 : : #include "cgen/stub.h"
20 : : #include "filter.h"
21 : :
22 : : /**
23 : : * Generate XDP program prologue.
24 : : *
25 : : * @warning @ref bf_stub_parse_l2_ethhdr will check for L3 protocol. If L3 is
26 : : * not IPv4, the program will be terminated.
27 : : *
28 : : * @param program Program to generate the prologue for. Must not be NULL.
29 : : * @return 0 on success, or negative errno value on error.
30 : : */
31 : 162 : static int _bf_xdp_gen_inline_prologue(struct bf_program *program)
32 : : {
33 : : int r;
34 : :
35 : : assert(program);
36 : :
37 : : // Calculate the packet size and store it into the runtime context
38 [ + - ]: 162 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
39 : : offsetof(struct xdp_md, data)));
40 [ + - ]: 162 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
41 : : offsetof(struct xdp_md, data_end)));
42 [ + - ]: 162 : EMIT(program, BPF_ALU64_REG(BPF_SUB, BPF_REG_3, BPF_REG_2));
43 [ + - ]: 162 : EMIT(program,
44 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, BF_PROG_CTX_OFF(pkt_size)));
45 : :
46 : : // Store the ingress ifindex into the runtime context
47 [ + - ]: 162 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
48 : : offsetof(struct xdp_md, ingress_ifindex)));
49 [ + - ]: 162 : EMIT(program,
50 : : BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(ifindex)));
51 : :
52 : 162 : r = bf_stub_make_ctx_xdp_dynptr(program, BPF_REG_1);
53 [ + - ]: 162 : if (r)
54 : : return r;
55 : :
56 : 162 : r = bf_stub_parse_l2_ethhdr(program);
57 [ + - ]: 162 : if (r)
58 : : return r;
59 : :
60 : 162 : r = bf_stub_parse_l3_hdr(program);
61 [ + - ]: 162 : if (r)
62 : : return r;
63 : :
64 : 162 : r = bf_stub_parse_l4_hdr(program);
65 : : if (r)
66 : : return r;
67 : :
68 : : return 0;
69 : : }
70 : :
71 : 161 : static int _bf_xdp_gen_inline_epilogue(struct bf_program *program)
72 : : {
73 : : (void)program;
74 : :
75 : 161 : return 0;
76 : : }
77 : :
78 : : /**
79 : : * @brief Generate bytecode to redirect a packet using XDP.
80 : : *
81 : : * XDP redirect only supports egress direction - the packet is always
82 : : * transmitted out of the target interface. The BPF_F_INGRESS flag is
83 : : * ignored by XDP's bpf_redirect().
84 : : *
85 : : * @param program Program to generate bytecode for. Can't be NULL.
86 : : * @param ifindex Target interface index.
87 : : * @param dir Direction (must be BF_REDIRECT_EGRESS for XDP).
88 : : * @return 0 on success, or a negative errno value on failure.
89 : : */
90 : 4 : static int _bf_xdp_gen_inline_redirect(struct bf_program *program,
91 : : uint32_t ifindex,
92 : : enum bf_redirect_dir dir)
93 : : {
94 : : assert(program);
95 : :
96 [ + + ]: 4 : if (dir != BF_REDIRECT_EGRESS)
97 [ + - ]: 1 : return bf_err_r(-ENOTSUP, "XDP redirect only supports 'out' direction");
98 : :
99 : : // bpf_redirect(ifindex, flags) - flags are ignored for XDP
100 [ + - ]: 3 : EMIT(program, BPF_MOV64_IMM(BPF_REG_1, ifindex));
101 [ + - ]: 3 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, 0));
102 [ + - ]: 3 : EMIT(program, BPF_EMIT_CALL(BPF_FUNC_redirect));
103 : :
104 : : // Return value from bpf_redirect() is the action (XDP_REDIRECT on success)
105 : 3 : EMIT(program, BPF_EXIT_INSN());
106 : :
107 : : return 0;
108 : : }
109 : :
110 : : /**
111 : : * Convert a standard verdict into a return value.
112 : : *
113 : : * @param verdict Verdict to convert. Must be valid.
114 : : * @param ret_code XDP return code. Can't be NULL.
115 : : * @return 0 on success, or a negative errno value on failure.
116 : : */
117 : 974 : static int _bf_xdp_get_verdict(enum bf_verdict verdict, int *ret_code)
118 : : {
119 : : assert(ret_code);
120 : :
121 [ + + - ]: 974 : switch (verdict) {
122 : 830 : case BF_VERDICT_ACCEPT:
123 : : case BF_VERDICT_NEXT:
124 : 830 : *ret_code = XDP_PASS;
125 : 830 : return 0;
126 : 144 : case BF_VERDICT_DROP:
127 : 144 : *ret_code = XDP_DROP;
128 : 144 : return 0;
129 : : default:
130 : : return -ENOTSUP;
131 : : }
132 : : }
133 : :
134 : : const struct bf_flavor_ops bf_flavor_ops_xdp = {
135 : : .gen_inline_prologue = _bf_xdp_gen_inline_prologue,
136 : : .gen_inline_epilogue = _bf_xdp_gen_inline_epilogue,
137 : : .gen_inline_redirect = _bf_xdp_gen_inline_redirect,
138 : : .get_verdict = _bf_xdp_get_verdict,
139 : : .gen_inline_matcher = bf_packet_gen_inline_matcher,
140 : : .gen_inline_log = bf_packet_gen_inline_log,
141 : : };
|