Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

filter: added BPF random opcode

Added a new ancillary load (bpf call in eBPF parlance) that produces
a 32-bit random number. We are implementing it as an ancillary load
(instead of an ISA opcode) because (a) it is simpler, (b) allows easy
JITing, and (c) seems more in line with generic ISAs that do not have
"get a random number" as a instruction, but as an OS call.

The main use for this ancillary load is to perform random packet sampling.

Signed-off-by: Chema Gonzalez <chema@google.com>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Acked-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Chema Gonzalez and committed by
David S. Miller
4cd3675e 5a4ae5f6

+39 -2
+13
Documentation/networking/filter.txt
··· 281 281 cpu raw_smp_processor_id() 282 282 vlan_tci vlan_tx_tag_get(skb) 283 283 vlan_pr vlan_tx_tag_present(skb) 284 + rand prandom_u32() 284 285 285 286 These extensions can also be prefixed with '#'. 286 287 Examples for low-level BPF: ··· 306 305 307 306 ld vlan_tci 308 307 jneq #10, drop 308 + ret #-1 309 + drop: ret #0 310 + 311 + ** icmp random packet sampling, 1 in 4 312 + ldh [12] 313 + jne #0x800, drop 314 + ldb [23] 315 + jneq #1, drop 316 + # get a random uint32 number 317 + ld rand 318 + mod #4 319 + jneq #1, drop 309 320 ret #-1 310 321 drop: ret #0 311 322
+1
include/linux/filter.h
··· 223 223 BPF_S_ANC_VLAN_TAG, 224 224 BPF_S_ANC_VLAN_TAG_PRESENT, 225 225 BPF_S_ANC_PAY_OFFSET, 226 + BPF_S_ANC_RANDOM, 226 227 }; 227 228 228 229 #endif /* __LINUX_FILTER_H__ */
+2 -1
include/uapi/linux/filter.h
··· 130 130 #define SKF_AD_VLAN_TAG 44 131 131 #define SKF_AD_VLAN_TAG_PRESENT 48 132 132 #define SKF_AD_PAY_OFFSET 52 133 - #define SKF_AD_MAX 56 133 + #define SKF_AD_RANDOM 56 134 + #define SKF_AD_MAX 60 134 135 #define SKF_NET_OFF (-0x100000) 135 136 #define SKF_LL_OFF (-0x200000) 136 137
+12
net/core/filter.c
··· 643 643 return raw_smp_processor_id(); 644 644 } 645 645 646 + /* note that this only generates 32-bit random numbers */ 647 + static u64 __get_random_u32(u64 ctx, u64 A, u64 X, u64 r4, u64 r5) 648 + { 649 + return (u64)prandom_u32(); 650 + } 651 + 646 652 /* Register mappings for user programs. */ 647 653 #define A_REG 0 648 654 #define X_REG 7 ··· 785 779 case SKF_AD_OFF + SKF_AD_NLATTR: 786 780 case SKF_AD_OFF + SKF_AD_NLATTR_NEST: 787 781 case SKF_AD_OFF + SKF_AD_CPU: 782 + case SKF_AD_OFF + SKF_AD_RANDOM: 788 783 /* arg1 = ctx */ 789 784 insn->code = BPF_ALU64 | BPF_MOV | BPF_X; 790 785 insn->a_reg = ARG1_REG; ··· 818 811 break; 819 812 case SKF_AD_OFF + SKF_AD_CPU: 820 813 insn->imm = __get_raw_cpu_id - __bpf_call_base; 814 + break; 815 + case SKF_AD_OFF + SKF_AD_RANDOM: 816 + insn->imm = __get_random_u32 - __bpf_call_base; 821 817 break; 822 818 } 823 819 break; ··· 1372 1362 ANCILLARY(VLAN_TAG); 1373 1363 ANCILLARY(VLAN_TAG_PRESENT); 1374 1364 ANCILLARY(PAY_OFFSET); 1365 + ANCILLARY(RANDOM); 1375 1366 } 1376 1367 1377 1368 /* ancillary operation unknown or unsupported */ ··· 1757 1746 [BPF_S_ANC_VLAN_TAG] = BPF_LD|BPF_B|BPF_ABS, 1758 1747 [BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS, 1759 1748 [BPF_S_ANC_PAY_OFFSET] = BPF_LD|BPF_B|BPF_ABS, 1749 + [BPF_S_ANC_RANDOM] = BPF_LD|BPF_B|BPF_ABS, 1760 1750 [BPF_S_LD_W_LEN] = BPF_LD|BPF_W|BPF_LEN, 1761 1751 [BPF_S_LD_W_IND] = BPF_LD|BPF_W|BPF_IND, 1762 1752 [BPF_S_LD_H_IND] = BPF_LD|BPF_H|BPF_IND,
+1
tools/net/bpf_exp.l
··· 92 92 "#"?("cpu") { return K_CPU; } 93 93 "#"?("vlan_tci") { return K_VLANT; } 94 94 "#"?("vlan_pr") { return K_VLANP; } 95 + "#"?("rand") { return K_RAND; } 95 96 96 97 ":" { return ':'; } 97 98 "," { return ','; }
+10 -1
tools/net/bpf_exp.y
··· 56 56 %token OP_LDXI 57 57 58 58 %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE 59 - %token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF 59 + %token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF K_RAND 60 60 61 61 %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' 62 62 ··· 164 164 | OP_LDB K_POFF { 165 165 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, 166 166 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 167 + | OP_LDB K_RAND { 168 + bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, 169 + SKF_AD_OFF + SKF_AD_RANDOM); } 167 170 ; 168 171 169 172 ldh ··· 215 212 | OP_LDH K_POFF { 216 213 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 217 214 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 215 + | OP_LDH K_RAND { 216 + bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 217 + SKF_AD_OFF + SKF_AD_RANDOM); } 218 218 ; 219 219 220 220 ldi ··· 271 265 | OP_LD K_POFF { 272 266 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 273 267 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 268 + | OP_LD K_RAND { 269 + bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 270 + SKF_AD_OFF + SKF_AD_RANDOM); } 274 271 | OP_LD 'M' '[' number ']' { 275 272 bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } 276 273 | OP_LD '[' 'x' '+' number ']' {