[iptables] extensions: add `cluster' match support

Pablo Neira netfilter-cvslog-bounces at lists.netfilter.org
Wed May 6 13:01:59 CEST 2009


Gitweb:		http://git.netfilter.org/cgi-bin/gitweb.cgi?p=iptables.git;a=commit;h=cd958a6c92c84095a439780b53832bb3aae2d512
commit cd958a6c92c84095a439780b53832bb3aae2d512
Author:     Pablo Neira Ayuso <pablo at netfilter.org>
AuthorDate: Wed May 6 13:01:20 2009 +0200
Commit:     Pablo Neira Ayuso <pablo at netfilter.org>
CommitDate: Wed May 6 13:01:20 2009 +0200

    extensions: add `cluster' match support
    
    This patch adds support for the cluster match to iptables.
    
    Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>
       via  cd958a6c92c84095a439780b53832bb3aae2d512 (commit)
      from  467fa9fe70f08342a50b859ddd431c848a956679 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit cd958a6c92c84095a439780b53832bb3aae2d512
Author: Pablo Neira Ayuso <pablo at netfilter.org>
Date:   Wed May 6 13:01:20 2009 +0200

    extensions: add `cluster' match support
    
    This patch adds support for the cluster match to iptables.
    
    Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>

-----------------------------------------------------------------------

 extensions/libxt_cluster.c           |  238 ++++++++++++++++++++++++++++++++++
 extensions/libxt_cluster.man         |   62 +++++++++
 include/linux/netfilter/xt_cluster.h |   17 +++
 3 files changed, 317 insertions(+), 0 deletions(-)
 create mode 100644 extensions/libxt_cluster.c
 create mode 100644 extensions/libxt_cluster.man
 create mode 100644 include/linux/netfilter/xt_cluster.h
This patch adds support for the cluster match to iptables.

Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>

diff --git a/extensions/libxt_cluster.c b/extensions/libxt_cluster.c
new file mode 100644
index 0000000..1659a60
--- /dev/null
+++ b/extensions/libxt_cluster.c
@@ -0,0 +1,238 @@
+/*
+ * (C) 2009 by Pablo Neira Ayuso <pablo at 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);
+
+		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);
+
+		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		= AF_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);
+}
diff --git a/extensions/libxt_cluster.man b/extensions/libxt_cluster.man
new file mode 100644
index 0000000..6081be1
--- /dev/null
+++ b/extensions/libxt_cluster.man
@@ -0,0 +1,62 @@
+Allows you to deploy gateway and back-end load-sharing clusters without the
+need of load-balancers.
+.PP
+This match requires that all the nodes see the same packets. Thus, the cluster
+match decides if this node has to handle a packet given the following options:
+.TP
+\fB\-\-cluster\-total\-nodes \fInum\fP
+Set number of total nodes in cluster.
+.TP
+[\fB!\fP] \fB\-\-cluster\-local\-node \fInum\fP
+Set the local node number ID.
+.TP
+[\fB!\fP] \fB\-\-cluster\-local\-nodemask \fImask\fP
+Set the local node number ID mask. You can use this option instead
+of \fB\-\-cluster\-local\-node.
+.TP
+\fB\-\-cluster\-hash\-seed \fIvalue\fP
+Set seed value of the Jenkins hash.
+.PP
+Example:
+.IP
+iptables \-A PREROUTING \-t mangle \-i eth1 \-m cluster \
+\-\-cluster\-total\-nodes 2 \-\-cluster\-local\-node 1 \
+\-\-cluster\-hash\-seed 0xdeadbeef \
+\-j MARK \-\-set-mark 0xffff
+.IP
+iptables \-A PREROUTING \-t mangle \-i eth2 \-m cluster \
+\-\-cluster\-total\-nodes 2 \-\-cluster\-local\-node 1 \
+\-\-cluster\-hash\-seed 0xdeadbeef \
+\-j MARK -\-set\-mark 0xffff
+.IP
+iptables \-A PREROUTING \-t mangle \-i eth1 \
+\-m mark ! \-\-mark 0xffff \-j DROP
+.IP
+iptables \-A PREROUTING \-t mangle \-i eth2 \
+\-m mark ! \-\-mark 0xffff \-j DROP
+.PP
+And the following commands to make all nodes see the same packets:
+.IP
+ip maddr add 01:00:5e:00:01:01 dev eth1
+.IP
+ip maddr add 01:00:5e:00:01:02 dev eth2
+.IP
+arptables \-A OUTPUT \-o eth1 \-\-h\-length 6 \
+\-j mangle \-\-mangle-mac-s 01:00:5e:00:01:01
+.IP
+arptables \-A INPUT \-i eth1 \-\-h-length 6 \
+\-\-destination-mac 01:00:5e:00:01:01 \
+\-j mangle \-\-mangle\-mac\-d 00:zz:yy:xx:5a:27
+.IP
+arptables \-A OUTPUT \-o eth2 \-\-h\-length 6 \
+\-j mangle \-\-mangle\-mac\-s 01:00:5e:00:01:02
+.IP
+arptables \-A INPUT \-i eth2 \-\-h\-length 6 \
+\-\-destination\-mac 01:00:5e:00:01:02 \
+\-j mangle \-\-mangle\-mac\-d 00:zz:yy:xx:5a:27
+.PP
+In the case of TCP connections, pickup facility has to be disabled
+to avoid marking TCP ACK packets coming in the reply direction as
+valid.
+.IP
+echo 0 > /proc/sys/net/netfilter/nf_conntrack_tcp_loose
diff --git a/include/linux/netfilter/xt_cluster.h b/include/linux/netfilter/xt_cluster.h
new file mode 100644
index 0000000..8866826
--- /dev/null
+++ b/include/linux/netfilter/xt_cluster.h
@@ -0,0 +1,17 @@
+#ifndef _XT_CLUSTER_MATCH_H
+#define _XT_CLUSTER_MATCH_H
+
+enum xt_cluster_flags {
+	XT_CLUSTER_F_INV	= (1 << 0)
+};
+
+struct xt_cluster_match_info {
+	u_int32_t		total_nodes;
+	u_int32_t		node_mask;
+	u_int32_t		hash_seed;
+	u_int32_t		flags;
+};
+
+#define XT_CLUSTER_NODES_MAX	32
+
+#endif /* _XT_CLUSTER_MATCH_H */



More information about the netfilter-cvslog mailing list