xref: /aosp_15_r20/external/iptables/extensions/libxt_ipvs.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1*a71a9546SAutomerger Merge Worker /*
2*a71a9546SAutomerger Merge Worker  * Shared library add-on to iptables to add IPVS matching.
3*a71a9546SAutomerger Merge Worker  *
4*a71a9546SAutomerger Merge Worker  * Detailed doc is in the kernel module source net/netfilter/xt_ipvs.c
5*a71a9546SAutomerger Merge Worker  *
6*a71a9546SAutomerger Merge Worker  * Author: Hannes Eder <[email protected]>
7*a71a9546SAutomerger Merge Worker  */
8*a71a9546SAutomerger Merge Worker #include <stdbool.h>
9*a71a9546SAutomerger Merge Worker #include <stdio.h>
10*a71a9546SAutomerger Merge Worker #include <string.h>
11*a71a9546SAutomerger Merge Worker #include <xtables.h>
12*a71a9546SAutomerger Merge Worker #include <linux/ip_vs.h>
13*a71a9546SAutomerger Merge Worker #include <linux/netfilter/xt_ipvs.h>
14*a71a9546SAutomerger Merge Worker 
15*a71a9546SAutomerger Merge Worker enum {
16*a71a9546SAutomerger Merge Worker 	/* For xt_ipvs: make sure this matches up with %XT_IPVS_*'s order */
17*a71a9546SAutomerger Merge Worker 	O_IPVS = 0,
18*a71a9546SAutomerger Merge Worker 	O_VPROTO,
19*a71a9546SAutomerger Merge Worker 	O_VADDR,
20*a71a9546SAutomerger Merge Worker 	O_VPORT,
21*a71a9546SAutomerger Merge Worker 	O_VDIR,
22*a71a9546SAutomerger Merge Worker 	O_VMETHOD,
23*a71a9546SAutomerger Merge Worker 	O_VPORTCTL,
24*a71a9546SAutomerger Merge Worker };
25*a71a9546SAutomerger Merge Worker 
26*a71a9546SAutomerger Merge Worker #define s struct xt_ipvs_mtinfo
27*a71a9546SAutomerger Merge Worker static const struct xt_option_entry ipvs_mt_opts[] = {
28*a71a9546SAutomerger Merge Worker 	{.name = "ipvs", .id = O_IPVS, .type = XTTYPE_NONE,
29*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_INVERT},
30*a71a9546SAutomerger Merge Worker 	{.name = "vproto", .id = O_VPROTO, .type = XTTYPE_PROTOCOL,
31*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, l4proto)},
32*a71a9546SAutomerger Merge Worker 	{.name = "vaddr", .id = O_VADDR, .type = XTTYPE_HOSTMASK,
33*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_INVERT},
34*a71a9546SAutomerger Merge Worker 	{.name = "vport", .id = O_VPORT, .type = XTTYPE_PORT,
35*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_NBO | XTOPT_INVERT | XTOPT_PUT,
36*a71a9546SAutomerger Merge Worker 	 XTOPT_POINTER(s, vport)},
37*a71a9546SAutomerger Merge Worker 	{.name = "vdir", .id = O_VDIR, .type = XTTYPE_STRING},
38*a71a9546SAutomerger Merge Worker 	{.name = "vmethod", .id = O_VMETHOD, .type = XTTYPE_STRING,
39*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_INVERT},
40*a71a9546SAutomerger Merge Worker 	{.name = "vportctl", .id = O_VPORTCTL, .type = XTTYPE_PORT,
41*a71a9546SAutomerger Merge Worker 	 .flags = XTOPT_NBO | XTOPT_INVERT | XTOPT_PUT,
42*a71a9546SAutomerger Merge Worker 	 XTOPT_POINTER(s, vportctl)},
43*a71a9546SAutomerger Merge Worker 	XTOPT_TABLEEND,
44*a71a9546SAutomerger Merge Worker };
45*a71a9546SAutomerger Merge Worker #undef s
46*a71a9546SAutomerger Merge Worker 
ipvs_mt_help(void)47*a71a9546SAutomerger Merge Worker static void ipvs_mt_help(void)
48*a71a9546SAutomerger Merge Worker {
49*a71a9546SAutomerger Merge Worker 	printf(
50*a71a9546SAutomerger Merge Worker "IPVS match options:\n"
51*a71a9546SAutomerger Merge Worker "[!] --ipvs                      packet belongs to an IPVS connection\n"
52*a71a9546SAutomerger Merge Worker "\n"
53*a71a9546SAutomerger Merge Worker "Any of the following options implies --ipvs (even negated)\n"
54*a71a9546SAutomerger Merge Worker "[!] --vproto protocol           VIP protocol to match; by number or name,\n"
55*a71a9546SAutomerger Merge Worker "                                e.g. \"tcp\"\n"
56*a71a9546SAutomerger Merge Worker "[!] --vaddr address[/mask]      VIP address to match\n"
57*a71a9546SAutomerger Merge Worker "[!] --vport port                VIP port to match; by number or name,\n"
58*a71a9546SAutomerger Merge Worker "                                e.g. \"http\"\n"
59*a71a9546SAutomerger Merge Worker "    --vdir {ORIGINAL|REPLY}     flow direction of packet\n"
60*a71a9546SAutomerger Merge Worker "[!] --vmethod {GATE|IPIP|MASQ}  IPVS forwarding method used\n"
61*a71a9546SAutomerger Merge Worker "[!] --vportctl port             VIP port of the controlling connection to\n"
62*a71a9546SAutomerger Merge Worker "                                match, e.g. 21 for FTP\n"
63*a71a9546SAutomerger Merge Worker 		);
64*a71a9546SAutomerger Merge Worker }
65*a71a9546SAutomerger Merge Worker 
ipvs_mt_parse(struct xt_option_call * cb)66*a71a9546SAutomerger Merge Worker static void ipvs_mt_parse(struct xt_option_call *cb)
67*a71a9546SAutomerger Merge Worker {
68*a71a9546SAutomerger Merge Worker 	struct xt_ipvs_mtinfo *data = cb->data;
69*a71a9546SAutomerger Merge Worker 
70*a71a9546SAutomerger Merge Worker 	xtables_option_parse(cb);
71*a71a9546SAutomerger Merge Worker 	switch (cb->entry->id) {
72*a71a9546SAutomerger Merge Worker 	case O_VADDR:
73*a71a9546SAutomerger Merge Worker 		memcpy(&data->vaddr, &cb->val.haddr, sizeof(cb->val.haddr));
74*a71a9546SAutomerger Merge Worker 		memcpy(&data->vmask, &cb->val.hmask, sizeof(cb->val.hmask));
75*a71a9546SAutomerger Merge Worker 		break;
76*a71a9546SAutomerger Merge Worker 	case O_VDIR:
77*a71a9546SAutomerger Merge Worker 		if (strcasecmp(cb->arg, "ORIGINAL") == 0) {
78*a71a9546SAutomerger Merge Worker 			data->bitmask |= XT_IPVS_DIR;
79*a71a9546SAutomerger Merge Worker 			data->invert   &= ~XT_IPVS_DIR;
80*a71a9546SAutomerger Merge Worker 		} else if (strcasecmp(cb->arg, "REPLY") == 0) {
81*a71a9546SAutomerger Merge Worker 			data->bitmask |= XT_IPVS_DIR;
82*a71a9546SAutomerger Merge Worker 			data->invert  |= XT_IPVS_DIR;
83*a71a9546SAutomerger Merge Worker 		} else {
84*a71a9546SAutomerger Merge Worker 			xtables_param_act(XTF_BAD_VALUE,
85*a71a9546SAutomerger Merge Worker 					  "ipvs", "--vdir", cb->arg);
86*a71a9546SAutomerger Merge Worker 		}
87*a71a9546SAutomerger Merge Worker 		break;
88*a71a9546SAutomerger Merge Worker 	case O_VMETHOD:
89*a71a9546SAutomerger Merge Worker 		if (strcasecmp(cb->arg, "GATE") == 0)
90*a71a9546SAutomerger Merge Worker 			data->fwd_method = IP_VS_CONN_F_DROUTE;
91*a71a9546SAutomerger Merge Worker 		else if (strcasecmp(cb->arg, "IPIP") == 0)
92*a71a9546SAutomerger Merge Worker 			data->fwd_method = IP_VS_CONN_F_TUNNEL;
93*a71a9546SAutomerger Merge Worker 		else if (strcasecmp(cb->arg, "MASQ") == 0)
94*a71a9546SAutomerger Merge Worker 			data->fwd_method = IP_VS_CONN_F_MASQ;
95*a71a9546SAutomerger Merge Worker 		else
96*a71a9546SAutomerger Merge Worker 			xtables_param_act(XTF_BAD_VALUE,
97*a71a9546SAutomerger Merge Worker 					  "ipvs", "--vmethod", cb->arg);
98*a71a9546SAutomerger Merge Worker 		break;
99*a71a9546SAutomerger Merge Worker 	}
100*a71a9546SAutomerger Merge Worker 	data->bitmask |= 1 << cb->entry->id;
101*a71a9546SAutomerger Merge Worker 	if (cb->invert)
102*a71a9546SAutomerger Merge Worker 		data->invert |= 1 << cb->entry->id;
103*a71a9546SAutomerger Merge Worker }
104*a71a9546SAutomerger Merge Worker 
ipvs_mt_check(struct xt_fcheck_call * cb)105*a71a9546SAutomerger Merge Worker static void ipvs_mt_check(struct xt_fcheck_call *cb)
106*a71a9546SAutomerger Merge Worker {
107*a71a9546SAutomerger Merge Worker 	struct xt_ipvs_mtinfo *info = cb->data;
108*a71a9546SAutomerger Merge Worker 
109*a71a9546SAutomerger Merge Worker 	if (cb->xflags == 0)
110*a71a9546SAutomerger Merge Worker 		xtables_error(PARAMETER_PROBLEM,
111*a71a9546SAutomerger Merge Worker 			      "IPVS: At least one option is required");
112*a71a9546SAutomerger Merge Worker 	if (info->bitmask & XT_IPVS_ONCE_MASK) {
113*a71a9546SAutomerger Merge Worker 		if (info->invert & XT_IPVS_IPVS_PROPERTY)
114*a71a9546SAutomerger Merge Worker 			xtables_error(PARAMETER_PROBLEM,
115*a71a9546SAutomerger Merge Worker 				      "! --ipvs cannot be together with"
116*a71a9546SAutomerger Merge Worker 				      " other options");
117*a71a9546SAutomerger Merge Worker 		info->bitmask |= XT_IPVS_IPVS_PROPERTY;
118*a71a9546SAutomerger Merge Worker 	}
119*a71a9546SAutomerger Merge Worker }
120*a71a9546SAutomerger Merge Worker 
121*a71a9546SAutomerger Merge Worker /* Shamelessly copied from libxt_conntrack.c */
ipvs_mt_dump_addr(const union nf_inet_addr * addr,const union nf_inet_addr * mask,unsigned int family,bool numeric)122*a71a9546SAutomerger Merge Worker static void ipvs_mt_dump_addr(const union nf_inet_addr *addr,
123*a71a9546SAutomerger Merge Worker 			      const union nf_inet_addr *mask,
124*a71a9546SAutomerger Merge Worker 			      unsigned int family, bool numeric)
125*a71a9546SAutomerger Merge Worker {
126*a71a9546SAutomerger Merge Worker 	if (family == NFPROTO_IPV4) {
127*a71a9546SAutomerger Merge Worker 		if (!numeric && addr->ip == 0) {
128*a71a9546SAutomerger Merge Worker 			printf(" anywhere");
129*a71a9546SAutomerger Merge Worker 			return;
130*a71a9546SAutomerger Merge Worker 		}
131*a71a9546SAutomerger Merge Worker 		if (numeric)
132*a71a9546SAutomerger Merge Worker 			printf(" %s%s",
133*a71a9546SAutomerger Merge Worker 			       xtables_ipaddr_to_numeric(&addr->in),
134*a71a9546SAutomerger Merge Worker 			       xtables_ipmask_to_numeric(&mask->in));
135*a71a9546SAutomerger Merge Worker 		else
136*a71a9546SAutomerger Merge Worker 			printf(" %s%s",
137*a71a9546SAutomerger Merge Worker 			       xtables_ipaddr_to_anyname(&addr->in),
138*a71a9546SAutomerger Merge Worker 			       xtables_ipmask_to_numeric(&mask->in));
139*a71a9546SAutomerger Merge Worker 	} else if (family == NFPROTO_IPV6) {
140*a71a9546SAutomerger Merge Worker 		if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
141*a71a9546SAutomerger Merge Worker 		    addr->ip6[2] == 0 && addr->ip6[3] == 0) {
142*a71a9546SAutomerger Merge Worker 			printf(" anywhere");
143*a71a9546SAutomerger Merge Worker 			return;
144*a71a9546SAutomerger Merge Worker 		}
145*a71a9546SAutomerger Merge Worker 		if (numeric)
146*a71a9546SAutomerger Merge Worker 			printf(" %s%s",
147*a71a9546SAutomerger Merge Worker 			       xtables_ip6addr_to_numeric(&addr->in6),
148*a71a9546SAutomerger Merge Worker 			       xtables_ip6mask_to_numeric(&mask->in6));
149*a71a9546SAutomerger Merge Worker 		else
150*a71a9546SAutomerger Merge Worker 			printf(" %s%s",
151*a71a9546SAutomerger Merge Worker 			       xtables_ip6addr_to_anyname(&addr->in6),
152*a71a9546SAutomerger Merge Worker 			       xtables_ip6mask_to_numeric(&mask->in6));
153*a71a9546SAutomerger Merge Worker 	}
154*a71a9546SAutomerger Merge Worker }
155*a71a9546SAutomerger Merge Worker 
ipvs_mt_dump(const void * ip,const struct xt_ipvs_mtinfo * data,unsigned int family,bool numeric,const char * prefix)156*a71a9546SAutomerger Merge Worker static void ipvs_mt_dump(const void *ip, const struct xt_ipvs_mtinfo *data,
157*a71a9546SAutomerger Merge Worker 			 unsigned int family, bool numeric, const char *prefix)
158*a71a9546SAutomerger Merge Worker {
159*a71a9546SAutomerger Merge Worker 	if (data->bitmask == XT_IPVS_IPVS_PROPERTY) {
160*a71a9546SAutomerger Merge Worker 		if (data->invert & XT_IPVS_IPVS_PROPERTY)
161*a71a9546SAutomerger Merge Worker 			printf(" !");
162*a71a9546SAutomerger Merge Worker 		printf(" %sipvs", prefix);
163*a71a9546SAutomerger Merge Worker 	}
164*a71a9546SAutomerger Merge Worker 
165*a71a9546SAutomerger Merge Worker 	if (data->bitmask & XT_IPVS_PROTO) {
166*a71a9546SAutomerger Merge Worker 		if (data->invert & XT_IPVS_PROTO)
167*a71a9546SAutomerger Merge Worker 			printf(" !");
168*a71a9546SAutomerger Merge Worker 		printf(" %svproto %u", prefix, data->l4proto);
169*a71a9546SAutomerger Merge Worker 	}
170*a71a9546SAutomerger Merge Worker 
171*a71a9546SAutomerger Merge Worker 	if (data->bitmask & XT_IPVS_VADDR) {
172*a71a9546SAutomerger Merge Worker 		if (data->invert & XT_IPVS_VADDR)
173*a71a9546SAutomerger Merge Worker 			printf(" !");
174*a71a9546SAutomerger Merge Worker 
175*a71a9546SAutomerger Merge Worker 		printf(" %svaddr", prefix);
176*a71a9546SAutomerger Merge Worker 		ipvs_mt_dump_addr(&data->vaddr, &data->vmask, family, numeric);
177*a71a9546SAutomerger Merge Worker 	}
178*a71a9546SAutomerger Merge Worker 
179*a71a9546SAutomerger Merge Worker 	if (data->bitmask & XT_IPVS_VPORT) {
180*a71a9546SAutomerger Merge Worker 		if (data->invert & XT_IPVS_VPORT)
181*a71a9546SAutomerger Merge Worker 			printf(" !");
182*a71a9546SAutomerger Merge Worker 
183*a71a9546SAutomerger Merge Worker 		printf(" %svport %u", prefix, ntohs(data->vport));
184*a71a9546SAutomerger Merge Worker 	}
185*a71a9546SAutomerger Merge Worker 
186*a71a9546SAutomerger Merge Worker 	if (data->bitmask & XT_IPVS_DIR) {
187*a71a9546SAutomerger Merge Worker 		if (data->invert & XT_IPVS_DIR)
188*a71a9546SAutomerger Merge Worker 			printf(" %svdir REPLY", prefix);
189*a71a9546SAutomerger Merge Worker 		else
190*a71a9546SAutomerger Merge Worker 			printf(" %svdir ORIGINAL", prefix);
191*a71a9546SAutomerger Merge Worker 	}
192*a71a9546SAutomerger Merge Worker 
193*a71a9546SAutomerger Merge Worker 	if (data->bitmask & XT_IPVS_METHOD) {
194*a71a9546SAutomerger Merge Worker 		if (data->invert & XT_IPVS_METHOD)
195*a71a9546SAutomerger Merge Worker 			printf(" !");
196*a71a9546SAutomerger Merge Worker 
197*a71a9546SAutomerger Merge Worker 		printf(" %svmethod", prefix);
198*a71a9546SAutomerger Merge Worker 		switch (data->fwd_method) {
199*a71a9546SAutomerger Merge Worker 		case IP_VS_CONN_F_DROUTE:
200*a71a9546SAutomerger Merge Worker 			printf(" GATE");
201*a71a9546SAutomerger Merge Worker 			break;
202*a71a9546SAutomerger Merge Worker 		case IP_VS_CONN_F_TUNNEL:
203*a71a9546SAutomerger Merge Worker 			printf(" IPIP");
204*a71a9546SAutomerger Merge Worker 			break;
205*a71a9546SAutomerger Merge Worker 		case IP_VS_CONN_F_MASQ:
206*a71a9546SAutomerger Merge Worker 			printf(" MASQ");
207*a71a9546SAutomerger Merge Worker 			break;
208*a71a9546SAutomerger Merge Worker 		default:
209*a71a9546SAutomerger Merge Worker 			/* Hu? */
210*a71a9546SAutomerger Merge Worker 			printf(" UNKNOWN");
211*a71a9546SAutomerger Merge Worker 			break;
212*a71a9546SAutomerger Merge Worker 		}
213*a71a9546SAutomerger Merge Worker 	}
214*a71a9546SAutomerger Merge Worker 
215*a71a9546SAutomerger Merge Worker 	if (data->bitmask & XT_IPVS_VPORTCTL) {
216*a71a9546SAutomerger Merge Worker 		if (data->invert & XT_IPVS_VPORTCTL)
217*a71a9546SAutomerger Merge Worker 			printf(" !");
218*a71a9546SAutomerger Merge Worker 
219*a71a9546SAutomerger Merge Worker 		printf(" %svportctl %u", prefix, ntohs(data->vportctl));
220*a71a9546SAutomerger Merge Worker 	}
221*a71a9546SAutomerger Merge Worker }
222*a71a9546SAutomerger Merge Worker 
ipvs_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)223*a71a9546SAutomerger Merge Worker static void ipvs_mt4_print(const void *ip, const struct xt_entry_match *match,
224*a71a9546SAutomerger Merge Worker 			   int numeric)
225*a71a9546SAutomerger Merge Worker {
226*a71a9546SAutomerger Merge Worker 	const struct xt_ipvs_mtinfo *data = (const void *)match->data;
227*a71a9546SAutomerger Merge Worker 	ipvs_mt_dump(ip, data, NFPROTO_IPV4, numeric, "");
228*a71a9546SAutomerger Merge Worker }
229*a71a9546SAutomerger Merge Worker 
ipvs_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)230*a71a9546SAutomerger Merge Worker static void ipvs_mt6_print(const void *ip, const struct xt_entry_match *match,
231*a71a9546SAutomerger Merge Worker 			   int numeric)
232*a71a9546SAutomerger Merge Worker {
233*a71a9546SAutomerger Merge Worker 	const struct xt_ipvs_mtinfo *data = (const void *)match->data;
234*a71a9546SAutomerger Merge Worker 	ipvs_mt_dump(ip, data, NFPROTO_IPV6, numeric, "");
235*a71a9546SAutomerger Merge Worker }
236*a71a9546SAutomerger Merge Worker 
ipvs_mt4_save(const void * ip,const struct xt_entry_match * match)237*a71a9546SAutomerger Merge Worker static void ipvs_mt4_save(const void *ip, const struct xt_entry_match *match)
238*a71a9546SAutomerger Merge Worker {
239*a71a9546SAutomerger Merge Worker 	const struct xt_ipvs_mtinfo *data = (const void *)match->data;
240*a71a9546SAutomerger Merge Worker 	ipvs_mt_dump(ip, data, NFPROTO_IPV4, true, "--");
241*a71a9546SAutomerger Merge Worker }
242*a71a9546SAutomerger Merge Worker 
ipvs_mt6_save(const void * ip,const struct xt_entry_match * match)243*a71a9546SAutomerger Merge Worker static void ipvs_mt6_save(const void *ip, const struct xt_entry_match *match)
244*a71a9546SAutomerger Merge Worker {
245*a71a9546SAutomerger Merge Worker 	const struct xt_ipvs_mtinfo *data = (const void *)match->data;
246*a71a9546SAutomerger Merge Worker 	ipvs_mt_dump(ip, data, NFPROTO_IPV6, true, "--");
247*a71a9546SAutomerger Merge Worker }
248*a71a9546SAutomerger Merge Worker 
249*a71a9546SAutomerger Merge Worker static struct xtables_match ipvs_matches_reg[] = {
250*a71a9546SAutomerger Merge Worker 	{
251*a71a9546SAutomerger Merge Worker 		.version       = XTABLES_VERSION,
252*a71a9546SAutomerger Merge Worker 		.name          = "ipvs",
253*a71a9546SAutomerger Merge Worker 		.revision      = 0,
254*a71a9546SAutomerger Merge Worker 		.family        = NFPROTO_IPV4,
255*a71a9546SAutomerger Merge Worker 		.size          = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
256*a71a9546SAutomerger Merge Worker 		.userspacesize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
257*a71a9546SAutomerger Merge Worker 		.help          = ipvs_mt_help,
258*a71a9546SAutomerger Merge Worker 		.x6_parse      = ipvs_mt_parse,
259*a71a9546SAutomerger Merge Worker 		.x6_fcheck     = ipvs_mt_check,
260*a71a9546SAutomerger Merge Worker 		.print         = ipvs_mt4_print,
261*a71a9546SAutomerger Merge Worker 		.save          = ipvs_mt4_save,
262*a71a9546SAutomerger Merge Worker 		.x6_options    = ipvs_mt_opts,
263*a71a9546SAutomerger Merge Worker 	},
264*a71a9546SAutomerger Merge Worker 	{
265*a71a9546SAutomerger Merge Worker 		.version       = XTABLES_VERSION,
266*a71a9546SAutomerger Merge Worker 		.name          = "ipvs",
267*a71a9546SAutomerger Merge Worker 		.revision      = 0,
268*a71a9546SAutomerger Merge Worker 		.family        = NFPROTO_IPV6,
269*a71a9546SAutomerger Merge Worker 		.size          = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
270*a71a9546SAutomerger Merge Worker 		.userspacesize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
271*a71a9546SAutomerger Merge Worker 		.help          = ipvs_mt_help,
272*a71a9546SAutomerger Merge Worker 		.x6_parse      = ipvs_mt_parse,
273*a71a9546SAutomerger Merge Worker 		.x6_fcheck     = ipvs_mt_check,
274*a71a9546SAutomerger Merge Worker 		.print         = ipvs_mt6_print,
275*a71a9546SAutomerger Merge Worker 		.save          = ipvs_mt6_save,
276*a71a9546SAutomerger Merge Worker 		.x6_options    = ipvs_mt_opts,
277*a71a9546SAutomerger Merge Worker 	},
278*a71a9546SAutomerger Merge Worker };
279*a71a9546SAutomerger Merge Worker 
_init(void)280*a71a9546SAutomerger Merge Worker void _init(void)
281*a71a9546SAutomerger Merge Worker {
282*a71a9546SAutomerger Merge Worker 	xtables_register_matches(ipvs_matches_reg,
283*a71a9546SAutomerger Merge Worker 				 ARRAY_SIZE(ipvs_matches_reg));
284*a71a9546SAutomerger Merge Worker }
285