Re: [PATCH] add hash:ip,mark data type to ipset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Wed, 30 Oct 2013, Vytas Dauksa wrote:

> Introduce packet mark support with new ip,mark hash set. This includes
> userspace and kernelspace code, hash:ip,mark set tests and updates man
> page.

Please give an example which demonstrates the usefulness of the set type.

See my comments below about the code.

> ---
>  include/libipset/data.h                            |    3 +
>  include/libipset/linux_ip_set.h                    |    1 +
>  include/libipset/parse.h                           |    2 +
>  include/libipset/print.h                           |    3 +
>  kernel/include/linux/netfilter/ipset/ip_set.h      |    6 +-
>  kernel/include/uapi/linux/netfilter/ipset/ip_set.h |    1 +
>  kernel/net/netfilter/ipset/Kbuild                  |    3 +-
>  kernel/net/netfilter/ipset/Kconfig                 |    9 +
>  kernel/net/netfilter/ipset/ip_set_hash_ipmark.c    |  319 ++++++++++++++++++++
>  lib/Makefile.am                                    |    1 +
>  lib/data.c                                         |    8 +
>  lib/debug.c                                        |    2 +
>  lib/ipset_hash_ipmark.c                            |  167 ++++++++++
>  lib/libipset.map                                   |    2 +
>  lib/parse.c                                        |   30 ++
>  lib/print.c                                        |   35 +++
>  lib/session.c                                      |    8 +
>  src/ipset.8                                        |   49 +++
>  tests/hash:ip,mark.t                               |  125 ++++++++
>  tests/hash:ip,mark.t.list0                         |   10 +
>  tests/hash:ip,mark.t.list1                         |    6 +
>  tests/hash:ip6,mark.t                              |  227 ++++++++++++++
>  tests/hash:ip6,mark.t.list0                        |   10 +
>  tests/hash:ip6,mark.t.list1                        |    6 +
>  tests/ipmarkhash.t                                 |   71 +++++
>  tests/ipmarkhash.t.list0                           |   10 +
>  tests/ipmarkhash.t.list1                           |   10 +
>  tests/resizet.sh                                   |    8 +
>  tests/runtest.sh                                   |    1 +
>  tests/setlist_resize.sh                            |    2 +-
>  30 files changed, 1131 insertions(+), 4 deletions(-)
>  create mode 100644 kernel/net/netfilter/ipset/ip_set_hash_ipmark.c
>  create mode 100644 lib/ipset_hash_ipmark.c
>  create mode 100644 tests/hash:ip,mark.t
>  create mode 100644 tests/hash:ip,mark.t.list0
>  create mode 100644 tests/hash:ip,mark.t.list1
>  create mode 100644 tests/hash:ip6,mark.t
>  create mode 100644 tests/hash:ip6,mark.t.list0
>  create mode 100644 tests/hash:ip6,mark.t.list1
>  create mode 100644 tests/ipmarkhash.t
>  create mode 100644 tests/ipmarkhash.t.list0
>  create mode 100644 tests/ipmarkhash.t.list1
> 
> diff --git a/include/libipset/data.h b/include/libipset/data.h
> index b6e75e8..c3a8ac4 100644
> --- a/include/libipset/data.h
> +++ b/include/libipset/data.h
> @@ -22,6 +22,7 @@ enum ipset_opt {
>  	IPSET_OPT_IP_FROM = IPSET_OPT_IP,
>  	IPSET_OPT_IP_TO,
>  	IPSET_OPT_CIDR,
> +	IPSET_OPT_MARK,
>  	IPSET_OPT_PORT,
>  	IPSET_OPT_PORT_FROM = IPSET_OPT_PORT,
>  	IPSET_OPT_PORT_TO,
> @@ -80,6 +81,7 @@ enum ipset_opt {
>  	| IPSET_FLAG(IPSET_OPT_IP)	\
>  	| IPSET_FLAG(IPSET_OPT_IP_TO)	\
>  	| IPSET_FLAG(IPSET_OPT_CIDR)	\
> +	| IPSET_FLAG(IPSET_OPT_MARK)	\
>  	| IPSET_FLAG(IPSET_OPT_PORT)	\
>  	| IPSET_FLAG(IPSET_OPT_PORT_TO)	\
>  	| IPSET_FLAG(IPSET_OPT_TIMEOUT)	\

The MARK option is not valid as a create flag: there's no such data to 
pass to the kernel when creating the set type.

> @@ -96,6 +98,7 @@ enum ipset_opt {
>  	(IPSET_FLAG(IPSET_OPT_IP)	\
>  	| IPSET_FLAG(IPSET_OPT_IP_TO)	\
>  	| IPSET_FLAG(IPSET_OPT_CIDR)	\
> +	| IPSET_FLAG(IPSET_OPT_MARK)	\
>  	| IPSET_FLAG(IPSET_OPT_PORT)	\
>  	| IPSET_FLAG(IPSET_OPT_PORT_TO)	\
>  	| IPSET_FLAG(IPSET_OPT_TIMEOUT)	\
> diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h
> index 847bbff..c57f81e 100644
> --- a/include/libipset/linux_ip_set.h
> +++ b/include/libipset/linux_ip_set.h
> @@ -83,6 +83,7 @@ enum {
>  	IPSET_ATTR_PROTO,	/* 7 */
>  	IPSET_ATTR_CADT_FLAGS,	/* 8 */
>  	IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,	/* 9 */
> +	IPSET_ATTR_MARK,	/* 10 */
>  	/* Reserve empty slots */
>  	IPSET_ATTR_CADT_MAX = 16,
>  	/* Create-only specific attributes */
> diff --git a/include/libipset/parse.h b/include/libipset/parse.h
> index 5c46a88..55981f2 100644
> --- a/include/libipset/parse.h
> +++ b/include/libipset/parse.h
> @@ -29,6 +29,8 @@ extern int ipset_parse_ether(struct ipset_session *session,
>  extern int ipset_parse_port(struct ipset_session *session,
>  			    enum ipset_opt opt, const char *str,
>  			    const char *proto);
> +extern int ipset_parse_mark(struct ipset_session *session,
> +			    enum ipset_opt opt, const char *str);
>  extern int ipset_parse_tcpudp_port(struct ipset_session *session,
>  				   enum ipset_opt opt, const char *str,
>  				   const char *proto);
> diff --git a/include/libipset/print.h b/include/libipset/print.h
> index f2a6095..b8fa709 100644
> --- a/include/libipset/print.h
> +++ b/include/libipset/print.h
> @@ -37,6 +37,9 @@ extern int ipset_print_name(char *buf, unsigned int len,
>  extern int ipset_print_port(char *buf, unsigned int len,
>  			    const struct ipset_data *data,
>  			    enum ipset_opt opt, uint8_t env);
> +extern int ipset_print_mark(char *buf, unsigned int len,
> +			    const struct ipset_data *data,
> +			    enum ipset_opt opt, uint8_t env);
>  extern int ipset_print_iface(char *buf, unsigned int len,
>  			     const struct ipset_data *data,
>  			     enum ipset_opt opt, uint8_t env);
> diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h
> index 7cde1cf..f5cb44f 100644
> --- a/kernel/include/linux/netfilter/ipset/ip_set.h
> +++ b/kernel/include/linux/netfilter/ipset/ip_set.h
> @@ -40,11 +40,13 @@ enum ip_set_feature {
>  	IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
>  	IPSET_TYPE_IFACE_FLAG = 5,
>  	IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG),
> -	IPSET_TYPE_NOMATCH_FLAG = 6,
> +	IPSET_TYPE_MARK_FLAG = 6,
> +	IPSET_TYPE_MARK = (1 << IPSET_TYPE_MARK_FLAG),
> +	IPSET_TYPE_NOMATCH_FLAG = 7,
>  	IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG),
>  	/* Strictly speaking not a feature, but a flag for dumping:
>  	 * this settype must be dumped last */
> -	IPSET_DUMP_LAST_FLAG = 7,
> +	IPSET_DUMP_LAST_FLAG = 8,
>  	IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
>  };

The features member of struct ip_set_type is u8, so you must change it to 
at least u16. At the same time reorder the members so that features comes 
after revision_max.
  
> diff --git a/kernel/include/uapi/linux/netfilter/ipset/ip_set.h b/kernel/include/uapi/linux/netfilter/ipset/ip_set.h
> index 847bbff..c57f81e 100644
> --- a/kernel/include/uapi/linux/netfilter/ipset/ip_set.h
> +++ b/kernel/include/uapi/linux/netfilter/ipset/ip_set.h
> @@ -83,6 +83,7 @@ enum {
>  	IPSET_ATTR_PROTO,	/* 7 */
>  	IPSET_ATTR_CADT_FLAGS,	/* 8 */
>  	IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,	/* 9 */
> +	IPSET_ATTR_MARK,	/* 10 */
>  	/* Reserve empty slots */
>  	IPSET_ATTR_CADT_MAX = 16,
>  	/* Create-only specific attributes */
> diff --git a/kernel/net/netfilter/ipset/Kbuild b/kernel/net/netfilter/ipset/Kbuild
> index 5564cb5..9e52ef8 100644
> --- a/kernel/net/netfilter/ipset/Kbuild
> +++ b/kernel/net/netfilter/ipset/Kbuild
> @@ -1,10 +1,11 @@
>  NOSTDINC_FLAGS += -I$(KDIR)/include
> -EXTRA_CFLAGS := -DIP_SET_MAX=$(IP_SET_MAX)
> +EXTRA_CFLAGS := -DCONFIG_IP_SET_MAX=$(IP_SET_MAX)

Why do you want to change this back? Config settings are handled in
kernel/include/linux/netfilter/ipset/ip_set_compat.h.in.
  
>  ip_set-y := ip_set_core.o ip_set_getport.o pfxlen.o
>  obj-m += ip_set.o
>  obj-m += ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o ip_set_bitmap_port.o
>  obj-m += ip_set_hash_ip.o ip_set_hash_ipport.o ip_set_hash_ipportip.o
> +obj-m += ip_set_hash_ipmark.o
>  obj-m += ip_set_hash_ipportnet.o
>  obj-m += ip_set_hash_net.o ip_set_hash_netport.o ip_set_hash_netiface.o
>  obj-m += ip_set_hash_netnet.o ip_set_hash_netportnet.o
> diff --git a/kernel/net/netfilter/ipset/Kconfig b/kernel/net/netfilter/ipset/Kconfig
> index a2d6263..638faa7 100644
> --- a/kernel/net/netfilter/ipset/Kconfig
> +++ b/kernel/net/netfilter/ipset/Kconfig
> @@ -61,6 +61,15 @@ config IP_SET_HASH_IP
>  
>  	  To compile it as a module, choose M here.  If unsure, say N.
>  
> +config IP_SET_HASH_IPMARK
> +	tristate "hash:ip,mark set support"
> +	depends on IP_SET
> +	help
> +	  This option adds the hash:ip,mark set type support, by which one
> +	  can store IPv4/IPv6 address and mark pairs.
> +
> +	  To compile it as a module, choose M here.  If unsure, say N.
> +
>  config IP_SET_HASH_IPPORT
>  	tristate "hash:ip,port set support"
>  	depends on IP_SET
> diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipmark.c b/kernel/net/netfilter/ipset/ip_set_hash_ipmark.c
> new file mode 100644
> index 0000000..80e549f
> --- /dev/null
> +++ b/kernel/net/netfilter/ipset/ip_set_hash_ipmark.c
> @@ -0,0 +1,319 @@
> +/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxxxxxx>

You should be named here.

> + *
> + * 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.
> + */
> +
> +/* Kernel module implementing an IP set type: the hash:ip,mark type */
> +
> +#include <linux/jhash.h>
> +#include <linux/module.h>
> +#include <linux/ip.h>
> +#include <linux/skbuff.h>
> +#include <linux/errno.h>
> +#include <linux/random.h>
> +#include <net/ip.h>
> +#include <net/ipv6.h>
> +#include <net/netlink.h>
> +#include <net/tcp.h>
> +
> +#include <linux/netfilter.h>
> +#include <linux/netfilter/ipset/pfxlen.h>
> +#include <linux/netfilter/ipset/ip_set.h>
> +#include <linux/netfilter/ipset/ip_set_hash.h>
> +
> +#define IPSET_TYPE_REV_MIN	0
> +#define IPSET_TYPE_REV_MAX	0
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@xxxxxxxxxxxxxx>");
> +IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
> +MODULE_ALIAS("ip_set_hash:ip,mark");
> +
> +/* Type specific function prefix */
> +#define HTYPE		hash_ipmark
> +
> +/* IPv4 variant */
> +
> +/* Member elements */
> +struct hash_ipmark4_elem {
> +	__be32 ip;
> +	__be32 mark;

Mark is in host order, so __u32 is more appropriate.

> +};
> +
> +/* Common functions */
> +
> +static inline bool
> +hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1,
> +			const struct hash_ipmark4_elem *ip2,
> +			u32 *multi)
> +{
> +	return ip1->ip == ip2->ip &&
> +	       ip1->mark == ip2->mark;
> +}
> +
> +static bool
> +hash_ipmark4_data_list(struct sk_buff *skb,
> +		       const struct hash_ipmark4_elem *data)
> +{
> +	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
> +	    nla_put_net32(skb, IPSET_ATTR_MARK, data->mark))
> +		goto nla_put_failure;
> +	return 0;
> +
> +nla_put_failure:
> +	return 1;
> +}
> +
> +static inline void
> +hash_ipmark4_data_next(struct hash_ipmark4_elem *next,
> +		       const struct hash_ipmark4_elem *d)
> +{
> +	next->ip = d->ip;
> +}
> +
> +#define MTYPE           hash_ipmark4
> +#define PF              4
> +#define HOST_MASK       32
> +#define HKEY_DATALEN	sizeof(struct hash_ipmark4_elem)
> +#include "ip_set_hash_gen.h"
> +
> +static int
> +hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb,
> +		  const struct xt_action_param *par,
> +		  enum ipset_adt adt, struct ip_set_adt_opt *opt)
> +{
> +	ipset_adtfn adtfn = set->variant->adt[adt];
> +	struct hash_ipmark4_elem e = { };
> +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
> +
> +	e.mark = ntohl(skb->mark);

If mark in struct hash_ipmark4_elem is __u32, no conversion is needed at 
all.

> +
> +	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
> +	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
> +}
> +
> +static int
> +hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
> +		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
> +{
> +	const struct hash_ipmark *h = set->data;
> +	ipset_adtfn adtfn = set->variant->adt[adt];
> +	struct hash_ipmark4_elem e = { };
> +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
> +	u32 ip, ip_to = 0;
> +	int ret;
> +
> +	if (unlikely(!tb[IPSET_ATTR_IP] ||
> +		     !tb[IPSET_ATTR_MARK] ||

Wrap tb[IPSET_ATTR_MARK] in ip_set_attr_netorder() call above.

> +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
> +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
> +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
> +		return -IPSET_ERR_PROTOCOL;
> +
> +	if (tb[IPSET_ATTR_LINENO])
> +		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
> +
> +	ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) ||
> +	      ip_set_get_extensions(set, tb, &ext);
> +	if (ret)
> +		return ret;
> +
> +	if (tb[IPSET_ATTR_MARK])
> +		e.mark = nla_get_be32(tb[IPSET_ATTR_MARK]);
> +	else
> +		return -IPSET_ERR_PROTOCOL;

tb[IPSET_ATTR_MARK] is checked above, so there's no need for the condition 
here.

> +	if (adt == IPSET_TEST ||
> +	    !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
> +	      tb[IPSET_ATTR_MARK])) {
> +		ret = adtfn(set, &e, &ext, &ext, flags);
> +		return ip_set_eexist(ret, flags) ? 0 : ret;
> +	}
> +
> +	ip_to = ip = ntohl(e.ip);
> +	if (tb[IPSET_ATTR_IP_TO]) {
> +		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
> +		if (ret)
> +			return ret;
> +		if (ip > ip_to)
> +			swap(ip, ip_to);
> +	} else if (tb[IPSET_ATTR_CIDR]) {
> +		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
> +
> +		if (!cidr || cidr > 32)
> +			return -IPSET_ERR_INVALID_CIDR;
> +		ip_set_mask_from_to(ip, ip_to, cidr);
> +	}
> +
> +	if (retried)
> +		ip = ntohl(h->next.ip);
> +	for (; !before(ip_to, ip); ip++) {
> +		e.ip = htonl(ip);
> +		ret = adtfn(set, &e, &ext, &ext, flags);
> +
> +		if (ret && !ip_set_eexist(ret, flags))
> +			return ret;
> +		else
> +			ret = 0;
> +	}
> +	return ret;
> +}
> +
> +/* IPv6 variant */
> +
> +struct hash_ipmark6_elem {
> +	union nf_inet_addr ip;
> +	__be32 mark;

The same comments go here and below as for the IPv4 variant above.

> +};
> +
> +/* Common functions */
> +
> +static inline bool
> +hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1,
> +			const struct hash_ipmark6_elem *ip2,
> +			u32 *multi)
> +{
> +	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
> +	       ip1->mark == ip2->mark;
> +}
> +
> +static bool
> +hash_ipmark6_data_list(struct sk_buff *skb,
> +		       const struct hash_ipmark6_elem *data)
> +{
> +	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
> +	    nla_put_net32(skb, IPSET_ATTR_MARK, data->mark))
> +		goto nla_put_failure;
> +	return 0;
> +
> +nla_put_failure:
> +	return 1;
> +}
> +
> +static inline void
> +hash_ipmark6_data_next(struct hash_ipmark4_elem *next,
> +		       const struct hash_ipmark6_elem *d)
> +{
> +}
> +
> +#undef MTYPE
> +#undef PF
> +#undef HOST_MASK
> +#undef HKEY_DATALEN
> +
> +#define MTYPE		hash_ipmark6
> +#define PF		6
> +#define HOST_MASK	128
> +#define HKEY_DATALEN	sizeof(struct hash_ipmark6_elem)
> +#define	IP_SET_EMIT_CREATE
> +#include "ip_set_hash_gen.h"
> +
> +
> +static int
> +hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb,
> +		  const struct xt_action_param *par,
> +		  enum ipset_adt adt, struct ip_set_adt_opt *opt)
> +{
> +	ipset_adtfn adtfn = set->variant->adt[adt];
> +	struct hash_ipmark6_elem e = { };
> +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
> +
> +	e.mark = ntohl(skb->mark);
> +
> +	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
> +	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
> +}
> +
> +static int
> +hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[],
> +		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
> +{
> +	ipset_adtfn adtfn = set->variant->adt[adt];
> +	struct hash_ipmark6_elem e = { };
> +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
> +	int ret;
> +
> +	if (unlikely(!tb[IPSET_ATTR_IP] ||
> +		     !tb[IPSET_ATTR_MARK] ||
> +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
> +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
> +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
> +		     tb[IPSET_ATTR_IP_TO] ||
> +		     tb[IPSET_ATTR_CIDR]))
> +		return -IPSET_ERR_PROTOCOL;
> +
> +	if (tb[IPSET_ATTR_LINENO])
> +		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
> +
> +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
> +	      ip_set_get_extensions(set, tb, &ext);
> +	if (ret)
> +		return ret;
> +
> +	if (tb[IPSET_ATTR_MARK])
> +		e.mark = nla_get_be32(tb[IPSET_ATTR_MARK]);
> +	else
> +		return -IPSET_ERR_PROTOCOL;
> +
> +	if (adt == IPSET_TEST) {
> +		ret = adtfn(set, &e, &ext, &ext, flags);
> +		return ip_set_eexist(ret, flags) ? 0 : ret;
> +	}
> +
> +	ret = adtfn(set, &e, &ext, &ext, flags);
> +	if (ret && !ip_set_eexist(ret, flags))
> +		return ret;
> +	else
> +		ret = 0;
> +
> +	return ret;
> +}
> +
> +static struct ip_set_type hash_ipmark_type __read_mostly = {
> +	.name		= "hash:ip,mark",
> +	.protocol	= IPSET_PROTOCOL,
> +	.features	= IPSET_TYPE_IP | IPSET_TYPE_MARK,
> +	.dimension	= IPSET_DIM_TWO,
> +	.family		= NFPROTO_UNSPEC,
> +	.revision_min	= IPSET_TYPE_REV_MIN,
> +	.revision_max	= IPSET_TYPE_REV_MAX,
> +	.create		= hash_ipmark_create,
> +	.create_policy	= {
> +		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 },
> +		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 },
> +		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 },
> +		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  },
> +		[IPSET_ATTR_MARK]	= { .type = NLA_U32 },
> +		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
> +		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
> +	},
> +	.adt_policy	= {
> +		[IPSET_ATTR_IP]		= { .type = NLA_NESTED },
> +		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED },
> +		[IPSET_ATTR_MARK]	= { .type = NLA_U32 },
> +		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 },
> +		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
> +		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
> +		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },
> +		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 },
> +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },
> +	},
> +	.me		= THIS_MODULE,
> +};
> +
> +static int __init
> +hash_ipmark_init(void)
> +{
> +	return ip_set_type_register(&hash_ipmark_type);
> +}
> +
> +static void __exit
> +hash_ipmark_fini(void)
> +{
> +	ip_set_type_unregister(&hash_ipmark_type);
> +}
> +
> +module_init(hash_ipmark_init);
> +module_exit(hash_ipmark_fini);
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 2234670..6398be4 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -6,6 +6,7 @@ IPSET_SETTYPE_LIST = \
>  	ipset_bitmap_port.c \
>  	ipset_hash_ip.c \
>  	ipset_hash_ipport.c \
> +	ipset_hash_ipmark.c \
>  	ipset_hash_ipportip.c \
>  	ipset_hash_ipportnet.c \
>  	ipset_hash_net.c \
> diff --git a/lib/data.c b/lib/data.c
> index ba4ed57..1f74cd5 100644
> --- a/lib/data.c
> +++ b/lib/data.c
> @@ -41,6 +41,7 @@ struct ipset_data {
>  	uint32_t timeout;
>  	union nf_inet_addr ip;
>  	union nf_inet_addr ip_to;
> +	uint32_t mark;
>  	uint16_t port;
>  	uint16_t port_to;
>  	union {
> @@ -264,6 +265,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
>  	case IPSET_OPT_CIDR:
>  		data->cidr = *(const uint8_t *) value;
>  		break;
> +	case IPSET_OPT_MARK:
> +		data->mark = *(const uint32_t *) value;
> +		break;
>  	case IPSET_OPT_PORT:
>  		data->port = *(const uint16_t *) value;
>  		break;
> @@ -448,6 +452,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
>  		 return &data->ip_to;
>  	case IPSET_OPT_CIDR:
>  		return &data->cidr;
> +	case IPSET_OPT_MARK:
> +		return &data->mark;
>  	case IPSET_OPT_PORT:
>  		return &data->port;
>  	case IPSET_OPT_PORT_TO:
> @@ -542,6 +548,8 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
>  	case IPSET_OPT_IP2_TO:
>  		return family == NFPROTO_IPV4 ? sizeof(uint32_t)
>  					 : sizeof(struct in6_addr);
> +	case IPSET_OPT_MARK:
> +		return sizeof(uint32_t);
>  	case IPSET_OPT_PORT:
>  	case IPSET_OPT_PORT_TO:
>  		return sizeof(uint16_t);
> diff --git a/lib/debug.c b/lib/debug.c
> index a204940..56196ab 100644
> --- a/lib/debug.c
> +++ b/lib/debug.c
> @@ -29,6 +29,7 @@ static const struct ipset_attrname createattr2name[] = {
>  	[IPSET_ATTR_IP]		= { .name = "IP" },
>  	[IPSET_ATTR_IP_TO]	= { .name = "IP_TO" },
>  	[IPSET_ATTR_CIDR]	= { .name = "CIDR" },
> +	[IPSET_ATTR_MARK]	= { .name = "MARK" },

This is unnecessary here too: no MARK option at create.

>  	[IPSET_ATTR_PORT]	= { .name = "PORT" },
>  	[IPSET_ATTR_PORT_TO]	= { .name = "PORT_TO" },
>  	[IPSET_ATTR_TIMEOUT]	= { .name = "TIMEOUT" },
> @@ -51,6 +52,7 @@ static const struct ipset_attrname adtattr2name[] = {
>  	[IPSET_ATTR_IP]		= { .name = "IP" },
>  	[IPSET_ATTR_IP_TO]	= { .name = "IP_TO" },
>  	[IPSET_ATTR_CIDR]	= { .name = "CIDR" },
> +	[IPSET_ATTR_MARK]	= { .name = "MARK" },
>  	[IPSET_ATTR_PORT]	= { .name = "PORT" },
>  	[IPSET_ATTR_PORT_TO]	= { .name = "PORT_TO" },
>  	[IPSET_ATTR_TIMEOUT]	= { .name = "TIMEOUT" },
> diff --git a/lib/ipset_hash_ipmark.c b/lib/ipset_hash_ipmark.c
> new file mode 100644
> index 0000000..5a12ce8
> --- /dev/null
> +++ b/lib/ipset_hash_ipmark.c
> @@ -0,0 +1,167 @@
> +/* Copyright 2007-2010 Jozsef Kadlecsik (kadlec@xxxxxxxxxxxxxxxxx)
> + *
> + * 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 <libipset/data.h>			/* IPSET_OPT_* */
> +#include <libipset/parse.h>			/* parser functions */
> +#include <libipset/print.h>			/* printing functions */
> +#include <libipset/types.h>			/* prototypes */
> +
> +/* Parse commandline arguments */
> +static const struct ipset_arg hash_ipmark_create_args0[] = {
> +	{ .name = { "family", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_FAMILY,
> +	  .parse = ipset_parse_family,		.print = ipset_print_family,
> +	},
> +	/* Alias: family inet */
> +	{ .name = { "-4", NULL },
> +	  .has_arg = IPSET_NO_ARG,		.opt = IPSET_OPT_FAMILY,
> +	  .parse = ipset_parse_family,
> +	},
> +	/* Alias: family inet6 */
> +	{ .name = { "-6", NULL },
> +	  .has_arg = IPSET_NO_ARG,		.opt = IPSET_OPT_FAMILY,
> +	  .parse = ipset_parse_family,
> +	},
> +	{ .name = { "hashsize", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_HASHSIZE,
> +	  .parse = ipset_parse_uint32,		.print = ipset_print_number,
> +	},
> +	{ .name = { "maxelem", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_MAXELEM,
> +	  .parse = ipset_parse_uint32,		.print = ipset_print_number,
> +	},
> +	{ .name = { "timeout", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_TIMEOUT,
> +	  .parse = ipset_parse_timeout,		.print = ipset_print_number,
> +	},
> +	{ .name = { "counters", NULL },
> +	  .has_arg = IPSET_NO_ARG,		.opt = IPSET_OPT_COUNTERS,
> +	  .parse = ipset_parse_flag,		.print = ipset_print_flag,
> +	},
> +	{ .name = { "comment", NULL },
> +	  .has_arg = IPSET_NO_ARG,		.opt = IPSET_OPT_CREATE_COMMENT,
> +	  .parse = ipset_parse_flag,		.print = ipset_print_flag,
> +	},
> +	/* Backward compatibility */
> +	{ .name = { "probes", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_PROBES,
> +	  .parse = ipset_parse_ignored,		.print = ipset_print_number,
> +	},
> +	{ .name = { "resize", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_RESIZE,
> +	  .parse = ipset_parse_ignored,		.print = ipset_print_number,
> +	},
> +	{ .name = { "from", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_IP,
> +	  .parse = ipset_parse_ignored,
> +	},
> +	{ .name = { "to", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_IP_TO,
> +	  .parse = ipset_parse_ignored,
> +	},
> +	{ .name = { "network", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_IP,
> +	  .parse = ipset_parse_ignored,
> +	},
> +	{ },
> +};
> +
> +static const struct ipset_arg hash_ipmark_add_args0[] = {
> +	{ .name = { "timeout", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_TIMEOUT,
> +	  .parse = ipset_parse_timeout,		.print = ipset_print_number,
> +	},
> +	{ .name = { "packets", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_PACKETS,
> +	  .parse = ipset_parse_uint64,		.print = ipset_print_number,
> +	},
> +	{ .name = { "bytes", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_BYTES,
> +	  .parse = ipset_parse_uint64,		.print = ipset_print_number,
> +	},
> +	{ .name = { "comment", NULL },
> +	  .has_arg = IPSET_MANDATORY_ARG,	.opt = IPSET_OPT_ADT_COMMENT,
> +	  .parse = ipset_parse_comment,		.print = ipset_print_comment,
> +	},
> +	{ },
> +};
> +
> +static const char hash_ipmark_usage0[] =
> +"create SETNAME hash:ip,mark\n"
> +"		[family inet|inet6]\n"
> +"               [hashsize VALUE] [maxelem VALUE]\n"
> +"               [timeout VALUE] [counters] [comment]\n"
> +"add    SETNAME IP,MARK [timeout VALUE]\n"
> +"               [packets VALUE] [bytes VALUE] [comment \"string\"]\n"
> +"del    SETNAME IP,MARK\n"
> +"test   SETNAME IP,MARK\n\n"
> +"where depending on the INET family\n"
> +"      IP is a valid IPv4 or IPv6 address (or hostname).\n"
> +"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
> +"      is supported for IPv4.\n"
> +"      Adding/deleting single mark element\n"
> +"      is supported both for IPv4 and IPv6.\n";
> +
> +static struct ipset_type ipset_hash_ipmark0 = {
> +	.name = "hash:ip,mark",
> +	.alias = { "ipmarkhash", NULL },
> +	.revision = 0,
> +	.family = NFPROTO_IPSET_IPV46,
> +	.dimension = IPSET_DIM_TWO,
> +	.elem = {
> +		[IPSET_DIM_ONE - 1] = {
> +			.parse = ipset_parse_ip4_single6,
> +			.print = ipset_print_ip,
> +			.opt = IPSET_OPT_IP
> +		},
> +		[IPSET_DIM_TWO - 1] = {
> +			.parse = ipset_parse_mark,
> +			.print = ipset_print_mark,
> +			.opt = IPSET_OPT_MARK
> +		},
> +	},
> +	.args = {
> +		[IPSET_CREATE] = hash_ipmark_create_args0,
> +		[IPSET_ADD] = hash_ipmark_add_args0,
> +	},
> +	.mandatory = {
> +		[IPSET_CREATE] = 0,
> +		[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
> +			| IPSET_FLAG(IPSET_OPT_MARK),
> +		[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
> +			| IPSET_FLAG(IPSET_OPT_MARK),
> +		[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
> +			| IPSET_FLAG(IPSET_OPT_MARK),
> +	},
> +	.full = {
> +		[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
> +			| IPSET_FLAG(IPSET_OPT_MAXELEM)
> +			| IPSET_FLAG(IPSET_OPT_TIMEOUT)
> +			| IPSET_FLAG(IPSET_OPT_COUNTERS)
> +			| IPSET_FLAG(IPSET_OPT_CREATE_COMMENT),
> +		[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
> +			| IPSET_FLAG(IPSET_OPT_IP_TO)
> +			| IPSET_FLAG(IPSET_OPT_MARK)
> +			| IPSET_FLAG(IPSET_OPT_TIMEOUT)
> +			| IPSET_FLAG(IPSET_OPT_PACKETS)
> +			| IPSET_FLAG(IPSET_OPT_BYTES)
> +			| IPSET_FLAG(IPSET_OPT_ADT_COMMENT),
> +		[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
> +			| IPSET_FLAG(IPSET_OPT_IP_TO)
> +			| IPSET_FLAG(IPSET_OPT_MARK),
> +		[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
> +			| IPSET_FLAG(IPSET_OPT_MARK),
> +	},
> +
> +	.usage = hash_ipmark_usage0,
> +	.description = "initial revision",
> +};
> +
> +void _init(void);
> +void _init(void)
> +{
> +	ipset_type_add(&ipset_hash_ipmark0);
> +}
> diff --git a/lib/libipset.map b/lib/libipset.map
> index 1080f0d..fc7ac95 100644
> --- a/lib/libipset.map
> +++ b/lib/libipset.map
> @@ -28,6 +28,7 @@ global:
>    name_to_icmpv6;
>    ipset_get_nlmsg_type;
>    ipset_parse_ether;
> +  ipset_parse_mark;
>    ipset_parse_port;
>    ipset_parse_tcpudp_port;
>    ipset_parse_tcp_port;
> @@ -69,6 +70,7 @@ global:
>    ipset_print_ipaddr;
>    ipset_print_number;
>    ipset_print_name;
> +  ipset_print_mark;
>    ipset_print_port;
>    ipset_print_iface;
>    ipset_print_proto;

You have to add a new library revision, which is just an extension of the 
previous one with the new functions.

Also, the API version must be adjusted in Make_global.am.

> diff --git a/lib/parse.c b/lib/parse.c
> index 8ea8542..97ff435 100644
> --- a/lib/parse.c
> +++ b/lib/parse.c
> @@ -328,6 +328,36 @@ ipset_parse_port(struct ipset_session *session,
>  }
>  
>  /**
> + * ipset_parse_mark - parse a mark
> + * @session: session structure
> + * @opt: option kind of the data
> + * @str: string to parse
> + *
> + * Parse string as a mark. The parsed mark number is
> + * stored in the data blob of the session.
> + *
> + * Returns 0 on success or a negative error code.
> + */
> +int
> +ipset_parse_mark(struct ipset_session *session,
> +		 enum ipset_opt opt, const char *str)
> +{
> +	uint32_t mark;
> +	int err;
> +
> +	assert(session);
> +	assert(str);
> +
> +	if ((err = string_to_u32(session, str, &mark)) == 0)
> +		err = ipset_session_data_set(session, opt, &mark);
> +
> +	if (!err)
> +		/* No error, so reset false error messages! */
> +		ipset_session_report_reset(session);
> +	return err;
> +}
> +
> +/**
>   * ipset_parse_tcpudp_port - parse TCP/UDP port name, number, or range of them
>   * @session: session structure
>   * @opt: option kind of the data
> diff --git a/lib/print.c b/lib/print.c
> index abdfd34..6634802 100644
> --- a/lib/print.c
> +++ b/lib/print.c
> @@ -491,6 +491,41 @@ ipset_print_port(char *buf, unsigned int len,
>  }
>  
>  /**
> + * ipset_print_mark - print mark to string
> + * @buf: printing buffer
> + * @len: length of available buffer space
> + * @data: data blob
> + * @opt: the option kind
> + * @env: environment flags
> + *
> + * Print mark to output buffer.
> + *
> + * Return lenght of printed string or error size.
> + */
> +int
> +ipset_print_mark(char *buf, unsigned int len,
> +		   const struct ipset_data *data,
> +		   enum ipset_opt opt ASSERT_UNUSED,
> +		   uint8_t env UNUSED)
> +{
> +	const uint32_t *mark;
> +	int size, offset = 0;
> +
> +	assert(buf);
> +	assert(len > 0);
> +	assert(data);
> +	assert(opt == IPSET_OPT_MARK);
> +
> +	mark = ipset_data_get(data, IPSET_OPT_MARK);
> +	assert(mark);
> +
> +	size = snprintf(buf, len, "%u", *mark);
> +	SNPRINTF_FAILURE(size, len, offset);
> +
> +	return offset;
> +}
> +
> +/**
>   * ipset_print_iface - print interface element string
>   * @buf: printing buffer
>   * @len: length of available buffer space
> diff --git a/lib/session.c b/lib/session.c
> index 6f89281..673b440 100644
> --- a/lib/session.c
> +++ b/lib/session.c
> @@ -349,6 +349,10 @@ static const struct ipset_attr_policy create_attrs[] = {
>  		.type = MNL_TYPE_U8,
>  		.opt = IPSET_OPT_CIDR,
>  	},
> +	[IPSET_ATTR_MARK] = {
> +		.type = MNL_TYPE_U32,
> +		.opt = IPSET_OPT_MARK,
> +	},

No needed again.

>  	[IPSET_ATTR_PORT] = {
>  		.type = MNL_TYPE_U16,
>  		.opt = IPSET_OPT_PORT,
> @@ -424,6 +428,10 @@ static const struct ipset_attr_policy adt_attrs[] = {
>  		.type = MNL_TYPE_U8,
>  		.opt = IPSET_OPT_CIDR,
>  	},
> +	[IPSET_ATTR_MARK] = {
> +		.type = MNL_TYPE_U32,
> +		.opt = IPSET_OPT_MARK,
> +	},
>  	[IPSET_ATTR_PORT] = {
>  		.type = MNL_TYPE_U16,
>  		.opt = IPSET_OPT_PORT,
> diff --git a/src/ipset.8 b/src/ipset.8
[...]

Best regards,
Jozsef
-
E-mail  : kadlec@xxxxxxxxxxxxxxxxx, kadlecsik.jozsef@xxxxxxxxxxxxx
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux