This patch adds support for selective flushing of conntrack mappings. By adding CTA_MARK and CTA_MARK_MASK to a delete-message, the mark (and mask) is checked before a connection is deleted while flushing. Configuring the flush is moved out of ctnetlink_del_conntrack(), and instead of calling nf_conntrack_flush_report(), we always call nf_ct_iterate_cleanup(). This enables us to only make one call from the new ctnetlink_flush_conntrack() and makes it easy to add more filter parameters. Filtering is done in the ctnetlink_apply_filter()-function, which is also called from ctnetlink_dump_table(). ctnetlink_dump_filter has been renamed ctnetlink_filter, to indicated that it is no longer only used when dumping conntrack entries. Signed-off-by: Kristian Evensen <kristian.evensen@xxxxxxxxx> --- net/netfilter/nf_conntrack_netlink.c | 57 ++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 1bd9ed9..85046d3 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -749,13 +749,29 @@ static int ctnetlink_done(struct netlink_callback *cb) return 0; } -struct ctnetlink_dump_filter { +struct ctnetlink_filter { struct { u_int32_t val; u_int32_t mask; } mark; }; +static int ctnetlink_apply_filter(struct nf_conn *i, void *data) +{ + struct ctnetlink_filter *filter = data; + + if (!filter) + return 1; + +#ifdef CONFIG_NF_CONNTRACK_MARK + if ((filter->mark.val && filter->mark.mask) && + (i->mark & filter->mark.mask) != filter->mark.val) + return 0; +#endif + + return 1; +} + static int ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { @@ -769,7 +785,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) spinlock_t *lockp; #ifdef CONFIG_NF_CONNTRACK_MARK - const struct ctnetlink_dump_filter *filter = cb->data; + const struct ctnetlink_filter *filter = cb->data; #endif last = (struct nf_conn *)cb->args[1]; @@ -799,10 +815,9 @@ restart: cb->args[1] = 0; } #ifdef CONFIG_NF_CONNTRACK_MARK - if (filter && !((ct->mark & filter->mark.mask) == - filter->mark.val)) { + if (filter && + !ctnetlink_apply_filter(ct, (void *)filter)) continue; - } #endif rcu_read_lock(); res = @@ -1001,6 +1016,25 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { .len = NF_CT_LABELS_MAX_SIZE }, }; +static void ctnetlink_flush_conntrack(struct net *net, + const struct nlattr * const cda[], + u32 portid, int report) +{ + struct ctnetlink_filter filter; + + memset(&filter, 0, sizeof(filter)); + +#ifdef CONFIG_NF_CONNTRACK_MARK + if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) { + filter.mark.val = ntohl(nla_get_be32(cda[CTA_MARK])); + filter.mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK])); + } +#endif + + nf_ct_iterate_cleanup(net, ctnetlink_apply_filter, &filter, + portid, report); +} + static int ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, @@ -1024,10 +1058,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, else if (cda[CTA_TUPLE_REPLY]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); else { - /* Flush the whole table */ - nf_conntrack_flush_report(net, - NETLINK_CB(skb).portid, - nlmsg_report(nlh)); + /* Flush the table */ + ctnetlink_flush_conntrack(net, cda, NETLINK_CB(skb).portid, + nlmsg_report(nlh)); return 0; } @@ -1075,13 +1108,13 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, struct netlink_dump_control c = { .dump = ctnetlink_dump_table, .done = ctnetlink_done, + .data = NULL, }; #ifdef CONFIG_NF_CONNTRACK_MARK if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) { - struct ctnetlink_dump_filter *filter; + struct ctnetlink_filter *filter; - filter = kzalloc(sizeof(struct ctnetlink_dump_filter), - GFP_ATOMIC); + filter = kzalloc(sizeof(*filter), GFP_ATOMIC); if (filter == NULL) return -ENOMEM; -- 2.1.0 -- 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