aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChema Gonzalez <chema@google.com>2014-04-21 12:21:24 -0400
committerDavid S. Miller <davem@davemloft.net>2014-04-22 21:27:57 -0400
commit4cd3675ebf74d7f559038ded6aa8088e4099a83d (patch)
tree6988d7dc3352fbcce10c5c510ffa11e6f30217de
parent5a4ae5f6e7d4b2b5a9b8981d513345053e40b6ac (diff)
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>
-rw-r--r--Documentation/networking/filter.txt13
-rw-r--r--include/linux/filter.h1
-rw-r--r--include/uapi/linux/filter.h3
-rw-r--r--net/core/filter.c12
-rw-r--r--tools/net/bpf_exp.l1
-rw-r--r--tools/net/bpf_exp.y11
6 files changed, 39 insertions, 2 deletions
diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt
index 81f940f4e884..82e1cb0b3da8 100644
--- a/Documentation/networking/filter.txt
+++ b/Documentation/networking/filter.txt
@@ -281,6 +281,7 @@ Possible BPF extensions are shown in the following table:
281 cpu raw_smp_processor_id() 281 cpu raw_smp_processor_id()
282 vlan_tci vlan_tx_tag_get(skb) 282 vlan_tci vlan_tx_tag_get(skb)
283 vlan_pr vlan_tx_tag_present(skb) 283 vlan_pr vlan_tx_tag_present(skb)
284 rand prandom_u32()
284 285
285These extensions can also be prefixed with '#'. 286These extensions can also be prefixed with '#'.
286Examples for low-level BPF: 287Examples for low-level BPF:
@@ -308,6 +309,18 @@ Examples for low-level BPF:
308 ret #-1 309 ret #-1
309 drop: ret #0 310 drop: ret #0
310 311
312** icmp random packet sampling, 1 in 4
313 ldh [12]
314 jne #0x800, drop
315 ldb [23]
316 jneq #1, drop
317 # get a random uint32 number
318 ld rand
319 mod #4
320 jneq #1, drop
321 ret #-1
322 drop: ret #0
323
311** SECCOMP filter example: 324** SECCOMP filter example:
312 325
313 ld [4] /* offsetof(struct seccomp_data, arch) */ 326 ld [4] /* offsetof(struct seccomp_data, arch) */
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 024fd03e5d18..759abf78dd61 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -223,6 +223,7 @@ enum {
223 BPF_S_ANC_VLAN_TAG, 223 BPF_S_ANC_VLAN_TAG,
224 BPF_S_ANC_VLAN_TAG_PRESENT, 224 BPF_S_ANC_VLAN_TAG_PRESENT,
225 BPF_S_ANC_PAY_OFFSET, 225 BPF_S_ANC_PAY_OFFSET,
226 BPF_S_ANC_RANDOM,
226}; 227};
227 228
228#endif /* __LINUX_FILTER_H__ */ 229#endif /* __LINUX_FILTER_H__ */
diff --git a/include/uapi/linux/filter.h b/include/uapi/linux/filter.h
index 8eb9ccaa5b48..253b4d42cf2b 100644
--- a/include/uapi/linux/filter.h
+++ b/include/uapi/linux/filter.h
@@ -130,7 +130,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
130#define SKF_AD_VLAN_TAG 44 130#define SKF_AD_VLAN_TAG 44
131#define SKF_AD_VLAN_TAG_PRESENT 48 131#define SKF_AD_VLAN_TAG_PRESENT 48
132#define SKF_AD_PAY_OFFSET 52 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#define SKF_NET_OFF (-0x100000) 135#define SKF_NET_OFF (-0x100000)
135#define SKF_LL_OFF (-0x200000) 136#define SKF_LL_OFF (-0x200000)
136 137
diff --git a/net/core/filter.c b/net/core/filter.c
index cd58614660cf..78a636e60a0b 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -643,6 +643,12 @@ static u64 __get_raw_cpu_id(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
643 return raw_smp_processor_id(); 643 return raw_smp_processor_id();
644} 644}
645 645
646/* note that this only generates 32-bit random numbers */
647static u64 __get_random_u32(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
648{
649 return (u64)prandom_u32();
650}
651
646/* Register mappings for user programs. */ 652/* Register mappings for user programs. */
647#define A_REG 0 653#define A_REG 0
648#define X_REG 7 654#define X_REG 7
@@ -779,6 +785,7 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
779 case SKF_AD_OFF + SKF_AD_NLATTR: 785 case SKF_AD_OFF + SKF_AD_NLATTR:
780 case SKF_AD_OFF + SKF_AD_NLATTR_NEST: 786 case SKF_AD_OFF + SKF_AD_NLATTR_NEST:
781 case SKF_AD_OFF + SKF_AD_CPU: 787 case SKF_AD_OFF + SKF_AD_CPU:
788 case SKF_AD_OFF + SKF_AD_RANDOM:
782 /* arg1 = ctx */ 789 /* arg1 = ctx */
783 insn->code = BPF_ALU64 | BPF_MOV | BPF_X; 790 insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
784 insn->a_reg = ARG1_REG; 791 insn->a_reg = ARG1_REG;
@@ -812,6 +819,9 @@ static bool convert_bpf_extensions(struct sock_filter *fp,
812 case SKF_AD_OFF + SKF_AD_CPU: 819 case SKF_AD_OFF + SKF_AD_CPU:
813 insn->imm = __get_raw_cpu_id - __bpf_call_base; 820 insn->imm = __get_raw_cpu_id - __bpf_call_base;
814 break; 821 break;
822 case SKF_AD_OFF + SKF_AD_RANDOM:
823 insn->imm = __get_random_u32 - __bpf_call_base;
824 break;
815 } 825 }
816 break; 826 break;
817 827
@@ -1362,6 +1372,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
1362 ANCILLARY(VLAN_TAG); 1372 ANCILLARY(VLAN_TAG);
1363 ANCILLARY(VLAN_TAG_PRESENT); 1373 ANCILLARY(VLAN_TAG_PRESENT);
1364 ANCILLARY(PAY_OFFSET); 1374 ANCILLARY(PAY_OFFSET);
1375 ANCILLARY(RANDOM);
1365 } 1376 }
1366 1377
1367 /* ancillary operation unknown or unsupported */ 1378 /* ancillary operation unknown or unsupported */
@@ -1746,6 +1757,7 @@ void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)
1746 [BPF_S_ANC_VLAN_TAG] = BPF_LD|BPF_B|BPF_ABS, 1757 [BPF_S_ANC_VLAN_TAG] = BPF_LD|BPF_B|BPF_ABS,
1747 [BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS, 1758 [BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS,
1748 [BPF_S_ANC_PAY_OFFSET] = BPF_LD|BPF_B|BPF_ABS, 1759 [BPF_S_ANC_PAY_OFFSET] = BPF_LD|BPF_B|BPF_ABS,
1760 [BPF_S_ANC_RANDOM] = BPF_LD|BPF_B|BPF_ABS,
1749 [BPF_S_LD_W_LEN] = BPF_LD|BPF_W|BPF_LEN, 1761 [BPF_S_LD_W_LEN] = BPF_LD|BPF_W|BPF_LEN,
1750 [BPF_S_LD_W_IND] = BPF_LD|BPF_W|BPF_IND, 1762 [BPF_S_LD_W_IND] = BPF_LD|BPF_W|BPF_IND,
1751 [BPF_S_LD_H_IND] = BPF_LD|BPF_H|BPF_IND, 1763 [BPF_S_LD_H_IND] = BPF_LD|BPF_H|BPF_IND,
diff --git a/tools/net/bpf_exp.l b/tools/net/bpf_exp.l
index bf7be77ddd62..833a96611da6 100644
--- a/tools/net/bpf_exp.l
+++ b/tools/net/bpf_exp.l
@@ -92,6 +92,7 @@ extern void yyerror(const char *str);
92"#"?("cpu") { return K_CPU; } 92"#"?("cpu") { return K_CPU; }
93"#"?("vlan_tci") { return K_VLANT; } 93"#"?("vlan_tci") { return K_VLANT; }
94"#"?("vlan_pr") { return K_VLANP; } 94"#"?("vlan_pr") { return K_VLANP; }
95"#"?("rand") { return K_RAND; }
95 96
96":" { return ':'; } 97":" { return ':'; }
97"," { return ','; } 98"," { return ','; }
diff --git a/tools/net/bpf_exp.y b/tools/net/bpf_exp.y
index d15efc989ef5..e6306c51c26f 100644
--- a/tools/net/bpf_exp.y
+++ b/tools/net/bpf_exp.y
@@ -56,7 +56,7 @@ static void bpf_set_jmp_label(char *label, enum jmp_type type);
56%token OP_LDXI 56%token OP_LDXI
57 57
58%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE 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%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' 61%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
62 62
@@ -164,6 +164,9 @@ ldb
164 | OP_LDB K_POFF { 164 | OP_LDB K_POFF {
165 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, 165 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
166 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 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
169ldh 172ldh
@@ -212,6 +215,9 @@ ldh
212 | OP_LDH K_POFF { 215 | OP_LDH K_POFF {
213 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 216 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
214 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 217 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
218 | OP_LDH K_RAND {
219 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
220 SKF_AD_OFF + SKF_AD_RANDOM); }
215 ; 221 ;
216 222
217ldi 223ldi
@@ -265,6 +271,9 @@ ld
265 | OP_LD K_POFF { 271 | OP_LD K_POFF {
266 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 272 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
267 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 273 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
274 | OP_LD K_RAND {
275 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
276 SKF_AD_OFF + SKF_AD_RANDOM); }
268 | OP_LD 'M' '[' number ']' { 277 | OP_LD 'M' '[' number ']' {
269 bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } 278 bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
270 | OP_LD '[' 'x' '+' number ']' { 279 | OP_LD '[' 'x' '+' number ']' {