diff --git a/Documentation/netlink/specs/conntrack.yaml b/Documentation/netlink/specs/conntrack.yaml
index 1d163130241a..56c13705243b 100644
--- a/Documentation/netlink/specs/conntrack.yaml
+++ b/Documentation/netlink/specs/conntrack.yaml
@@ -393,6 +393,12 @@ attribute-sets:
name: reply-flags
type: u32
doc: bitmask of tuple fields to filter on, reply direction
+ -
+ name: zone
+ type: flag
+ doc: >-
+ Filter on conntrack zone id; requires the top-level zone
+ (``CTA_ZONE``) attribute.
-
name: conntrack-attrs
attributes:diff --git a/include/uapi/linux/netfilter/nfnetlink_conntrack.h b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
index 43233af75b9d..985f9c08d3e9 100644
--- a/include/uapi/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
@@ -285,6 +285,7 @@ enum ctattr_filter {
CTA_FILTER_UNSPEC,
CTA_FILTER_ORIG_FLAGS,
CTA_FILTER_REPLY_FLAGS,
+ CTA_FILTER_ZONE,
__CTA_FILTER_MAX
};
#define CTA_FILTER_MAX (__CTA_FILTER_MAX - 1)diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index e8477f792c95..4b6abe36028e 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -911,6 +911,7 @@ struct ctnetlink_filter {
static const struct nla_policy cta_filter_nla_policy[CTA_FILTER_MAX + 1] = {
[CTA_FILTER_ORIG_FLAGS] = NLA_POLICY_MASK(NLA_U32, CTA_FILTER_F_ALL),
[CTA_FILTER_REPLY_FLAGS] = NLA_POLICY_MASK(NLA_U32, CTA_FILTER_F_ALL),
+ [CTA_FILTER_ZONE] = { .type = NLA_FLAG },
};
static int ctnetlink_parse_filter(const struct nlattr *attr,@@ -930,6 +931,9 @@ static int ctnetlink_parse_filter(const struct nlattr *attr,
if (tb[CTA_FILTER_REPLY_FLAGS])
filter->reply_flags = nla_get_u32(tb[CTA_FILTER_REPLY_FLAGS]);
+ if (tb[CTA_FILTER_ZONE])
+ filter->zone_filter = true;
+
return 0;
}
@@ -1006,6 +1010,7 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
if (err)
goto err_filter;
+ /* CTA_ZONE is allowed without CTA_FILTER_ZONE. */
if (cda[CTA_ZONE]) {
err = ctnetlink_parse_zone(cda[CTA_ZONE], &filter->zone);
if (err < 0)@@ -1020,6 +1025,12 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
if (err < 0)
goto err_filter;
+ /* CTA_FILTER_ZONE cannot be set without CTA_ZONE. */
+ if (filter->zone_filter && !cda[CTA_ZONE]) {
+ err = -EINVAL;
+ goto err_filter;
+ }
+
if (filter->orig_flags) {
if (!cda[CTA_TUPLE_ORIG]) {
err = -EINVAL;diff --git a/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c b/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c
index 31b8250ddc53..0c777323f4ba 100644
--- a/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c
+++ b/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c
@@ -215,7 +215,22 @@ static int count_entries(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
-static int conntrack_count_zone(struct mnl_socket *sock, uint16_t zone)
+static void put_zone_attr(struct nlmsghdr *nlh, uint16_t zone,
+ bool use_cta_filter)
+{
+ struct nlattr *nest;
+
+ mnl_attr_put_u16(nlh, CTA_ZONE, htons(zone));
+
+ if (use_cta_filter) {
+ nest = mnl_attr_nest_start(nlh, CTA_FILTER);
+ mnl_attr_put(nlh, CTA_FILTER_ZONE, 0, NULL);
+ mnl_attr_nest_end(nlh, nest);
+ }
+}
+
+static int conntrack_count_zone(struct mnl_socket *sock, uint16_t zone,
+ bool use_cta_filter)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;@@ -235,7 +250,7 @@ static int conntrack_count_zone(struct mnl_socket *sock, uint16_t zone)
nfh->version = NFNETLINK_V0;
nfh->res_id = 0;
- mnl_attr_put_u16(nlh, CTA_ZONE, htons(zone));
+ put_zone_attr(nlh, zone, use_cta_filter);
ret = mnl_socket_sendto(sock, nlh, nlh->nlmsg_len);
if (ret < 0) {@@ -261,7 +276,8 @@ static int conntrack_count_zone(struct mnl_socket *sock, uint16_t zone)
return reply_counter;
}
-static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone)
+static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone,
+ bool use_cta_filter)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;@@ -281,7 +297,7 @@ static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone)
nfh->version = NFNETLINK_V0;
nfh->res_id = 0;
- mnl_attr_put_u16(nlh, CTA_ZONE, htons(zone));
+ put_zone_attr(nlh, zone, use_cta_filter);
ret = mnl_socket_sendto(sock, nlh, nlh->nlmsg_len);
if (ret < 0) {@@ -304,43 +320,40 @@ static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone)
return 0;
}
-FIXTURE(conntrack_dump_flush)
-{
- struct mnl_socket *sock;
-};
-
-FIXTURE_SETUP(conntrack_dump_flush)
+static int conntrack_zone_setup(struct __test_metadata *_metadata,
+ struct mnl_socket **sock)
{
struct in6_addr src, dst;
int ret;
- self->sock = mnl_socket_open(NETLINK_NETFILTER);
- if (!self->sock) {
+ *sock = mnl_socket_open(NETLINK_NETFILTER);
+ if (!*sock) {
perror("mnl_socket_open");
- SKIP(return, "cannot open netlink_netfilter socket");
+ SKIP(return -1, "cannot open netlink_netfilter socket");
}
- ret = mnl_socket_bind(self->sock, 0, MNL_SOCKET_AUTOPID);
- EXPECT_EQ(ret, 0);
+ ret = mnl_socket_bind(*sock, 0, MNL_SOCKET_AUTOPID);
+ ASSERT_EQ(ret, 0);
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
+ ret = conntrack_count_zone(*sock, TEST_ZONE_ID, false);
if (ret < 0 && errno == EPERM)
- SKIP(return, "Needs to be run as root");
+ SKIP(return -1, "Needs to be run as root");
else if (ret < 0 && errno == EOPNOTSUPP)
- SKIP(return, "Kernel does not seem to support conntrack zones");
+ SKIP(return -1,
+ "Kernel does not seem to support conntrack zones");
- ret = conntrack_data_generate_v4(self->sock, 0xf0f0f0f0, 0xf1f1f1f1,
+ ret = conntrack_data_generate_v4(*sock, 0xf0f0f0f0, 0xf1f1f1f1,
TEST_ZONE_ID);
- EXPECT_EQ(ret, 0);
- ret = conntrack_data_generate_v4(self->sock, 0xf2f2f2f2, 0xf3f3f3f3,
+ ASSERT_EQ(ret, 0);
+ ret = conntrack_data_generate_v4(*sock, 0xf2f2f2f2, 0xf3f3f3f3,
TEST_ZONE_ID + 1);
- EXPECT_EQ(ret, 0);
- ret = conntrack_data_generate_v4(self->sock, 0xf4f4f4f4, 0xf5f5f5f5,
+ ASSERT_EQ(ret, 0);
+ ret = conntrack_data_generate_v4(*sock, 0xf4f4f4f4, 0xf5f5f5f5,
TEST_ZONE_ID + 2);
- EXPECT_EQ(ret, 0);
- ret = conntrack_data_generate_v4(self->sock, 0xf6f6f6f6, 0xf7f7f7f7,
+ ASSERT_EQ(ret, 0);
+ ret = conntrack_data_generate_v4(*sock, 0xf6f6f6f6, 0xf7f7f7f7,
NF_CT_DEFAULT_ZONE_ID);
- EXPECT_EQ(ret, 0);
+ ASSERT_EQ(ret, 0);
src = (struct in6_addr) {{
.__u6_addr32 = {@@ -358,9 +371,9 @@ FIXTURE_SETUP(conntrack_dump_flush)
0x02000000
}
}};
- ret = conntrack_data_generate_v6(self->sock, src, dst,
+ ret = conntrack_data_generate_v6(*sock, src, dst,
TEST_ZONE_ID);
- EXPECT_EQ(ret, 0);
+ ASSERT_EQ(ret, 0);
src = (struct in6_addr) {{
.__u6_addr32 = {
0xb80d0120,@@ -377,9 +390,9 @@ FIXTURE_SETUP(conntrack_dump_flush)
0x04000000
}
}};
- ret = conntrack_data_generate_v6(self->sock, src, dst,
+ ret = conntrack_data_generate_v6(*sock, src, dst,
TEST_ZONE_ID + 1);
- EXPECT_EQ(ret, 0);
+ ASSERT_EQ(ret, 0);
src = (struct in6_addr) {{
.__u6_addr32 = {
0xb80d0120,@@ -396,9 +409,9 @@ FIXTURE_SETUP(conntrack_dump_flush)
0x06000000
}
}};
- ret = conntrack_data_generate_v6(self->sock, src, dst,
+ ret = conntrack_data_generate_v6(*sock, src, dst,
TEST_ZONE_ID + 2);
- EXPECT_EQ(ret, 0);
+ ASSERT_EQ(ret, 0);
src = (struct in6_addr) {{
.__u6_addr32 = {@@ -416,14 +429,51 @@ FIXTURE_SETUP(conntrack_dump_flush)
0x08000000
}
}};
- ret = conntrack_data_generate_v6(self->sock, src, dst,
+ ret = conntrack_data_generate_v6(*sock, src, dst,
NF_CT_DEFAULT_ZONE_ID);
- EXPECT_EQ(ret, 0);
+ ASSERT_EQ(ret, 0);
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
+ return 0;
+}
+
+FIXTURE(conntrack_dump_flush)
+{
+ struct mnl_socket *sock;
+};
+
+FIXTURE_VARIANT(conntrack_dump_flush)
+{
+ bool use_cta_filter;
+};
+
+FIXTURE_VARIANT_ADD(conntrack_dump_flush, cta_zone)
+{
+ .use_cta_filter = false,
+};
+
+FIXTURE_VARIANT_ADD(conntrack_dump_flush, cta_filter)
+{
+ .use_cta_filter = true,
+};
+
+FIXTURE_SETUP(conntrack_dump_flush)
+{
+ int ret;
+
+ if (conntrack_zone_setup(_metadata, &self->sock))
+ return;
+
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID, false);
EXPECT_GE(ret, 2);
if (ret > 2)
SKIP(return, "kernel does not support filtering by zone");
+
+ if (variant->use_cta_filter) {
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID, true);
+ if (ret < 0 && errno == EINVAL)
+ SKIP(return, "kernel does not support CTA_FILTER_ZONE");
+ ASSERT_GE(ret, 0);
+ }
}
FIXTURE_TEARDOWN(conntrack_dump_flush)@@ -434,39 +484,42 @@ TEST_F(conntrack_dump_flush, test_dump_by_zone)
{
int ret;
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID,
+ variant->use_cta_filter);
EXPECT_EQ(ret, 2);
}
TEST_F(conntrack_dump_flush, test_flush_by_zone)
{
+ bool filter = variant->use_cta_filter;
int ret;
- ret = conntrack_flush_zone(self->sock, TEST_ZONE_ID);
+ ret = conntrack_flush_zone(self->sock, TEST_ZONE_ID, filter);
EXPECT_EQ(ret, 0);
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID, filter);
EXPECT_EQ(ret, 0);
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 1);
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 1, filter);
EXPECT_EQ(ret, 2);
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 2);
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 2, filter);
EXPECT_EQ(ret, 2);
- ret = conntrack_count_zone(self->sock, NF_CT_DEFAULT_ZONE_ID);
+ ret = conntrack_count_zone(self->sock, NF_CT_DEFAULT_ZONE_ID, filter);
EXPECT_EQ(ret, 2);
}
TEST_F(conntrack_dump_flush, test_flush_by_zone_default)
{
+ bool filter = variant->use_cta_filter;
int ret;
- ret = conntrack_flush_zone(self->sock, NF_CT_DEFAULT_ZONE_ID);
+ ret = conntrack_flush_zone(self->sock, NF_CT_DEFAULT_ZONE_ID, filter);
EXPECT_EQ(ret, 0);
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID);
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID, filter);
EXPECT_EQ(ret, 2);
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 1);
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 1, filter);
EXPECT_EQ(ret, 2);
- ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 2);
+ ret = conntrack_count_zone(self->sock, TEST_ZONE_ID + 2, filter);
EXPECT_EQ(ret, 2);
- ret = conntrack_count_zone(self->sock, NF_CT_DEFAULT_ZONE_ID);
+ ret = conntrack_count_zone(self->sock, NF_CT_DEFAULT_ZONE_ID, filter);
EXPECT_EQ(ret, 0);
}
--
2.47.3