diff --git a/include/libipset/args.h b/include/libipset/args.h
index ef861c1..a549e42 100644
--- a/include/libipset/args.h
+++ b/include/libipset/args.h
@@ -58,6 +58,7 @@ enum ipset_keywords {
 	IPSET_ARG_SKBQUEUE,			/* skbqueue */
 	IPSET_ARG_BUCKETSIZE,			/* bucketsize */
 	IPSET_ARG_INITVAL,			/* initval */
+	IPSET_ARG_BITMASK,			/* bitmask */
 	IPSET_ARG_MAX,
 };
 
diff --git a/include/libipset/data.h b/include/libipset/data.h
index 0e33c67..afaf18c 100644
--- a/include/libipset/data.h
+++ b/include/libipset/data.h
@@ -37,6 +37,7 @@ enum ipset_opt {
 	IPSET_OPT_RESIZE,
 	IPSET_OPT_SIZE,
 	IPSET_OPT_FORCEADD,
+	IPSET_OPT_BITMASK,
 	/* Create-specific options, filled out by the kernel */
 	IPSET_OPT_ELEMENTS,
 	IPSET_OPT_REFERENCES,
@@ -70,7 +71,7 @@ enum ipset_opt {
 	IPSET_OPT_BUCKETSIZE,
 	IPSET_OPT_INITVAL,
 	/* Internal options */
-	IPSET_OPT_FLAGS = 48,	/* IPSET_FLAG_EXIST| */
+	IPSET_OPT_FLAGS = 49,	/* IPSET_FLAG_EXIST| */
 	IPSET_OPT_CADT_FLAGS,	/* IPSET_FLAG_BEFORE| */
 	IPSET_OPT_ELEM,
 	IPSET_OPT_TYPE,
@@ -105,7 +106,8 @@ enum ipset_opt {
 	| IPSET_FLAG(IPSET_OPT_COUNTERS)\
 	| IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)\
 	| IPSET_FLAG(IPSET_OPT_FORCEADD)\
-	| IPSET_FLAG(IPSET_OPT_SKBINFO))
+	| IPSET_FLAG(IPSET_OPT_SKBINFO)\
+	| IPSET_FLAG(IPSET_OPT_BITMASK))
 
 #define IPSET_ADT_FLAGS			\
 	(IPSET_FLAG(IPSET_OPT_IP)	\
diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h
index 1852636..d8172bd 100644
--- a/include/libipset/linux_ip_set.h
+++ b/include/libipset/linux_ip_set.h
@@ -89,6 +89,7 @@ enum {
 	IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,	/* 9 */
 	IPSET_ATTR_MARK,	/* 10 */
 	IPSET_ATTR_MARKMASK,	/* 11 */
+	IPSET_ATTR_BITMASK,/* 12 */
 	/* 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 3fa9129..0123d4b 100644
--- a/include/libipset/parse.h
+++ b/include/libipset/parse.h
@@ -92,6 +92,8 @@ extern int ipset_parse_uint8(struct ipset_session *session,
 			     enum ipset_opt opt, const char *str);
 extern int ipset_parse_netmask(struct ipset_session *session,
 			       enum ipset_opt opt, const char *str);
+extern int ipset_parse_bitmask(struct ipset_session *session,
+			       enum ipset_opt opt, const char *str);
 extern int ipset_parse_flag(struct ipset_session *session,
 			    enum ipset_opt opt, const char *str);
 extern int ipset_parse_typename(struct ipset_session *session,
diff --git a/lib/args.c b/lib/args.c
index bab3b13..2e139a9 100644
--- a/lib/args.c
+++ b/lib/args.c
@@ -300,6 +300,14 @@ static const struct ipset_arg ipset_args[] = {
 		.print = ipset_print_hexnumber,
 		.help = "[initval VALUE]",
 	},
+	[IPSET_ARG_BITMASK] = {
+		.name = { "bitmask", NULL },
+		.has_arg = IPSET_MANDATORY_ARG,
+		.opt = IPSET_OPT_BITMASK,
+		.parse = ipset_parse_bitmask,
+		.print = ipset_print_ip,
+		.help = "[bitmask CIDR/bitmask]",
+	},
 };
 
 const struct ipset_arg *
diff --git a/lib/data.c b/lib/data.c
index 7720178..72f1330 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -53,6 +53,7 @@ struct ipset_data {
 			uint8_t bucketsize;
 			uint8_t resize;
 			uint8_t netmask;
+			union nf_inet_addr bitmask;
 			uint32_t hashsize;
 			uint32_t maxelem;
 			uint32_t markmask;
@@ -301,6 +302,12 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
 	case IPSET_OPT_NETMASK:
 		data->create.netmask = *(const uint8_t *) value;
 		break;
+	case IPSET_OPT_BITMASK:
+		if (!(data->family == NFPROTO_IPV4 ||
+		      data->family == NFPROTO_IPV6))
+			return -1;
+		copy_addr(data->family, &data->create.bitmask, value);
+		break;
 	case IPSET_OPT_BUCKETSIZE:
 		data->create.bucketsize = *(const uint8_t *) value;
 		break;
@@ -508,6 +515,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
 		return &data->create.markmask;
 	case IPSET_OPT_NETMASK:
 		return &data->create.netmask;
+	case IPSET_OPT_BITMASK:
+		return &data->create.bitmask;
 	case IPSET_OPT_BUCKETSIZE:
 		return &data->create.bucketsize;
 	case IPSET_OPT_RESIZE:
@@ -594,6 +603,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
 	case IPSET_OPT_IP_TO:
 	case IPSET_OPT_IP2:
 	case IPSET_OPT_IP2_TO:
+	case IPSET_OPT_BITMASK:
 		return family == NFPROTO_IPV4 ? sizeof(uint32_t)
 					 : sizeof(struct in6_addr);
 	case IPSET_OPT_MARK:
diff --git a/lib/debug.c b/lib/debug.c
index bf57a41..dbc5cfb 100644
--- a/lib/debug.c
+++ b/lib/debug.c
@@ -40,6 +40,7 @@ static const struct ipset_attrname createattr2name[] = {
 	[IPSET_ATTR_MAXELEM]	= { .name = "MAXELEM" },
 	[IPSET_ATTR_MARKMASK]	= { .name = "MARKMASK" },
 	[IPSET_ATTR_NETMASK]	= { .name = "NETMASK" },
+	[IPSET_ATTR_BITMASK]    = { .name = "BITMASK" },
 	[IPSET_ATTR_BUCKETSIZE]	= { .name = "BUCKETSIZE" },
 	[IPSET_ATTR_RESIZE]	= { .name = "RESIZE" },
 	[IPSET_ATTR_SIZE]	= { .name = "SIZE" },
diff --git a/lib/parse.c b/lib/parse.c
index 974eaf8..c54bedf 100644
--- a/lib/parse.c
+++ b/lib/parse.c
@@ -1721,6 +1721,43 @@ ipset_parse_netmask(struct ipset_session *session,
 	return ipset_data_set(data, opt, &cidr);
 }
 
+/**
+ * ipset_parse_bitmask - parse string as a bitmask
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as a bitmask value, depending on family type.
+ * If family is not set yet, INET is assumed.
+ * The value is stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_bitmask(struct ipset_session *session,
+		    enum ipset_opt opt, const char *str)
+{
+	uint8_t family;
+	struct ipset_data *data;
+
+	assert(session);
+	assert(opt == IPSET_OPT_BITMASK);
+	assert(str);
+
+	data = ipset_session_data(session);
+	family = ipset_data_family(data);
+	if (family == NFPROTO_UNSPEC) {
+		family = NFPROTO_IPV4;
+		ipset_data_set(data, IPSET_OPT_FAMILY, &family);
+	}
+
+	if (parse_ipaddr(session, opt, str, family))
+		return syntax_err("bitmask is not valid for family = %s",
+				  family == NFPROTO_IPV4 ? "inet" : "inet6");
+
+	return 0;
+}
+
 /**
  * ipset_parse_flag - "parse" option flags
  * @session: session structure
diff --git a/lib/print.c b/lib/print.c
index a7ffd81..50f0ad6 100644
--- a/lib/print.c
+++ b/lib/print.c
@@ -265,7 +265,7 @@ ipset_print_ip(char *buf, unsigned int len,
 	assert(buf);
 	assert(len > 0);
 	assert(data);
-	assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
+	assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2 || opt == IPSET_OPT_BITMASK);
 
 	D("len: %u", len);
 	family = ipset_data_family(data);
@@ -976,6 +976,7 @@ ipset_print_data(char *buf, unsigned int len,
 		size = ipset_print_elem(buf, len, data, opt, env);
 		break;
 	case IPSET_OPT_IP:
+	case IPSET_OPT_BITMASK:
 		size = ipset_print_ip(buf, len, data, opt, env);
 		break;
 	case IPSET_OPT_PORT:
diff --git a/lib/session.c b/lib/session.c
index 1ca26ff..cdc59e0 100644
--- a/lib/session.c
+++ b/lib/session.c
@@ -462,6 +462,10 @@ static const struct ipset_attr_policy create_attrs[] = {
 		.type = MNL_TYPE_U32,
 		.opt = IPSET_OPT_MEMSIZE,
 	},
+	[IPSET_ATTR_BITMASK] = {
+		.type = MNL_TYPE_NESTED,
+		.opt = IPSET_OPT_BITMASK,
+	},
 };
 
 static const struct ipset_attr_policy adt_attrs[] = {
@@ -1721,6 +1725,10 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
 	if (attr->type == MNL_TYPE_NESTED) {
 		/* IP addresses */
 		struct nlattr *nested;
+
+		if (type == IPSET_ATTR_BITMASK)
+			family = ipset_data_family(session->data);
+
 		int atype = family == NFPROTO_IPV4 ? IPSET_ATTR_IPADDR_IPV4
 					      : IPSET_ATTR_IPADDR_IPV6;
 
