blob: ea5d9fb40dc5a389973985253be0e5a22254b578 [file] [log] [blame]
/*
* (C) 2009 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <stddef.h>
#include <xtables.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_cluster.h>
/* hack to keep for check */
static unsigned int total_nodes;
static unsigned int node_mask;
static void
cluster_help(void)
{
printf(
"cluster match options:\n"
" --cluster-total-nodes <num> Set number of total nodes in cluster\n"
" [!] --cluster-local-node <num> Set the local node number\n"
" [!] --cluster-local-nodemask <num> Set the local node mask\n"
" --cluster-hash-seed <num> Set seed value of the Jenkins hash\n");
}
enum {
CLUSTER_OPT_TOTAL_NODES,
CLUSTER_OPT_LOCAL_NODE,
CLUSTER_OPT_NODE_MASK,
CLUSTER_OPT_HASH_SEED,
};
static const struct option cluster_opts[] = {
{ "cluster-total-nodes", 1, NULL, CLUSTER_OPT_TOTAL_NODES },
{ "cluster-local-node", 1, NULL, CLUSTER_OPT_LOCAL_NODE },
{ "cluster-local-nodemask", 1, NULL, CLUSTER_OPT_NODE_MASK },
{ "cluster-hash-seed", 1, NULL, CLUSTER_OPT_HASH_SEED },
{ .name = NULL }
};
static int
cluster_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct xt_cluster_match_info *info = (void *)(*match)->data;
unsigned int num;
switch (c) {
case CLUSTER_OPT_TOTAL_NODES:
if (*flags & (1 << c)) {
xtables_error(PARAMETER_PROBLEM,
"Can only specify "
"`--cluster-total-nodes' once");
}
if (!xtables_strtoui(optarg, NULL, &num, 1,
XT_CLUSTER_NODES_MAX)) {
xtables_error(PARAMETER_PROBLEM,
"Unable to parse `%s' in "
"`--cluster-total-nodes'", optarg);
}
total_nodes = num;
info->total_nodes = total_nodes = num;
*flags |= 1 << c;
break;
case CLUSTER_OPT_LOCAL_NODE:
if (*flags & (1 << c)) {
xtables_error(PARAMETER_PROBLEM,
"Can only specify "
"`--cluster-local-node' once");
}
if (*flags & (1 << CLUSTER_OPT_NODE_MASK)) {
xtables_error(PARAMETER_PROBLEM, "You cannot use "
"`--cluster-local-nodemask' and "
"`--cluster-local-node'");
}
xtables_check_inverse(optarg, &invert, &optind, 0, argv);
if (!xtables_strtoui(optarg, NULL, &num, 1,
XT_CLUSTER_NODES_MAX)) {
xtables_error(PARAMETER_PROBLEM,
"Unable to parse `%s' in "
"`--cluster-local-node'", optarg);
}
if (invert)
info->flags |= (1 << XT_CLUSTER_F_INV);
info->node_mask = node_mask = (1 << (num - 1));
*flags |= 1 << c;
break;
case CLUSTER_OPT_NODE_MASK:
if (*flags & (1 << c)) {
xtables_error(PARAMETER_PROBLEM,
"Can only specify "
"`--cluster-local-node' once");
}
if (*flags & (1 << CLUSTER_OPT_LOCAL_NODE)) {
xtables_error(PARAMETER_PROBLEM, "You cannot use "
"`--cluster-local-nodemask' and "
"`--cluster-local-node'");
}
xtables_check_inverse(optarg, &invert, &optind, 0, argv);
if (!xtables_strtoui(optarg, NULL, &num, 1,
XT_CLUSTER_NODES_MAX)) {
xtables_error(PARAMETER_PROBLEM,
"Unable to parse `%s' in "
"`--cluster-local-node'", optarg);
}
if (invert)
info->flags |= (1 << XT_CLUSTER_F_INV);
info->node_mask = node_mask = num;
*flags |= 1 << c;
break;
case CLUSTER_OPT_HASH_SEED:
if (*flags & (1 << c)) {
xtables_error(PARAMETER_PROBLEM,
"Can only specify "
"`--cluster-hash-seed' once");
}
if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) {
xtables_error(PARAMETER_PROBLEM,
"Unable to parse `%s'", optarg);
}
info->hash_seed = num;
*flags |= 1 << c;
break;
default:
return 0;
}
return 1;
}
static void
cluster_check(unsigned int flags)
{
if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) |
(1 << CLUSTER_OPT_LOCAL_NODE) |
(1 << CLUSTER_OPT_HASH_SEED)))
== ((1 << CLUSTER_OPT_TOTAL_NODES) |
(1 << CLUSTER_OPT_LOCAL_NODE) |
(1 << CLUSTER_OPT_HASH_SEED))) {
if (node_mask >= (1ULL << total_nodes)) {
xtables_error(PARAMETER_PROBLEM,
"cluster match: "
"`--cluster-local-node' "
"must be <= `--cluster-total-nodes'");
}
return;
}
if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) |
(1 << CLUSTER_OPT_NODE_MASK) |
(1 << CLUSTER_OPT_HASH_SEED)))
== ((1 << CLUSTER_OPT_TOTAL_NODES) |
(1 << CLUSTER_OPT_NODE_MASK) |
(1 << CLUSTER_OPT_HASH_SEED))) {
if (node_mask >= (1ULL << total_nodes)) {
xtables_error(PARAMETER_PROBLEM,
"cluster match: "
"`--cluster-local-nodemask' too big "
"for `--cluster-total-nodes'");
}
return;
}
if (!(flags & (1 << CLUSTER_OPT_TOTAL_NODES))) {
xtables_error(PARAMETER_PROBLEM,
"cluster match: `--cluster-total-nodes' "
"is missing");
}
if (!(flags & (1 << CLUSTER_OPT_HASH_SEED))) {
xtables_error(PARAMETER_PROBLEM,
"cluster match: `--cluster-hash-seed' "
"is missing");
}
if (!(flags & ((1 << (CLUSTER_OPT_LOCAL_NODE) |
(1 << (CLUSTER_OPT_NODE_MASK)))))) {
xtables_error(PARAMETER_PROBLEM,
"cluster match: `--cluster-local-node' or"
"`--cluster-local-nodemask' is missing");
}
}
static void
cluster_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_cluster_match_info *info = (void *)match->data;
printf("cluster ");
if (info->flags & XT_CLUSTER_F_INV)
printf("!node_mask=0x%08x ", info->node_mask);
else
printf("node_mask=0x%08x ", info->node_mask);
printf("total_nodes=%u hash_seed=0x%08x ",
info->total_nodes, info->hash_seed);
}
static void
cluster_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_cluster_match_info *info = (void *)match->data;
if (info->flags & XT_CLUSTER_F_INV)
printf("! --cluster-local-nodemask 0x%08x ", info->node_mask);
else
printf("--cluster-local-nodemask 0x%08x ", info->node_mask);
printf("--cluster-total-nodes %u --cluster-hash-seed 0x%08x ",
info->total_nodes, info->hash_seed);
}
static struct xtables_match cluster_mt_reg = {
.family = NFPROTO_UNSPEC,
.name = "cluster",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_cluster_match_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_cluster_match_info)),
.help = cluster_help,
.parse = cluster_parse,
.final_check = cluster_check,
.print = cluster_print,
.save = cluster_save,
.extra_opts = cluster_opts,
};
void _init(void)
{
xtables_register_match(&cluster_mt_reg);
}