libxt_cluster.c revision 42979363f3958b4436c6d2503753c182c58e55ea
1/*
2 * (C) 2009 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11#include <getopt.h>
12#include <stddef.h>
13
14#include <xtables.h>
15#include <linux/netfilter/x_tables.h>
16#include <linux/netfilter/xt_cluster.h>
17
18/* hack to keep for check */
19static unsigned int total_nodes;
20static unsigned int node_mask;
21
22static void
23cluster_help(void)
24{
25	printf(
26"cluster match options:\n"
27"  --cluster-total-nodes <num>		Set number of total nodes in cluster\n"
28"  [!] --cluster-local-node <num>	Set the local node number\n"
29"  [!] --cluster-local-nodemask <num>	Set the local node mask\n"
30"  --cluster-hash-seed <num>		Set seed value of the Jenkins hash\n");
31}
32
33enum {
34	CLUSTER_OPT_TOTAL_NODES,
35	CLUSTER_OPT_LOCAL_NODE,
36	CLUSTER_OPT_NODE_MASK,
37	CLUSTER_OPT_HASH_SEED,
38};
39
40static const struct option cluster_opts[] = {
41	{ "cluster-total-nodes", 	1, NULL, CLUSTER_OPT_TOTAL_NODES },
42	{ "cluster-local-node", 	1, NULL, CLUSTER_OPT_LOCAL_NODE },
43	{ "cluster-local-nodemask",	1, NULL, CLUSTER_OPT_NODE_MASK },
44	{ "cluster-hash-seed",		1, NULL, CLUSTER_OPT_HASH_SEED },
45	{ .name = NULL }
46};
47
48static int
49cluster_parse(int c, char **argv, int invert, unsigned int *flags,
50	      const void *entry, struct xt_entry_match **match)
51{
52	struct xt_cluster_match_info *info = (void *)(*match)->data;
53	unsigned int num;
54
55	switch (c) {
56	case CLUSTER_OPT_TOTAL_NODES:
57		if (*flags & (1 << c)) {
58			xtables_error(PARAMETER_PROBLEM,
59				      "Can only specify "
60				      "`--cluster-total-nodes' once");
61		}
62		if (!xtables_strtoui(optarg, NULL, &num, 1,
63				     XT_CLUSTER_NODES_MAX)) {
64			xtables_error(PARAMETER_PROBLEM,
65				      "Unable to parse `%s' in "
66				      "`--cluster-total-nodes'", optarg);
67		}
68		total_nodes = num;
69		info->total_nodes = total_nodes = num;
70		*flags |= 1 << c;
71		break;
72	case CLUSTER_OPT_LOCAL_NODE:
73		if (*flags & (1 << c)) {
74			xtables_error(PARAMETER_PROBLEM,
75				      "Can only specify "
76				      "`--cluster-local-node' once");
77		}
78		if (*flags & (1 << CLUSTER_OPT_NODE_MASK)) {
79			xtables_error(PARAMETER_PROBLEM, "You cannot use "
80				      "`--cluster-local-nodemask' and "
81				      "`--cluster-local-node'");
82		}
83		xtables_check_inverse(optarg, &invert, &optind, 0);
84
85		if (!xtables_strtoui(optarg, NULL, &num, 1,
86				     XT_CLUSTER_NODES_MAX)) {
87			xtables_error(PARAMETER_PROBLEM,
88				      "Unable to parse `%s' in "
89				      "`--cluster-local-node'", optarg);
90		}
91		if (invert)
92			info->flags |= (1 << XT_CLUSTER_F_INV);
93
94		info->node_mask = node_mask = (1 << (num - 1));
95		*flags |= 1 << c;
96		break;
97	case CLUSTER_OPT_NODE_MASK:
98		if (*flags & (1 << c)) {
99			xtables_error(PARAMETER_PROBLEM,
100				      "Can only specify "
101				      "`--cluster-local-node' once");
102		}
103		if (*flags & (1 << CLUSTER_OPT_LOCAL_NODE)) {
104			xtables_error(PARAMETER_PROBLEM, "You cannot use "
105				      "`--cluster-local-nodemask' and "
106				      "`--cluster-local-node'");
107		}
108		xtables_check_inverse(optarg, &invert, &optind, 0);
109
110		if (!xtables_strtoui(optarg, NULL, &num, 1,
111				     XT_CLUSTER_NODES_MAX)) {
112			xtables_error(PARAMETER_PROBLEM,
113				      "Unable to parse `%s' in "
114				      "`--cluster-local-node'", optarg);
115		}
116		if (invert)
117			info->flags |= (1 << XT_CLUSTER_F_INV);
118
119		info->node_mask = node_mask = num;
120		*flags |= 1 << c;
121		break;
122
123	case CLUSTER_OPT_HASH_SEED:
124		if (*flags & (1 << c)) {
125			xtables_error(PARAMETER_PROBLEM,
126				      "Can only specify "
127				      "`--cluster-hash-seed' once");
128		}
129		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) {
130			xtables_error(PARAMETER_PROBLEM,
131				      "Unable to parse `%s'", optarg);
132		}
133		info->hash_seed = num;
134		*flags |= 1 << c;
135		break;
136	default:
137		return 0;
138	}
139
140	return 1;
141}
142
143static void
144cluster_check(unsigned int flags)
145{
146	if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) |
147		      (1 << CLUSTER_OPT_LOCAL_NODE) |
148		      (1 << CLUSTER_OPT_HASH_SEED)))
149		== ((1 << CLUSTER_OPT_TOTAL_NODES) |
150		    (1 << CLUSTER_OPT_LOCAL_NODE) |
151		    (1 << CLUSTER_OPT_HASH_SEED))) {
152		if (node_mask >= (1ULL << total_nodes)) {
153			xtables_error(PARAMETER_PROBLEM,
154				      "cluster match: "
155				      "`--cluster-local-node' "
156				      "must be <= `--cluster-total-nodes'");
157		}
158		return;
159	}
160	if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) |
161		      (1 << CLUSTER_OPT_NODE_MASK) |
162		      (1 << CLUSTER_OPT_HASH_SEED)))
163		== ((1 << CLUSTER_OPT_TOTAL_NODES) |
164		    (1 << CLUSTER_OPT_NODE_MASK) |
165		    (1 << CLUSTER_OPT_HASH_SEED))) {
166		if (node_mask >= (1ULL << total_nodes)) {
167			xtables_error(PARAMETER_PROBLEM,
168				      "cluster match: "
169				      "`--cluster-local-nodemask' too big "
170				      "for `--cluster-total-nodes'");
171		}
172		return;
173	}
174	if (!(flags & (1 << CLUSTER_OPT_TOTAL_NODES))) {
175		xtables_error(PARAMETER_PROBLEM,
176			      "cluster match: `--cluster-total-nodes' "
177			      "is missing");
178	}
179	if (!(flags & (1 << CLUSTER_OPT_HASH_SEED))) {
180		xtables_error(PARAMETER_PROBLEM,
181			      "cluster match: `--cluster-hash-seed' "
182			      "is missing");
183	}
184	if (!(flags & ((1 << (CLUSTER_OPT_LOCAL_NODE) |
185		       (1 << (CLUSTER_OPT_NODE_MASK)))))) {
186		xtables_error(PARAMETER_PROBLEM,
187			      "cluster match: `--cluster-local-node' or"
188			      "`--cluster-local-nodemask' is missing");
189	}
190}
191
192static void
193cluster_print(const void *ip, const struct xt_entry_match *match, int numeric)
194{
195	const struct xt_cluster_match_info *info = (void *)match->data;
196
197	printf("cluster ");
198	if (info->flags & XT_CLUSTER_F_INV)
199		printf("!node_mask=0x%08x ", info->node_mask);
200	else
201		printf("node_mask=0x%08x ", info->node_mask);
202
203	printf("total_nodes=%u hash_seed=0x%08x ",
204		info->total_nodes, info->hash_seed);
205}
206
207static void
208cluster_save(const void *ip, const struct xt_entry_match *match)
209{
210	const struct xt_cluster_match_info *info = (void *)match->data;
211
212	if (info->flags & XT_CLUSTER_F_INV)
213		printf("! --cluster-local-nodemask 0x%08x ", info->node_mask);
214	else
215		printf("--cluster-local-nodemask 0x%08x ", info->node_mask);
216
217	printf("--cluster-total-nodes %u --cluster-hash-seed 0x%08x ",
218		info->total_nodes, info->hash_seed);
219}
220
221static struct xtables_match cluster_mt_reg = {
222	.family		= NFPROTO_UNSPEC,
223	.name		= "cluster",
224	.version	= XTABLES_VERSION,
225	.size		= XT_ALIGN(sizeof(struct xt_cluster_match_info)),
226	.userspacesize  = XT_ALIGN(sizeof(struct xt_cluster_match_info)),
227 	.help		= cluster_help,
228	.parse		= cluster_parse,
229	.final_check	= cluster_check,
230	.print		= cluster_print,
231	.save		= cluster_save,
232	.extra_opts	= cluster_opts,
233};
234
235void _init(void)
236{
237	xtables_register_match(&cluster_mt_reg);
238}
239