From patchwork Wed Nov 22 01:00:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 840237 X-Patchwork-Delegate: jpettit@nicira.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Uq4ZMSp0"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3yhPMy0wCJz9ryv for ; Wed, 22 Nov 2017 12:03:26 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C56CFBCE; Wed, 22 Nov 2017 01:01:54 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 70A18BBD for ; Wed, 22 Nov 2017 01:01:52 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f68.google.com (mail-pg0-f68.google.com [74.125.83.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id A5F26204 for ; Wed, 22 Nov 2017 01:01:51 +0000 (UTC) Received: by mail-pg0-f68.google.com with SMTP id c123so11598626pga.11 for ; Tue, 21 Nov 2017 17:01:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ceYKphOgZLu7ID5lUAoxpoYLBpOfJ8Vt83xdWn/47hQ=; b=Uq4ZMSp0G7Di+xiTJdanPFHV3sjTaRkpsgE8Dc1TKAZgtLTM+JWSI/lTN7r0NwCbtz TjZEjCg4a5NAF3YFQSijpfZlHystBiDU/LSMgU87oWkkXqOp1qRGN/wQqvL+e/hJ3B8Y 7QOgbZc0QFXTzIZ9a0rwxv4TGw8ywfpaupXzU2YxfFwlt8bbgdyAtivh8s7uilcm+DFu Ca/yl82u5K5FKjVA7oLSjT8MkW+dxIZS632uP0WTxgWQTNlNyePUufBNTLsMrtXMoDhq zX10HNY7ZHGovzXHbi8be58xvqu0gDgnNz9rRjwNhleMifB6hwzcwxn9sKEAGMRQP3hS 2q4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ceYKphOgZLu7ID5lUAoxpoYLBpOfJ8Vt83xdWn/47hQ=; b=iUF5mqMuylkqnV0YEWgR9dAmpXR3OVenOYib7uScEj8BtIARAHCORvFuLCsSMgxSpY W3EC0eRXndnjBw35dK6aE60wd47fh8rmzLfyHxxJx/Axm1ojtH1NHC8tRkMA6vFZtvKy Jyq4Q62Tb3yZiGHLbuxmcSvBWkmFj5mNq8ph2aDM9aBPAw+loe9mC2HYZBQ/g+CDQTY+ /0LYz/0ErnrP0MkWZkbN/FiSF65B0yKT4vIfL1+98lXTSvxcb3SCdjZtSCdDqzyiP1/J Y1DgRvxSL8hlzk7t/GYl+BAF0W86wCzPY7JcNARAw3pGhBq+q35GegZRGURHV3Jumo/M KaZQ== X-Gm-Message-State: AJaThX61VhbhVAdx1mawgwTkWxpDM53AHaAUf45hEBg36URgUvioMRqM H5fkhREbZbwJWdH4aKYsN+7n9TvR X-Google-Smtp-Source: AGs4zMbqgF9twQdky9Pla7yPeZWHCLofAQIdT2lZI2zxiGrDpkf9y/zzSrDxwrNDAMphIVh2UuqlxA== X-Received: by 10.99.144.68 with SMTP id a65mr19540862pge.429.1511312510777; Tue, 21 Nov 2017 17:01:50 -0800 (PST) Received: from sc9-mailhost2.vmware.com ([208.91.2.2]) by smtp.gmail.com with ESMTPSA id w3sm22105172pge.59.2017.11.21.17.01.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 21 Nov 2017 17:01:50 -0800 (PST) From: Yi-Hung Wei To: dev@openvswitch.org Date: Tue, 21 Nov 2017 17:00:53 -0800 Message-Id: <1511312455-7733-2-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511312455-7733-1-git-send-email-yihung.wei@gmail.com> References: <1511312455-7733-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 1/3] ct-dpif, dpif-netlink: Support conntrack flush by ct 5-tuple X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch adds support of flushing a conntrack entry specified by the conntrack 5-tuple, and provides the implementation in dpif-netlink. The implementation of dpif-netlink in the linux datapath utilizes the NFNL_SUBSYS_CTNETLINK netlink subsystem to delete a conntrack entry in nf_conntrack. VMWare-BZ: #1983178 Signed-off-by: Yi-Hung Wei --- lib/ct-dpif.c | 23 +++++++++--- lib/ct-dpif.h | 3 +- lib/dpctl.c | 2 +- lib/dpif-netdev.c | 6 ++- lib/dpif-netlink.c | 7 +++- lib/dpif-provider.h | 13 +++++-- lib/netlink-conntrack.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/netlink-conntrack.h | 1 + ofproto/ofproto-dpif.c | 2 +- tests/ovs-ofctl.at | 2 +- 10 files changed, 140 insertions(+), 16 deletions(-) diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index c79e69e23970..5cd6b5cfd870 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -111,19 +111,30 @@ ct_dpif_dump_done(struct ct_dpif_dump_state *dump) } /* Flush the entries in the connection tracker used by 'dpif'. - * - * If 'zone' is not NULL, flush only the entries in '*zone'. */ + * If both 'zone' and 'tuple' are NULL, flush all the conntrack entries. + * If 'zone' is not NULL, and 'tuple' is NULL, flush all the conntrack + * entries in '*zone'. + * If 'tuple' is not NULL, flush the conntrack entry specified by 'tuple' + * in '*zone'. In this case, we use default zone (zone 0) if 'zone' is + * NULL. */ int -ct_dpif_flush(struct dpif *dpif, const uint16_t *zone) +ct_dpif_flush(struct dpif *dpif, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) { - if (zone) { - VLOG_DBG("%s: ct_flush: %"PRIu16, dpif_name(dpif), *zone); + if (tuple) { + struct ds ds = DS_EMPTY_INITIALIZER; + ct_dpif_format_tuple(&ds, tuple); + VLOG_DBG("%s: ct_flush: %s in zone %d", dpif_name(dpif), ds_cstr(&ds), + zone ? *zone : 0); + ds_destroy(&ds); + } else if (zone) { + VLOG_DBG("%s: ct_flush: zone %"PRIu16, dpif_name(dpif), *zone); } else { VLOG_DBG("%s: ct_flush: ", dpif_name(dpif)); } return (dpif->dpif_class->ct_flush - ? dpif->dpif_class->ct_flush(dpif, zone) + ? dpif->dpif_class->ct_flush(dpif, zone, tuple) : EOPNOTSUPP); } diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index d5f966175bc0..ef019050c78e 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -195,7 +195,8 @@ int ct_dpif_dump_start(struct dpif *, struct ct_dpif_dump_state **, const uint16_t *zone, int *); int ct_dpif_dump_next(struct ct_dpif_dump_state *, struct ct_dpif_entry *); int ct_dpif_dump_done(struct ct_dpif_dump_state *); -int ct_dpif_flush(struct dpif *, const uint16_t *zone); +int ct_dpif_flush(struct dpif *, const uint16_t *zone, + const struct ct_dpif_tuple *); void ct_dpif_entry_uninit(struct ct_dpif_entry *); void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *, bool verbose, bool print_stats); diff --git a/lib/dpctl.c b/lib/dpctl.c index 6520788aa428..7fc0e3afab37 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -1353,7 +1353,7 @@ dpctl_flush_conntrack(int argc, const char *argv[], return error; } - error = ct_dpif_flush(dpif, pzone); + error = ct_dpif_flush(dpif, pzone, NULL); dpif_close(dpif); return error; diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 0a62630c2712..b1ef9a6a5992 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -5734,10 +5734,14 @@ dpif_netdev_ct_dump_done(struct dpif *dpif OVS_UNUSED, } static int -dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone) +dpif_netdev_ct_flush(struct dpif *dpif, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) { struct dp_netdev *dp = get_dp_netdev(dpif); + if (tuple) { + return EOPNOTSUPP; + } return conntrack_flush(&dp->conntrack, zone); } diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index c265909f8587..3f76128999d1 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -2892,9 +2892,12 @@ dpif_netlink_ct_dump_done(struct dpif *dpif OVS_UNUSED, } static int -dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone) +dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone, + const struct ct_dpif_tuple *tuple) { - if (zone) { + if (tuple) { + return nl_ct_flush_tuple(tuple, zone ? *zone : 0); + } else if (zone) { return nl_ct_flush_zone(*zone); } else { return nl_ct_flush(); diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 1d82a0939aa1..33d7f2a64367 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -75,6 +75,7 @@ dpif_flow_dump_thread_init(struct dpif_flow_dump_thread *thread, struct ct_dpif_dump_state; struct ct_dpif_entry; +struct ct_dpif_tuple; /* Datapath interface class structure, to be defined by each implementation of * a datapath interface. @@ -424,9 +425,15 @@ struct dpif_class { struct ct_dpif_entry *entry); int (*ct_dump_done)(struct dpif *, struct ct_dpif_dump_state *state); - /* Flushes the connection tracking tables. If 'zone' is not NULL, - * only deletes connections in '*zone'. */ - int (*ct_flush)(struct dpif *, const uint16_t *zone); + /* Flushes the connection tracking tables. + * If both 'zone' and 'tuple' are NULL, flush all the conntrack entries. + * If 'zone' is not NULL, and 'tuple' is NULL, flush all the conntrack + * entries in '*zone'. + * If 'tuple' is not NULL, flush the conntrack entry specified by 'tuple' + * in '*zone'. In this case, we use default zone (zone 0) if 'zone' is + * NULL. */ + int (*ct_flush)(struct dpif *, const uint16_t *zone, + const struct ct_dpif_tuple *tuple); /* Meters */ diff --git a/lib/netlink-conntrack.c b/lib/netlink-conntrack.c index 1e1bb2f79d1d..1f0b9121036d 100644 --- a/lib/netlink-conntrack.c +++ b/lib/netlink-conntrack.c @@ -18,6 +18,7 @@ #include "netlink-conntrack.h" +#include #include #include #include @@ -111,6 +112,8 @@ static bool nl_ct_parse_header_policy(struct ofpbuf *buf, static bool nl_ct_attrs_to_ct_dpif_entry(struct ct_dpif_entry *entry, struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)], uint8_t nfgen_family); +static bool nl_ct_put_ct_tuple(struct ofpbuf *buf, + const struct ct_dpif_tuple *tuple, enum ctattr_type type); struct nl_ct_dump_state { struct nl_dump dump; @@ -239,6 +242,27 @@ nl_ct_flush(void) return err; } +int +nl_ct_flush_tuple(const struct ct_dpif_tuple *tuple, uint16_t zone) +{ + int err; + struct ofpbuf buf; + + ofpbuf_init(&buf, NL_DUMP_BUFSIZE); + nl_msg_put_nfgenmsg(&buf, 0, tuple->l3_type, NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST); + + nl_msg_put_be16(&buf, CTA_ZONE, htons(zone)); + if (!nl_ct_put_ct_tuple(&buf, tuple, CTA_TUPLE_ORIG)) { + err = EOPNOTSUPP; + goto out; + } + err = nl_transact(NETLINK_NETFILTER, &buf, NULL); +out: + ofpbuf_uninit(&buf); + return err; +} + #ifdef _WIN32 int nl_ct_flush_zone(uint16_t flush_zone) @@ -517,6 +541,79 @@ nl_ct_parse_tuple(struct nlattr *nla, struct ct_dpif_tuple *tuple, return parsed; } +static bool +nl_ct_put_tuple_ip(struct ofpbuf *buf, const struct ct_dpif_tuple *tuple) +{ + size_t offset = nl_msg_start_nested(buf, CTA_TUPLE_IP); + + if (tuple->l3_type == AF_INET) { + nl_msg_put_be32(buf, CTA_IP_V4_SRC, tuple->src.ip); + nl_msg_put_be32(buf, CTA_IP_V4_DST, tuple->dst.ip); + } else if (tuple->l3_type == AF_INET6) { + nl_msg_put_in6_addr(buf, CTA_IP_V6_SRC, &tuple->src.in6); + nl_msg_put_in6_addr(buf, CTA_IP_V6_DST, &tuple->dst.in6); + } else { + VLOG_WARN_RL(&rl, "Unsupported IP protocol: %"PRIu16".", + tuple->l3_type); + return false; + } + + nl_msg_end_nested(buf, offset); + return true; +} + +static bool +nl_ct_put_tuple_proto(struct ofpbuf *buf, const struct ct_dpif_tuple *tuple) +{ + size_t offset = nl_msg_start_nested(buf, CTA_TUPLE_PROTO); + + nl_msg_put_u8(buf, CTA_PROTO_NUM, tuple->ip_proto); + + if (tuple->l3_type == AF_INET && tuple->ip_proto == IPPROTO_ICMP) { + nl_msg_put_be16(buf, CTA_PROTO_ICMP_ID, tuple->icmp_id); + nl_msg_put_u8(buf, CTA_PROTO_ICMP_TYPE, tuple->icmp_type); + nl_msg_put_u8(buf, CTA_PROTO_ICMP_CODE, tuple->icmp_code); + } else if (tuple->l3_type == AF_INET6 && + tuple->ip_proto == IPPROTO_ICMPV6) { + nl_msg_put_be16(buf, CTA_PROTO_ICMPV6_ID, tuple->icmp_id); + nl_msg_put_u8(buf, CTA_PROTO_ICMPV6_TYPE, tuple->icmp_type); + nl_msg_put_u8(buf, CTA_PROTO_ICMPV6_CODE, tuple->icmp_code); + } else if (tuple->ip_proto == IPPROTO_TCP || + tuple->ip_proto == IPPROTO_UDP) { + nl_msg_put_be16(buf, CTA_PROTO_SRC_PORT, tuple->src_port); + nl_msg_put_be16(buf, CTA_PROTO_DST_PORT, tuple->dst_port); + } else { + VLOG_WARN_RL(&rl, "Unsupported L4 protocol: %"PRIu8".", + tuple->ip_proto); + return false; + } + + nl_msg_end_nested(buf, offset); + return true; +} + +static bool +nl_ct_put_ct_tuple(struct ofpbuf *buf, const struct ct_dpif_tuple *tuple, + enum ctattr_type type) +{ + if (type != CTA_TUPLE_ORIG && type != CTA_TUPLE_REPLY && + type != CTA_TUPLE_MASTER) { + return false; + } + + size_t offset = nl_msg_start_nested(buf, type); + + if (!nl_ct_put_tuple_ip(buf, tuple)) { + return false; + } + if (!nl_ct_put_tuple_proto(buf, tuple)) { + return false; + } + + nl_msg_end_nested(buf, offset); + return true; +} + /* Translate netlink TCP state to CT_DPIF_TCP state. */ static uint8_t nl_ct_tcp_state_to_dpif(uint8_t state) diff --git a/lib/netlink-conntrack.h b/lib/netlink-conntrack.h index a95aa69a4cde..8b536fd65ba8 100644 --- a/lib/netlink-conntrack.h +++ b/lib/netlink-conntrack.h @@ -42,6 +42,7 @@ int nl_ct_dump_done(struct nl_ct_dump_state *); int nl_ct_flush(void); int nl_ct_flush_zone(uint16_t zone); +int nl_ct_flush_tuple(const struct ct_dpif_tuple *, uint16_t zone); bool nl_ct_parse_entry(struct ofpbuf *, struct ct_dpif_entry *, enum nl_ct_event_type *); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index b14b339a962a..fc053290ad98 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4848,7 +4848,7 @@ ct_flush(const struct ofproto *ofproto_, const uint16_t *zone) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - ct_dpif_flush(ofproto->backer->dpif, zone); + ct_dpif_flush(ofproto->backer->dpif, zone, NULL); } static bool diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 28bca8b9b781..f8d43adccd33 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -3167,7 +3167,7 @@ AT_CHECK([ovs-appctl vlog/set ct_dpif:dbg]) AT_CHECK([ovs-ofctl ct-flush-zone br0 123]) OVS_WAIT_UNTIL([grep -q "|ct_dpif|DBG|.*ct_flush:" ovs-vswitchd.log]) -AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: 123" ovs-vswitchd.log]) +AT_CHECK([grep -q "ct_dpif|DBG|.*ct_flush: zone 123" ovs-vswitchd.log]) OVS_VSWITCHD_STOP AT_CLEANUP