xref: /aosp_15_r20/external/iptables/extensions/libxt_bpf.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1*a71a9546SAutomerger Merge Worker /*
2*a71a9546SAutomerger Merge Worker  * Xtables BPF extension
3*a71a9546SAutomerger Merge Worker  *
4*a71a9546SAutomerger Merge Worker  * Written by Willem de Bruijn ([email protected])
5*a71a9546SAutomerger Merge Worker  * Copyright Google, Inc. 2013
6*a71a9546SAutomerger Merge Worker  * Licensed under the GNU General Public License version 2 (GPLv2)
7*a71a9546SAutomerger Merge Worker */
8*a71a9546SAutomerger Merge Worker 
9*a71a9546SAutomerger Merge Worker #include <linux/netfilter/xt_bpf.h>
10*a71a9546SAutomerger Merge Worker #include <errno.h>
11*a71a9546SAutomerger Merge Worker #include <fcntl.h>
12*a71a9546SAutomerger Merge Worker #include <stdio.h>
13*a71a9546SAutomerger Merge Worker #include <stdlib.h>
14*a71a9546SAutomerger Merge Worker #include <string.h>
15*a71a9546SAutomerger Merge Worker #include <sys/stat.h>
16*a71a9546SAutomerger Merge Worker #include <sys/types.h>
17*a71a9546SAutomerger Merge Worker #include <unistd.h>
18*a71a9546SAutomerger Merge Worker #include <xtables.h>
19*a71a9546SAutomerger Merge Worker #include "config.h"
20*a71a9546SAutomerger Merge Worker 
21*a71a9546SAutomerger Merge Worker #ifdef HAVE_LINUX_BPF_H
22*a71a9546SAutomerger Merge Worker #include <linux/bpf.h>
23*a71a9546SAutomerger Merge Worker #endif
24*a71a9546SAutomerger Merge Worker 
25*a71a9546SAutomerger Merge Worker #include <linux/magic.h>
26*a71a9546SAutomerger Merge Worker #include <linux/unistd.h>
27*a71a9546SAutomerger Merge Worker 
28*a71a9546SAutomerger Merge Worker #define BCODE_FILE_MAX_LEN_B	1024
29*a71a9546SAutomerger Merge Worker 
30*a71a9546SAutomerger Merge Worker enum {
31*a71a9546SAutomerger Merge Worker 	O_BCODE_STDIN = 0,
32*a71a9546SAutomerger Merge Worker 	O_OBJ_PINNED = 1,
33*a71a9546SAutomerger Merge Worker };
34*a71a9546SAutomerger Merge Worker 
bpf_help(void)35*a71a9546SAutomerger Merge Worker static void bpf_help(void)
36*a71a9546SAutomerger Merge Worker {
37*a71a9546SAutomerger Merge Worker 	printf(
38*a71a9546SAutomerger Merge Worker "bpf match options:\n"
39*a71a9546SAutomerger Merge Worker "--bytecode <program>	: a bpf program as generated by\n"
40*a71a9546SAutomerger Merge Worker "                         $(nfbpf_compile RAW '<filter>')\n");
41*a71a9546SAutomerger Merge Worker }
42*a71a9546SAutomerger Merge Worker 
bpf_help_v1(void)43*a71a9546SAutomerger Merge Worker static void bpf_help_v1(void)
44*a71a9546SAutomerger Merge Worker {
45*a71a9546SAutomerger Merge Worker 	printf(
46*a71a9546SAutomerger Merge Worker "bpf match options:\n"
47*a71a9546SAutomerger Merge Worker "--bytecode <program>	        : a bpf program as generated by\n"
48*a71a9546SAutomerger Merge Worker "                                 $(nfbpf_compile RAW '<filter>')\n"
49*a71a9546SAutomerger Merge Worker "--object-pinned <bpf object>	: a path to a pinned BPF object in bpf fs\n");
50*a71a9546SAutomerger Merge Worker }
51*a71a9546SAutomerger Merge Worker 
52*a71a9546SAutomerger Merge Worker static const struct xt_option_entry bpf_opts[] = {
53*a71a9546SAutomerger Merge Worker 	{.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
54*a71a9546SAutomerger Merge Worker 	XTOPT_TABLEEND,
55*a71a9546SAutomerger Merge Worker };
56*a71a9546SAutomerger Merge Worker 
57*a71a9546SAutomerger Merge Worker static const struct xt_option_entry bpf_opts_v1[] = {
58*a71a9546SAutomerger Merge Worker 	{.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
59*a71a9546SAutomerger Merge Worker 	{.name = "object-pinned" , .id = O_OBJ_PINNED, .type = XTTYPE_STRING,
60*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_bpf_info_v1, path)},
61*a71a9546SAutomerger Merge Worker 	XTOPT_TABLEEND,
62*a71a9546SAutomerger Merge Worker };
63*a71a9546SAutomerger Merge Worker 
bpf_obj_get_readonly(const char * filepath)64*a71a9546SAutomerger Merge Worker static int bpf_obj_get_readonly(const char *filepath)
65*a71a9546SAutomerger Merge Worker {
66*a71a9546SAutomerger Merge Worker #if defined HAVE_LINUX_BPF_H && defined __NR_bpf && defined BPF_FS_MAGIC
67*a71a9546SAutomerger Merge Worker 	/* union bpf_attr includes this in an anonymous struct, but the
68*a71a9546SAutomerger Merge Worker 	 * file_flags field and the BPF_F_RDONLY constant are only present
69*a71a9546SAutomerger Merge Worker 	 * in Linux 4.15+ kernel headers (include/uapi/linux/bpf.h)
70*a71a9546SAutomerger Merge Worker 	 */
71*a71a9546SAutomerger Merge Worker 	struct {   // this part of union bpf_attr is for BPF_OBJ_* commands
72*a71a9546SAutomerger Merge Worker 		__aligned_u64	pathname;
73*a71a9546SAutomerger Merge Worker 		__u32		bpf_fd;
74*a71a9546SAutomerger Merge Worker 		__u32		file_flags;
75*a71a9546SAutomerger Merge Worker 	} attr = {
76*a71a9546SAutomerger Merge Worker 		.pathname = (__u64)filepath,
77*a71a9546SAutomerger Merge Worker 		.file_flags = (1U << 3),   // BPF_F_RDONLY
78*a71a9546SAutomerger Merge Worker 	};
79*a71a9546SAutomerger Merge Worker 	int fd = syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
80*a71a9546SAutomerger Merge Worker 	if (fd >= 0) return fd;
81*a71a9546SAutomerger Merge Worker 
82*a71a9546SAutomerger Merge Worker 	/* on any error fallback to default R/W access for pre-4.15-rc1 kernels */
83*a71a9546SAutomerger Merge Worker 	attr.file_flags = 0;
84*a71a9546SAutomerger Merge Worker 	return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
85*a71a9546SAutomerger Merge Worker #else
86*a71a9546SAutomerger Merge Worker 	xtables_error(OTHER_PROBLEM, "No bpf header, kernel headers too old?");
87*a71a9546SAutomerger Merge Worker 	return -EINVAL;
88*a71a9546SAutomerger Merge Worker #endif
89*a71a9546SAutomerger Merge Worker }
90*a71a9546SAutomerger Merge Worker 
bpf_parse_string(struct sock_filter * pc,__u16 * lenp,__u16 len_max,const char * bpf_program)91*a71a9546SAutomerger Merge Worker static void bpf_parse_string(struct sock_filter *pc, __u16 *lenp, __u16 len_max,
92*a71a9546SAutomerger Merge Worker 			     const char *bpf_program)
93*a71a9546SAutomerger Merge Worker {
94*a71a9546SAutomerger Merge Worker 	const char separator = ',';
95*a71a9546SAutomerger Merge Worker 	const char *token;
96*a71a9546SAutomerger Merge Worker 	char sp;
97*a71a9546SAutomerger Merge Worker 	int i;
98*a71a9546SAutomerger Merge Worker 	__u16 len;
99*a71a9546SAutomerger Merge Worker 
100*a71a9546SAutomerger Merge Worker 	/* parse head: length. */
101*a71a9546SAutomerger Merge Worker 	if (sscanf(bpf_program, "%hu%c", &len, &sp) != 2 ||
102*a71a9546SAutomerger Merge Worker 		   sp != separator)
103*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
104*a71a9546SAutomerger Merge Worker 			      "bpf: error parsing program length");
105*a71a9546SAutomerger Merge Worker 	if (!len)
106*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
107*a71a9546SAutomerger Merge Worker 			      "bpf: illegal zero length program");
108*a71a9546SAutomerger Merge Worker 	if (len > len_max)
109*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
110*a71a9546SAutomerger Merge Worker 			      "bpf: number of instructions exceeds maximum");
111*a71a9546SAutomerger Merge Worker 
112*a71a9546SAutomerger Merge Worker 	/* parse instructions. */
113*a71a9546SAutomerger Merge Worker 	i = 0;
114*a71a9546SAutomerger Merge Worker 	token = bpf_program;
115*a71a9546SAutomerger Merge Worker 	while ((token = strchr(token, separator)) && (++token)[0]) {
116*a71a9546SAutomerger Merge Worker 		if (i >= len)
117*a71a9546SAutomerger Merge Worker 			xtables_error(PARAMETER_PROBLEM,
118*a71a9546SAutomerger Merge Worker 				      "bpf: real program length exceeds"
119*a71a9546SAutomerger Merge Worker 				      " the encoded length parameter");
120*a71a9546SAutomerger Merge Worker 		if (sscanf(token, "%hu %hhu %hhu %u,",
121*a71a9546SAutomerger Merge Worker 			   &pc->code, &pc->jt, &pc->jf, &pc->k) != 4)
122*a71a9546SAutomerger Merge Worker 			xtables_error(PARAMETER_PROBLEM,
123*a71a9546SAutomerger Merge Worker 				      "bpf: error at instr %d", i);
124*a71a9546SAutomerger Merge Worker 		i++;
125*a71a9546SAutomerger Merge Worker 		pc++;
126*a71a9546SAutomerger Merge Worker 	}
127*a71a9546SAutomerger Merge Worker 
128*a71a9546SAutomerger Merge Worker 	if (i != len)
129*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
130*a71a9546SAutomerger Merge Worker 			      "bpf: parsed program length is less than the"
131*a71a9546SAutomerger Merge Worker 			      " encoded length parameter");
132*a71a9546SAutomerger Merge Worker 
133*a71a9546SAutomerger Merge Worker 	*lenp = len;
134*a71a9546SAutomerger Merge Worker }
135*a71a9546SAutomerger Merge Worker 
bpf_parse_obj_pinned(struct xt_bpf_info_v1 * bi,const char * filepath)136*a71a9546SAutomerger Merge Worker static void bpf_parse_obj_pinned(struct xt_bpf_info_v1 *bi,
137*a71a9546SAutomerger Merge Worker 				 const char *filepath)
138*a71a9546SAutomerger Merge Worker {
139*a71a9546SAutomerger Merge Worker 	bi->fd = bpf_obj_get_readonly(filepath);
140*a71a9546SAutomerger Merge Worker 	if (bi->fd < 0)
141*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
142*a71a9546SAutomerger Merge Worker 			      "bpf: failed to get bpf object");
143*a71a9546SAutomerger Merge Worker 
144*a71a9546SAutomerger Merge Worker 	/* Cannot close bi->fd explicitly. Rely on exit */
145*a71a9546SAutomerger Merge Worker 	if (fcntl(bi->fd, F_SETFD, FD_CLOEXEC) == -1) {
146*a71a9546SAutomerger Merge Worker 		xtables_error(OTHER_PROBLEM,
147*a71a9546SAutomerger Merge Worker 			      "Could not set close on exec: %s\n",
148*a71a9546SAutomerger Merge Worker 			      strerror(errno));
149*a71a9546SAutomerger Merge Worker 	}
150*a71a9546SAutomerger Merge Worker }
151*a71a9546SAutomerger Merge Worker 
bpf_parse(struct xt_option_call * cb)152*a71a9546SAutomerger Merge Worker static void bpf_parse(struct xt_option_call *cb)
153*a71a9546SAutomerger Merge Worker {
154*a71a9546SAutomerger Merge Worker 	struct xt_bpf_info *bi = (void *) cb->data;
155*a71a9546SAutomerger Merge Worker 
156*a71a9546SAutomerger Merge Worker 	xtables_option_parse(cb);
157*a71a9546SAutomerger Merge Worker 	switch (cb->entry->id) {
158*a71a9546SAutomerger Merge Worker 	case O_BCODE_STDIN:
159*a71a9546SAutomerger Merge Worker 		bpf_parse_string(bi->bpf_program, &bi->bpf_program_num_elem,
160*a71a9546SAutomerger Merge Worker 				 ARRAY_SIZE(bi->bpf_program), cb->arg);
161*a71a9546SAutomerger Merge Worker 		break;
162*a71a9546SAutomerger Merge Worker 	default:
163*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM, "bpf: unknown option");
164*a71a9546SAutomerger Merge Worker 	}
165*a71a9546SAutomerger Merge Worker }
166*a71a9546SAutomerger Merge Worker 
bpf_parse_v1(struct xt_option_call * cb)167*a71a9546SAutomerger Merge Worker static void bpf_parse_v1(struct xt_option_call *cb)
168*a71a9546SAutomerger Merge Worker {
169*a71a9546SAutomerger Merge Worker 	struct xt_bpf_info_v1 *bi = (void *) cb->data;
170*a71a9546SAutomerger Merge Worker 
171*a71a9546SAutomerger Merge Worker 	xtables_option_parse(cb);
172*a71a9546SAutomerger Merge Worker 	switch (cb->entry->id) {
173*a71a9546SAutomerger Merge Worker 	case O_BCODE_STDIN:
174*a71a9546SAutomerger Merge Worker 		bpf_parse_string(bi->bpf_program, &bi->bpf_program_num_elem,
175*a71a9546SAutomerger Merge Worker 				 ARRAY_SIZE(bi->bpf_program), cb->arg);
176*a71a9546SAutomerger Merge Worker 		bi->mode = XT_BPF_MODE_BYTECODE;
177*a71a9546SAutomerger Merge Worker 		break;
178*a71a9546SAutomerger Merge Worker 	case O_OBJ_PINNED:
179*a71a9546SAutomerger Merge Worker 		bpf_parse_obj_pinned(bi, cb->arg);
180*a71a9546SAutomerger Merge Worker 		bi->mode = XT_BPF_MODE_FD_PINNED;
181*a71a9546SAutomerger Merge Worker 		break;
182*a71a9546SAutomerger Merge Worker 	default:
183*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM, "bpf: unknown option");
184*a71a9546SAutomerger Merge Worker 	}
185*a71a9546SAutomerger Merge Worker }
186*a71a9546SAutomerger Merge Worker 
bpf_print_code(const struct sock_filter * pc,__u16 len,char tail)187*a71a9546SAutomerger Merge Worker static void bpf_print_code(const struct sock_filter *pc, __u16 len, char tail)
188*a71a9546SAutomerger Merge Worker {
189*a71a9546SAutomerger Merge Worker 	for (; len; len--, pc++)
190*a71a9546SAutomerger Merge Worker 		printf("%hu %hhu %hhu %u%c",
191*a71a9546SAutomerger Merge Worker 		       pc->code, pc->jt, pc->jf, pc->k,
192*a71a9546SAutomerger Merge Worker 		       len > 1 ? ',' : tail);
193*a71a9546SAutomerger Merge Worker }
194*a71a9546SAutomerger Merge Worker 
bpf_save_code(const struct sock_filter * pc,__u16 len)195*a71a9546SAutomerger Merge Worker static void bpf_save_code(const struct sock_filter *pc, __u16 len)
196*a71a9546SAutomerger Merge Worker {
197*a71a9546SAutomerger Merge Worker 	printf(" --bytecode \"%hu,", len);
198*a71a9546SAutomerger Merge Worker 	bpf_print_code(pc, len, '\"');
199*a71a9546SAutomerger Merge Worker }
200*a71a9546SAutomerger Merge Worker 
bpf_save(const void * ip,const struct xt_entry_match * match)201*a71a9546SAutomerger Merge Worker static void bpf_save(const void *ip, const struct xt_entry_match *match)
202*a71a9546SAutomerger Merge Worker {
203*a71a9546SAutomerger Merge Worker 	const struct xt_bpf_info *info = (void *) match->data;
204*a71a9546SAutomerger Merge Worker 
205*a71a9546SAutomerger Merge Worker 	bpf_save_code(info->bpf_program, info->bpf_program_num_elem);
206*a71a9546SAutomerger Merge Worker }
207*a71a9546SAutomerger Merge Worker 
bpf_save_v1(const void * ip,const struct xt_entry_match * match)208*a71a9546SAutomerger Merge Worker static void bpf_save_v1(const void *ip, const struct xt_entry_match *match)
209*a71a9546SAutomerger Merge Worker {
210*a71a9546SAutomerger Merge Worker 	const struct xt_bpf_info_v1 *info = (void *) match->data;
211*a71a9546SAutomerger Merge Worker 
212*a71a9546SAutomerger Merge Worker 	if (info->mode == XT_BPF_MODE_BYTECODE)
213*a71a9546SAutomerger Merge Worker 		bpf_save_code(info->bpf_program, info->bpf_program_num_elem);
214*a71a9546SAutomerger Merge Worker 	else if (info->mode == XT_BPF_MODE_FD_PINNED)
215*a71a9546SAutomerger Merge Worker 		printf(" --object-pinned %s", info->path);
216*a71a9546SAutomerger Merge Worker 	else
217*a71a9546SAutomerger Merge Worker 		xtables_error(OTHER_PROBLEM, "unknown bpf mode");
218*a71a9546SAutomerger Merge Worker }
219*a71a9546SAutomerger Merge Worker 
bpf_fcheck(struct xt_fcheck_call * cb)220*a71a9546SAutomerger Merge Worker static void bpf_fcheck(struct xt_fcheck_call *cb)
221*a71a9546SAutomerger Merge Worker {
222*a71a9546SAutomerger Merge Worker 	if (!(cb->xflags & (1 << O_BCODE_STDIN)))
223*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
224*a71a9546SAutomerger Merge Worker 			      "bpf: missing --bytecode parameter");
225*a71a9546SAutomerger Merge Worker }
226*a71a9546SAutomerger Merge Worker 
bpf_fcheck_v1(struct xt_fcheck_call * cb)227*a71a9546SAutomerger Merge Worker static void bpf_fcheck_v1(struct xt_fcheck_call *cb)
228*a71a9546SAutomerger Merge Worker {
229*a71a9546SAutomerger Merge Worker 	const unsigned int bit_bcode = 1 << O_BCODE_STDIN;
230*a71a9546SAutomerger Merge Worker 	const unsigned int bit_pinned = 1 << O_OBJ_PINNED;
231*a71a9546SAutomerger Merge Worker 	unsigned int flags;
232*a71a9546SAutomerger Merge Worker 
233*a71a9546SAutomerger Merge Worker 	flags = cb->xflags & (bit_bcode | bit_pinned);
234*a71a9546SAutomerger Merge Worker 	if (flags != bit_bcode && flags != bit_pinned)
235*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
236*a71a9546SAutomerger Merge Worker 			      "bpf: one of --bytecode or --pinned is required");
237*a71a9546SAutomerger Merge Worker }
238*a71a9546SAutomerger Merge Worker 
bpf_print(const void * ip,const struct xt_entry_match * match,int numeric)239*a71a9546SAutomerger Merge Worker static void bpf_print(const void *ip, const struct xt_entry_match *match,
240*a71a9546SAutomerger Merge Worker 		      int numeric)
241*a71a9546SAutomerger Merge Worker {
242*a71a9546SAutomerger Merge Worker 	const struct xt_bpf_info *info = (void *) match->data;
243*a71a9546SAutomerger Merge Worker 
244*a71a9546SAutomerger Merge Worker 	printf("match bpf ");
245*a71a9546SAutomerger Merge Worker 	bpf_print_code(info->bpf_program, info->bpf_program_num_elem, '\0');
246*a71a9546SAutomerger Merge Worker }
247*a71a9546SAutomerger Merge Worker 
bpf_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)248*a71a9546SAutomerger Merge Worker static void bpf_print_v1(const void *ip, const struct xt_entry_match *match,
249*a71a9546SAutomerger Merge Worker 			 int numeric)
250*a71a9546SAutomerger Merge Worker {
251*a71a9546SAutomerger Merge Worker 	const struct xt_bpf_info_v1 *info = (void *) match->data;
252*a71a9546SAutomerger Merge Worker 
253*a71a9546SAutomerger Merge Worker 	printf("match bpf ");
254*a71a9546SAutomerger Merge Worker 	if (info->mode == XT_BPF_MODE_BYTECODE)
255*a71a9546SAutomerger Merge Worker 		bpf_print_code(info->bpf_program, info->bpf_program_num_elem, '\0');
256*a71a9546SAutomerger Merge Worker 	else if (info->mode == XT_BPF_MODE_FD_PINNED)
257*a71a9546SAutomerger Merge Worker 		printf("pinned %s", info->path);
258*a71a9546SAutomerger Merge Worker 	else
259*a71a9546SAutomerger Merge Worker 		printf("unknown");
260*a71a9546SAutomerger Merge Worker }
261*a71a9546SAutomerger Merge Worker 
262*a71a9546SAutomerger Merge Worker static struct xtables_match bpf_matches[] = {
263*a71a9546SAutomerger Merge Worker 	{
264*a71a9546SAutomerger Merge Worker 		.family		= NFPROTO_UNSPEC,
265*a71a9546SAutomerger Merge Worker 		.name		= "bpf",
266*a71a9546SAutomerger Merge Worker 		.version	= XTABLES_VERSION,
267*a71a9546SAutomerger Merge Worker 		.revision	= 0,
268*a71a9546SAutomerger Merge Worker 		.size		= XT_ALIGN(sizeof(struct xt_bpf_info)),
269*a71a9546SAutomerger Merge Worker 		.userspacesize	= XT_ALIGN(offsetof(struct xt_bpf_info, filter)),
270*a71a9546SAutomerger Merge Worker 		.help		= bpf_help,
271*a71a9546SAutomerger Merge Worker 		.print		= bpf_print,
272*a71a9546SAutomerger Merge Worker 		.save		= bpf_save,
273*a71a9546SAutomerger Merge Worker 		.x6_parse	= bpf_parse,
274*a71a9546SAutomerger Merge Worker 		.x6_fcheck	= bpf_fcheck,
275*a71a9546SAutomerger Merge Worker 		.x6_options	= bpf_opts,
276*a71a9546SAutomerger Merge Worker 	},
277*a71a9546SAutomerger Merge Worker 	{
278*a71a9546SAutomerger Merge Worker 		.family		= NFPROTO_UNSPEC,
279*a71a9546SAutomerger Merge Worker 		.name		= "bpf",
280*a71a9546SAutomerger Merge Worker 		.version	= XTABLES_VERSION,
281*a71a9546SAutomerger Merge Worker 		.revision	= 1,
282*a71a9546SAutomerger Merge Worker 		.size		= XT_ALIGN(sizeof(struct xt_bpf_info_v1)),
283*a71a9546SAutomerger Merge Worker 		.userspacesize	= XT_ALIGN(offsetof(struct xt_bpf_info_v1, filter)),
284*a71a9546SAutomerger Merge Worker 		.help		= bpf_help_v1,
285*a71a9546SAutomerger Merge Worker 		.print		= bpf_print_v1,
286*a71a9546SAutomerger Merge Worker 		.save		= bpf_save_v1,
287*a71a9546SAutomerger Merge Worker 		.x6_parse	= bpf_parse_v1,
288*a71a9546SAutomerger Merge Worker 		.x6_fcheck	= bpf_fcheck_v1,
289*a71a9546SAutomerger Merge Worker 		.x6_options	= bpf_opts_v1,
290*a71a9546SAutomerger Merge Worker 	},
291*a71a9546SAutomerger Merge Worker };
292*a71a9546SAutomerger Merge Worker 
_init(void)293*a71a9546SAutomerger Merge Worker void _init(void)
294*a71a9546SAutomerger Merge Worker {
295*a71a9546SAutomerger Merge Worker 	xtables_register_matches(bpf_matches, ARRAY_SIZE(bpf_matches));
296*a71a9546SAutomerger Merge Worker }
297