diff options
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/filter.h | 255 |
1 files changed, 205 insertions, 50 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h index 49ef7a298c92..f0c2ad43b4af 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
| @@ -76,56 +76,211 @@ enum { | |||
| 76 | /* BPF program can access up to 512 bytes of stack space. */ | 76 | /* BPF program can access up to 512 bytes of stack space. */ |
| 77 | #define MAX_BPF_STACK 512 | 77 | #define MAX_BPF_STACK 512 |
| 78 | 78 | ||
| 79 | /* bpf_add|sub|...: a += x, bpf_mov: a = x */ | 79 | /* Helper macros for filter block array initializers. */ |
| 80 | #define BPF_ALU64_REG(op, a, x) \ | 80 | |
| 81 | ((struct sock_filter_int) {BPF_ALU64|BPF_OP(op)|BPF_X, a, x, 0, 0}) | 81 | /* ALU ops on registers, bpf_add|sub|...: A += X */ |
| 82 | #define BPF_ALU32_REG(op, a, x) \ | 82 | |
| 83 | ((struct sock_filter_int) {BPF_ALU|BPF_OP(op)|BPF_X, a, x, 0, 0}) | 83 | #define BPF_ALU64_REG(OP, A, X) \ |
| 84 | 84 | ((struct sock_filter_int) { \ | |
| 85 | /* bpf_add|sub|...: a += imm, bpf_mov: a = imm */ | 85 | .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ |
| 86 | #define BPF_ALU64_IMM(op, a, imm) \ | 86 | .a_reg = A, \ |
| 87 | ((struct sock_filter_int) {BPF_ALU64|BPF_OP(op)|BPF_K, a, 0, 0, imm}) | 87 | .x_reg = X, \ |
| 88 | #define BPF_ALU32_IMM(op, a, imm) \ | 88 | .off = 0, \ |
| 89 | ((struct sock_filter_int) {BPF_ALU|BPF_OP(op)|BPF_K, a, 0, 0, imm}) | 89 | .imm = 0 }) |
| 90 | 90 | ||
| 91 | /* R0 = *(uint *) (skb->data + off) */ | 91 | #define BPF_ALU32_REG(OP, A, X) \ |
| 92 | #define BPF_LD_ABS(size, off) \ | 92 | ((struct sock_filter_int) { \ |
| 93 | ((struct sock_filter_int) {BPF_LD|BPF_SIZE(size)|BPF_ABS, 0, 0, 0, off}) | 93 | .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ |
| 94 | 94 | .a_reg = A, \ | |
| 95 | /* R0 = *(uint *) (skb->data + x + off) */ | 95 | .x_reg = X, \ |
| 96 | #define BPF_LD_IND(size, x, off) \ | 96 | .off = 0, \ |
| 97 | ((struct sock_filter_int) {BPF_LD|BPF_SIZE(size)|BPF_IND, 0, x, 0, off}) | 97 | .imm = 0 }) |
| 98 | 98 | ||
| 99 | /* a = *(uint *) (x + off) */ | 99 | /* ALU ops on immediates, bpf_add|sub|...: A += IMM */ |
| 100 | #define BPF_LDX_MEM(sz, a, x, off) \ | 100 | |
| 101 | ((struct sock_filter_int) {BPF_LDX|BPF_SIZE(sz)|BPF_MEM, a, x, off, 0}) | 101 | #define BPF_ALU64_IMM(OP, A, IMM) \ |
| 102 | 102 | ((struct sock_filter_int) { \ | |
| 103 | /* if (a 'op' x) goto pc+off */ | 103 | .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ |
| 104 | #define BPF_JMP_REG(op, a, x, off) \ | 104 | .a_reg = A, \ |
| 105 | ((struct sock_filter_int) {BPF_JMP|BPF_OP(op)|BPF_X, a, x, off, 0}) | 105 | .x_reg = 0, \ |
| 106 | 106 | .off = 0, \ | |
| 107 | /* if (a 'op' imm) goto pc+off */ | 107 | .imm = IMM }) |
| 108 | #define BPF_JMP_IMM(op, a, imm, off) \ | 108 | |
| 109 | ((struct sock_filter_int) {BPF_JMP|BPF_OP(op)|BPF_K, a, 0, off, imm}) | 109 | #define BPF_ALU32_IMM(OP, A, IMM) \ |
| 110 | 110 | ((struct sock_filter_int) { \ | |
| 111 | #define BPF_EXIT_INSN() \ | 111 | .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ |
| 112 | ((struct sock_filter_int) {BPF_JMP|BPF_EXIT, 0, 0, 0, 0}) | 112 | .a_reg = A, \ |
| 113 | 113 | .x_reg = 0, \ | |
| 114 | static inline int size_to_bpf(int size) | 114 | .off = 0, \ |
| 115 | { | 115 | .imm = IMM }) |
| 116 | switch (size) { | 116 | |
| 117 | case 1: | 117 | /* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */ |
| 118 | return BPF_B; | 118 | |
| 119 | case 2: | 119 | #define BPF_ENDIAN(TYPE, A, LEN) \ |
| 120 | return BPF_H; | 120 | ((struct sock_filter_int) { \ |
| 121 | case 4: | 121 | .code = BPF_ALU | BPF_END | BPF_SRC(TYPE), \ |
| 122 | return BPF_W; | 122 | .a_reg = A, \ |
| 123 | case 8: | 123 | .x_reg = 0, \ |
| 124 | return BPF_DW; | 124 | .off = 0, \ |
| 125 | default: | 125 | .imm = LEN }) |
| 126 | return -EINVAL; | 126 | |
| 127 | } | 127 | /* Short form of mov, A = X */ |
| 128 | } | 128 | |
| 129 | #define BPF_MOV64_REG(A, X) \ | ||
| 130 | ((struct sock_filter_int) { \ | ||
| 131 | .code = BPF_ALU64 | BPF_MOV | BPF_X, \ | ||
| 132 | .a_reg = A, \ | ||
| 133 | .x_reg = X, \ | ||
| 134 | .off = 0, \ | ||
| 135 | .imm = 0 }) | ||
| 136 | |||
| 137 | #define BPF_MOV32_REG(A, X) \ | ||
| 138 | ((struct sock_filter_int) { \ | ||
| 139 | .code = BPF_ALU | BPF_MOV | BPF_X, \ | ||
| 140 | .a_reg = A, \ | ||
| 141 | .x_reg = X, \ | ||
| 142 | .off = 0, \ | ||
| 143 | .imm = 0 }) | ||
| 144 | |||
| 145 | /* Short form of mov, A = IMM */ | ||
| 146 | |||
| 147 | #define BPF_MOV64_IMM(A, IMM) \ | ||
| 148 | ((struct sock_filter_int) { \ | ||
| 149 | .code = BPF_ALU64 | BPF_MOV | BPF_K, \ | ||
| 150 | .a_reg = A, \ | ||
| 151 | .x_reg = 0, \ | ||
| 152 | .off = 0, \ | ||
| 153 | .imm = IMM }) | ||
| 154 | |||
| 155 | #define BPF_MOV32_IMM(A, IMM) \ | ||
| 156 | ((struct sock_filter_int) { \ | ||
| 157 | .code = BPF_ALU | BPF_MOV | BPF_K, \ | ||
| 158 | .a_reg = A, \ | ||
| 159 | .x_reg = 0, \ | ||
| 160 | .off = 0, \ | ||
| 161 | .imm = IMM }) | ||
| 162 | |||
| 163 | /* Short form of mov based on type, BPF_X: A = X, BPF_K: A = IMM */ | ||
| 164 | |||
| 165 | #define BPF_MOV64_RAW(TYPE, A, X, IMM) \ | ||
| 166 | ((struct sock_filter_int) { \ | ||
| 167 | .code = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE), \ | ||
| 168 | .a_reg = A, \ | ||
| 169 | .x_reg = X, \ | ||
| 170 | .off = 0, \ | ||
| 171 | .imm = IMM }) | ||
| 172 | |||
| 173 | #define BPF_MOV32_RAW(TYPE, A, X, IMM) \ | ||
| 174 | ((struct sock_filter_int) { \ | ||
| 175 | .code = BPF_ALU | BPF_MOV | BPF_SRC(TYPE), \ | ||
| 176 | .a_reg = A, \ | ||
| 177 | .x_reg = X, \ | ||
| 178 | .off = 0, \ | ||
| 179 | .imm = IMM }) | ||
| 180 | |||
| 181 | /* Direct packet access, R0 = *(uint *) (skb->data + OFF) */ | ||
| 182 | |||
| 183 | #define BPF_LD_ABS(SIZE, OFF) \ | ||
| 184 | ((struct sock_filter_int) { \ | ||
| 185 | .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \ | ||
| 186 | .a_reg = 0, \ | ||
| 187 | .x_reg = 0, \ | ||
| 188 | .off = 0, \ | ||
| 189 | .imm = OFF }) | ||
| 190 | |||
| 191 | /* Indirect packet access, R0 = *(uint *) (skb->data + X + OFF) */ | ||
| 192 | |||
| 193 | #define BPF_LD_IND(SIZE, X, OFF) \ | ||
| 194 | ((struct sock_filter_int) { \ | ||
| 195 | .code = BPF_LD | BPF_SIZE(SIZE) | BPF_IND, \ | ||
| 196 | .a_reg = 0, \ | ||
| 197 | .x_reg = X, \ | ||
| 198 | .off = 0, \ | ||
| 199 | .imm = OFF }) | ||
| 200 | |||
| 201 | /* Memory store, A = *(uint *) (X + OFF), and vice versa */ | ||
| 202 | |||
| 203 | #define BPF_LDX_MEM(SIZE, A, X, OFF) \ | ||
| 204 | ((struct sock_filter_int) { \ | ||
| 205 | .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ | ||
| 206 | .a_reg = A, \ | ||
| 207 | .x_reg = X, \ | ||
| 208 | .off = OFF, \ | ||
| 209 | .imm = 0 }) | ||
| 210 | |||
| 211 | #define BPF_STX_MEM(SIZE, A, X, OFF) \ | ||
| 212 | ((struct sock_filter_int) { \ | ||
| 213 | .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ | ||
| 214 | .a_reg = A, \ | ||
| 215 | .x_reg = X, \ | ||
| 216 | .off = OFF, \ | ||
| 217 | .imm = 0 }) | ||
| 218 | |||
| 219 | /* Conditional jumps against registers, if (A 'op' X) goto pc + OFF */ | ||
| 220 | |||
| 221 | #define BPF_JMP_REG(OP, A, X, OFF) \ | ||
| 222 | ((struct sock_filter_int) { \ | ||
| 223 | .code = BPF_JMP | BPF_OP(OP) | BPF_X, \ | ||
| 224 | .a_reg = A, \ | ||
| 225 | .x_reg = X, \ | ||
| 226 | .off = OFF, \ | ||
| 227 | .imm = 0 }) | ||
| 228 | |||
| 229 | /* Conditional jumps against immediates, if (A 'op' IMM) goto pc + OFF */ | ||
| 230 | |||
| 231 | #define BPF_JMP_IMM(OP, A, IMM, OFF) \ | ||
| 232 | ((struct sock_filter_int) { \ | ||
| 233 | .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ | ||
| 234 | .a_reg = A, \ | ||
| 235 | .x_reg = 0, \ | ||
| 236 | .off = OFF, \ | ||
| 237 | .imm = IMM }) | ||
| 238 | |||
| 239 | /* Function call */ | ||
| 240 | |||
| 241 | #define BPF_EMIT_CALL(FUNC) \ | ||
| 242 | ((struct sock_filter_int) { \ | ||
| 243 | .code = BPF_JMP | BPF_CALL, \ | ||
| 244 | .a_reg = 0, \ | ||
| 245 | .x_reg = 0, \ | ||
| 246 | .off = 0, \ | ||
| 247 | .imm = ((FUNC) - __bpf_call_base) }) | ||
