From patchwork Mon Jul 9 16:32:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941433 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="CMdwVvfC"; 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 41PW9B11PRz9rvt for ; Tue, 10 Jul 2018 02:33:18 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 3D43BD65; Mon, 9 Jul 2018 16:32:40 +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 97916CD7 for ; Mon, 9 Jul 2018 16:32:38 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f66.google.com (mail-pl0-f66.google.com [209.85.160.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 5BA0378C for ; Mon, 9 Jul 2018 16:32:38 +0000 (UTC) Received: by mail-pl0-f66.google.com with SMTP id k1-v6so6278774plt.2 for ; Mon, 09 Jul 2018 09:32:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=xPA7hXj+lo4G83sg2YiFg+/6sRKsRdfb7uV+u3W0b/U=; b=CMdwVvfCOblqUXyhIL/g5Z29cLZAfe7QK1SKAjmxXFu8JZYsC8uI6SIH2zt9eGPIu4 y5cABdKgpbhxPbip3DcwvegqYj91M+PgWR20usjboGPzpGxWVu+uyJNr+Qo1zSQkPiDa NE95sfr2isOVaBFLxPcv2+tpRfdQRS4tJoY6+wp9R59liRTDBW0OvjdYSv5GuvOyjN3m 53ssoqO1NeNQ1ZRVzEGvuMrzIqwABUCsvLqUT2heh6lfIJQJfynhxsuovzuFKDVt9nE6 KiHxYjGBic/9r2WunYv11h89iX6FHWf05cXA4vSLE7qc/XywaeWZrDuoBNq9/Pml1jCo +Afg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=xPA7hXj+lo4G83sg2YiFg+/6sRKsRdfb7uV+u3W0b/U=; b=NeY6smF49jyr2XWdhpTNvIPe/FLaP3cgOBGsjdF26FcuZA27Pio1+NeprHNGYGoAP2 gbQyZhTHDkkI0t4Tj9gm0FjHMrM0rDYnoZFXYTs6WX5SbkzXgtiduS89hVKoCDfn+5ym ozIncwBuMWYIwe1wmRpWDq2tE0mi26h03CrNKG3hRFh0zvQWwGeYRM1uA2adjDX04jBg jhgHw6F/WbyYKiHixBdAetSrcixT7oBHXQZ3/4K36iYzjQexW86+abuklSshuhkCDtR1 eZDbUl4p69F6E4y2KMxsHVNmwmMtE4aPYV2z4RJxyHNwHXuHYLtUkJ6RuF4ibt17V4Q5 9pVw== X-Gm-Message-State: APt69E1/rpcZuo5/He1GlwQbEBhWl2KpjoSvN7/QQ/w+CgtJLSsGWMom yYBLtIH5rwWOY7z1gdCfES4= X-Google-Smtp-Source: AAOMgpdWRooQANMCOG/ZAPPLtzli1fhlGOmvEh/tRmLZF16BawAqMc6brfMNlSsSPKA+PLpzguhOeA== X-Received: by 2002:a17:902:301:: with SMTP id 1-v6mr21063118pld.127.1531153958074; Mon, 09 Jul 2018 09:32:38 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:36 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:17 -0700 Message-Id: <1531153945-121300-2-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 1/9] dp-packet: Add const qualifiers for checksum apis. 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 Signed-off-by: Darrell Ball Acked-by: Justin Pettit --- lib/dp-packet.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dp-packet.h b/lib/dp-packet.h index ba91e58..ecf16fb 100644 --- a/lib/dp-packet.h +++ b/lib/dp-packet.h @@ -637,7 +637,7 @@ dp_packet_mbuf_init(struct dp_packet *p OVS_UNUSED) } static inline bool -dp_packet_ip_checksum_valid(struct dp_packet *p OVS_UNUSED) +dp_packet_ip_checksum_valid(const struct dp_packet *p OVS_UNUSED) { #ifdef DPDK_NETDEV return (p->mbuf.ol_flags & PKT_RX_IP_CKSUM_MASK) == @@ -648,7 +648,7 @@ dp_packet_ip_checksum_valid(struct dp_packet *p OVS_UNUSED) } static inline bool -dp_packet_ip_checksum_bad(struct dp_packet *p OVS_UNUSED) +dp_packet_ip_checksum_bad(const struct dp_packet *p OVS_UNUSED) { #ifdef DPDK_NETDEV return (p->mbuf.ol_flags & PKT_RX_IP_CKSUM_MASK) == @@ -659,7 +659,7 @@ dp_packet_ip_checksum_bad(struct dp_packet *p OVS_UNUSED) } static inline bool -dp_packet_l4_checksum_valid(struct dp_packet *p OVS_UNUSED) +dp_packet_l4_checksum_valid(const struct dp_packet *p OVS_UNUSED) { #ifdef DPDK_NETDEV return (p->mbuf.ol_flags & PKT_RX_L4_CKSUM_MASK) == @@ -670,7 +670,7 @@ dp_packet_l4_checksum_valid(struct dp_packet *p OVS_UNUSED) } static inline bool -dp_packet_l4_checksum_bad(struct dp_packet *p OVS_UNUSED) +dp_packet_l4_checksum_bad(const struct dp_packet *p OVS_UNUSED) { #ifdef DPDK_NETDEV return (p->mbuf.ol_flags & PKT_RX_L4_CKSUM_MASK) == From patchwork Mon Jul 9 16:32:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941434 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="JyhkKhAc"; 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 41PW9h0fGxz9rvt for ; Tue, 10 Jul 2018 02:33:44 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id EACFBD7F; Mon, 9 Jul 2018 16:32:41 +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 833C6D08 for ; Mon, 9 Jul 2018 16:32:40 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f67.google.com (mail-pl0-f67.google.com [209.85.160.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 1EE3D78D for ; Mon, 9 Jul 2018 16:32:40 +0000 (UTC) Received: by mail-pl0-f67.google.com with SMTP id t6-v6so6274844plo.7 for ; Mon, 09 Jul 2018 09:32:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=5FO1ilynnaSwgjWQtDXwsUowgFeRwpDEPvK/Y0ZI8Os=; b=JyhkKhAcLE3+q3JU+Ro42ix90JNWzY0vZvKMYFJeKCXg4BV5mgeQb8Rxruo/ujuaYh xIJ4ofnd0L9HdetUuNhnWp+lylC659brOSbl0FytXjXNAABdgfjS1MTavZWwOrM397mY 1XPw7q4Q2QfhBgLQ5xaJRvMHoTDD1NwN4SmSEexp7lcWx12dhfY4mRx49jsD0ZsoqyIb UHwio7tGkBtnxGoNmO8rxQ3npg5bOyrr0dyK9uK70KSMon2kyl0mLf6Y72P1Gi3Y1bSI gNBdB7H8pFwLgvf3VFVVJZ2xIbhFQ1zN+b46LKgXa5KN0FBiIf4P26eosTBm6fMR/qWu vImw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=5FO1ilynnaSwgjWQtDXwsUowgFeRwpDEPvK/Y0ZI8Os=; b=FUxRZzpprW5EU+i8m0AKdRkBckF5Lm1iJ0LSdaW4UdBAzJu7r04wS0/6NQxTHX40km kW5yO/G2ozg317R6pXVq6+e3+dclJPjT3l4nEEwgd9R/Qs4nzowDYAozKhrRQ+eDMMjH gVF3C/R/ETHILg5Cq8/2LpexPexg0xCGYaVBcwAxPXipYVX854UmVuuiyov0M+dc+ZTN x4kz9s7SzhSZckdbvu2O2ySjD6gig5qxovqQIQz6iZwxOFtqsDB+QRlLKy2t+qAXDer2 oTspuCIJZiI3MaPsINy3l1SU14ue+YRxDqdmn+NNAvTXBURTXjWoZB6DiQNzB8cifMBV 8jcw== X-Gm-Message-State: APt69E2d3z7PXMzLCwQpZrGQJIXRUsCrqqwSvgFqk2P2PdTx8KbbUTGj eC+XBJlK7qaZgBK1/Tvv2Go= X-Google-Smtp-Source: AAOMgpe1sL6C/EIMcLHO6UqMDLfBAzJsnLO4Gd00GpL+ea52eMvPBYAPDdx2JCTcAPx3E6Gyn6DUkg== X-Received: by 2002:a17:902:7e08:: with SMTP id b8-v6mr21260286plm.230.1531153959787; Mon, 09 Jul 2018 09:32:39 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:38 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:18 -0700 Message-Id: <1531153945-121300-3-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 2/9] flow: Enhance parse_ipv6_ext_hdrs. 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 Enhance the api parse_ipv6_ext_hdrs to return the fragmentation header to be used in later patches. Signed-off-by: Darrell Ball Acked-by: Justin Pettit --- lib/conntrack.c | 4 ++-- lib/flow.c | 31 +++++++++++++++++++++---------- lib/flow.h | 3 ++- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/conntrack.c b/lib/conntrack.c index 97fd46a..efe8a18 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -1307,7 +1307,6 @@ conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch, const struct nat_action_info_t *nat_action_info, long long now) { - struct dp_packet *packet; struct conn_lookup_ctx ctx; @@ -1555,7 +1554,8 @@ extract_l3_ipv6(struct conn_key *key, const void *data, size_t size, uint8_t nw_proto = ip6->ip6_nxt; uint8_t nw_frag = 0; - if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag)) { + const struct ovs_16aligned_ip6_frag *frag_hdr; + if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag, &frag_hdr)) { return false; } diff --git a/lib/flow.c b/lib/flow.c index a785e63..8c4baf0 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -453,9 +453,14 @@ invalid: return true; } +/* datap points to the first extension header and advances as parsing + * occurs; sizep is the remaining size and is decreased accordingly. + * nw_proto starts as the first extension header to process and is + * updated as the extension headers are parsed. */ static inline bool parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto, - uint8_t *nw_frag) + uint8_t *nw_frag, + const struct ovs_16aligned_ip6_frag **frag_hdr) { while (1) { if (OVS_LIKELY((*nw_proto != IPPROTO_HOPOPTS) @@ -502,17 +507,17 @@ parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto, return false; } } else if (*nw_proto == IPPROTO_FRAGMENT) { - const struct ovs_16aligned_ip6_frag *frag_hdr = *datap; + *frag_hdr = *datap; - *nw_proto = frag_hdr->ip6f_nxt; - if (!data_try_pull(datap, sizep, sizeof *frag_hdr)) { + *nw_proto = (*frag_hdr)->ip6f_nxt; + if (!data_try_pull(datap, sizep, sizeof **frag_hdr)) { return false; } /* We only process the first fragment. */ - if (frag_hdr->ip6f_offlg != htons(0)) { + if ((*frag_hdr)->ip6f_offlg != htons(0)) { *nw_frag = FLOW_NW_FRAG_ANY; - if ((frag_hdr->ip6f_offlg & IP6F_OFF_MASK) != htons(0)) { + if (((*frag_hdr)->ip6f_offlg & IP6F_OFF_MASK) != htons(0)) { *nw_frag |= FLOW_NW_FRAG_LATER; *nw_proto = IPPROTO_FRAGMENT; return true; @@ -524,9 +529,11 @@ parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto, bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, - uint8_t *nw_frag) + uint8_t *nw_frag, + const struct ovs_16aligned_ip6_frag **frag_hdr) { - return parse_ipv6_ext_hdrs__(datap, sizep, nw_proto, nw_frag); + return parse_ipv6_ext_hdrs__(datap, sizep, nw_proto, nw_frag, + frag_hdr); } bool @@ -877,7 +884,9 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) nw_ttl = nh->ip6_hlim; nw_proto = nh->ip6_nxt; - if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag)) { + const struct ovs_16aligned_ip6_frag *frag_hdr; + if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag, + &frag_hdr)) { goto out; } } else { @@ -1067,7 +1076,9 @@ parse_tcp_flags(struct dp_packet *packet) plen = ntohs(nh->ip6_plen); /* Never pull padding. */ dp_packet_set_l2_pad_size(packet, size - plen); size = plen; - if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag)) { + const struct ovs_16aligned_ip6_frag *frag_hdr; + if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag, + &frag_hdr)) { return 0; } nw_proto = nh->ip6_nxt; diff --git a/lib/flow.h b/lib/flow.h index af7b5e9..e3e30f1 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -130,7 +130,8 @@ void flow_compose(struct dp_packet *, const struct flow *, void packet_expand(struct dp_packet *, const struct flow *, size_t size); bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, - uint8_t *nw_frag); + uint8_t *nw_frag, + const struct ovs_16aligned_ip6_frag **frag_hdr); ovs_be16 parse_dl_type(const struct eth_header *data_, size_t size); bool parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key); uint16_t parse_tcp_flags(struct dp_packet *packet); From patchwork Mon Jul 9 16:32:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941436 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="GwClvDHY"; 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 41PWF24Sn3z9s00 for ; Tue, 10 Jul 2018 02:34:16 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 955D6D88; Mon, 9 Jul 2018 16:32:42 +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 110E4D93 for ; Mon, 9 Jul 2018 16:32:42 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f67.google.com (mail-pl0-f67.google.com [209.85.160.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id C73B178D for ; Mon, 9 Jul 2018 16:32:41 +0000 (UTC) Received: by mail-pl0-f67.google.com with SMTP id m16-v6so6275402pls.11 for ; Mon, 09 Jul 2018 09:32:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=NnuGTx/3hmXfFiLwLxpUfOSmf9X8RkRer71GSTyNaFs=; b=GwClvDHYI8tXyTtfCRkLmAzt6UqUVRGTVbK43VYLLYlJ2wMjLc/dIgQsoB7b2/F+Ru gvIHnilU4xyXTtRQeyM0Ndv/FgLu548Sx2/iVZV+mo7MKJXT1TTwT43tNJ2xRo/HEWOi ZjjdJRgH/ihFd25Kb5ztCLDSJCPo3Ro2szFcQXLQFz0I3GoS/jiJt72myGckaOXYJJRs SVLEMLzQ2clhalwpnYlU7D+vTr/HwDi+w1gmhN2uFZ9WJW+dGnaczfM00c7kMc3DHhIO rc/cOO+rfQ45SQRjJR+EBuxlwTzlX/Zpvl9Ud2+RPLcVOXANWMCcx2HEl4a2NezrA6aI auwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=NnuGTx/3hmXfFiLwLxpUfOSmf9X8RkRer71GSTyNaFs=; b=NXx8vO/ZS3wYxKAN4owL3Vr4RlrtJu/2UTtwGH3NGdautgI/4GTDl7VRokpBToXvAi AoCDYOYaXRNj4UF01XD6CsegudXUhobJcHeHKbC1Gq5S/z1ILOt8n/Vsj00QnwdhkYXk +izplJd24qzQZ8vyMMhv6PLMsfh1Ex8v33eROyZ3QBYKzUWJ/6HPOST+SGn1WuVZ0ixk ZYqef7/TjAqpItC4VFDWfNi7szw5x5SrGa+agmunm8ECj+IydukWH9EgslTkg3JonWvQ Jpq0Ap6JM0FrnVrzQlAvLkGw9jNnSE+JYdFJDDLMCDCTKJNJwOrx0ersNCfNlQLGiwUX pSrg== X-Gm-Message-State: APt69E0YeVsRtFSNRUbzbr4aCoRjjnqXivw35n5tk3qSZqg9xYVUdtlt dGo0j7swEdRFnspTSQ2Nt+c= X-Google-Smtp-Source: AAOMgpcA90g91vYELKSgZxuVdCMFIXqw2L7X76/Dln42SpWKGcjJuMvyk4l1aqrxVJbpp++Z5qwrjg== X-Received: by 2002:a17:902:1682:: with SMTP id h2-v6mr21260464plh.327.1531153961518; Mon, 09 Jul 2018 09:32:41 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:40 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:19 -0700 Message-Id: <1531153945-121300-4-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 3/9] tests: Add missed local stack checks. 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 Signed-off-by: Darrell Ball Acked-by: Justin Pettit --- tests/system-traffic.at | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 519b234..75648d4 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -2530,6 +2530,7 @@ AT_SETUP([conntrack - Fragmentation over vxlan]) OVS_CHECK_VXLAN() CHECK_CONNTRACK() CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_LOCAL_STACK() OVS_TRAFFIC_VSWITCHD_START() ADD_BR([br-underlay]) @@ -2582,6 +2583,7 @@ AT_SETUP([conntrack - IPv6 Fragmentation over vxlan]) OVS_CHECK_VXLAN() CHECK_CONNTRACK() CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_LOCAL_STACK() OVS_TRAFFIC_VSWITCHD_START() ADD_BR([br-underlay]) From patchwork Mon Jul 9 16:32:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941437 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="T+bLvfxP"; 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 41PWF24XVhz9s19 for ; Tue, 10 Jul 2018 02:34:50 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 40088D98; Mon, 9 Jul 2018 16:32:45 +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 AEB7FD95 for ; Mon, 9 Jul 2018 16:32:43 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg1-f194.google.com (mail-pg1-f194.google.com [209.85.215.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 71A6978C for ; Mon, 9 Jul 2018 16:32:43 +0000 (UTC) Received: by mail-pg1-f194.google.com with SMTP id m19-v6so1365918pgv.3 for ; Mon, 09 Jul 2018 09:32:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=Ztt0RahRFwd0IQF/owxOzJ1xkhJJlc536VobB1XkcDk=; b=T+bLvfxP9DZz8PTGGLf8pHEb1gPWo20byuqfkElah3noevihBvmxgpdPU2x1D6WGCb 66/7joHTh713FWkE3tcCwsMe5ksyG8sl3omjNOoSgsOkSS2aYWrIhf1C2YizsIRM57g5 7tkGhh/LcloAstmigvuzl7IeRPiZZu9YSdcCR+BF/wjDe1+rUCfRVplGWVfzijJfKsA7 EW3FOXrLAZXmCK4zhfo+xC56o225cxSZ1hwD7/jn8RyWNDr/fuHnCmQZmNPv3FCt5huh Qukk55+/fSurGWJESscMq4KUSFP0Y9HgjwzZx5Ni2+x3aq4JSqw0MPN7FHYS/YQPBxFH PdUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=Ztt0RahRFwd0IQF/owxOzJ1xkhJJlc536VobB1XkcDk=; b=oj88TVD6jgCZee5Ci+j/6y2te7qd4vHFVpnWhV/yo46dknixrOgTkC76I4HiDyJVBa JoL4M2Pmd/TdY306YCghKXNJCbYOTxP4V4cRt7fHnVm6w6wk+BO9Y9h1uvLCFittMriG /ipcW0T8OYIdIN/Kssjza1mUHs/4nZ2nXaEiWQKx/+MtXxP2dDAN21dZUyonB5PJQa3G g2NMb0p2dasiY3d0eWNRF41n+FgRmhSbKvmPZEFNlmoXd2bZ7q8wkK2es2gSZULLmbsg waGncx0aqvD4XMup2jpEHN4mNt34D79bci8llGGk1Ov+injvDNE8uWME0IH+WS9BT9qy Ysgg== X-Gm-Message-State: APt69E0LTmJletNuO/qI6ZmEzoqKMdo0CZonMiXqJTrxtn+R9ZASQqzb jPYQadvHE57/1qmt1vmLe+w= X-Google-Smtp-Source: AAOMgpfG3CcwMxu6T7VwB4GPMgRC4SlDtwokM1Grz4KBG5Luf5dioHKUyxQxku4kArNeqKUsmaCMKA== X-Received: by 2002:a62:843:: with SMTP id c64-v6mr22003750pfd.14.1531153963157; Mon, 09 Jul 2018 09:32:43 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:42 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:20 -0700 Message-Id: <1531153945-121300-5-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 4/9] conntrack: Reword conntrack_execute() description. 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 Use 'must' instead of 'should'. Signed-off-by: Darrell Ball --- lib/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/conntrack.c b/lib/conntrack.c index efe8a18..30941ff 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -1291,7 +1291,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, } /* Sends the packets in '*pkt_batch' through the connection tracker 'ct'. All - * the packets should have the same 'dl_type' (IPv4 or IPv6) and should have + * the packets must have the same 'dl_type' (IPv4 or IPv6) and should have * the l3 and and l4 offset properly set. * * If 'commit' is true, the packets are allowed to create new entries in the From patchwork Mon Jul 9 16:32:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941439 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="s0ISL8Wq"; 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 41PWF24SM0z9ryt for ; Tue, 10 Jul 2018 02:36:00 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id DD9DEE2B; Mon, 9 Jul 2018 16:32:51 +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 09481DA6 for ; Mon, 9 Jul 2018 16:32:49 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f194.google.com (mail-pf0-f194.google.com [209.85.192.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 454B678E for ; Mon, 9 Jul 2018 16:32:46 +0000 (UTC) Received: by mail-pf0-f194.google.com with SMTP id q7-v6so12938007pff.2 for ; Mon, 09 Jul 2018 09:32:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=AK+jA0IbDBEf9hfl9k8CUnOQm81XS7ksC4DfhH0Uj7U=; b=s0ISL8Wqdb4egTFEPppAJphAT0yX5fXHnmjju0TV0mgJWInspap3OdCSqsnaZJ/er3 ERbLU8/3UBWbAmm+3e3z6K6UbgoCEj2vsiL1dbwUjy7fKeCSGltH0hJqeijvnTu18Ino rK0NUCZZDyGGtuBSPyxf2JcDYcr8Okvjxib25jCO7sjSYUmvt17cuctqCE+GwsSUws54 e2WhPslOyi51O8UQCVZ+qNmeqy2MgvBmrNalkrd8dACRHeZmbKyKyxAeMgx674AyzbOa zkm5aqxMX9PhVpJZs9ZCLj4zeWjxgpXS9xLTZqfz2vUUJ1a9KFhfn8GUK0pNLFiUI3YM mq2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=AK+jA0IbDBEf9hfl9k8CUnOQm81XS7ksC4DfhH0Uj7U=; b=nPaQo/dRRJ5uopKZ1Hic2l7ixdHtlKGSSFM+VClKqIiZDlXTtKTrVfSrM6yeGPkHqk 3lM+ss6CXjKuBEU//N5FG8yXFPzaQaeC+kG7/0OYlYXc2ydCvCLcu7e0d1eRpUGrthAE BMjp8k7+OwE66fEvupzBlvVJj+HpgvSPDmzu9bnziGgtLTzosR66SPGFSYr+vGGi4BbT siq9+T4HsuBKQO0dfZA7mVqDnq8M225nB7qPm+pLoqJeZBZw149N+S7M0u42Qu0WXZBD ffT4aLkLXC8GA6Tpy8L5N1xhJeQXEijG+2McO92V3gkENfhMqrADWVLpuBByx7dnHUO9 dYNQ== X-Gm-Message-State: APt69E3fDp1dW9Pe1mmi4WkgM6lSu7AvuUrgPkaJBd5RIkpE2zadxT1s Vs77iAiLyWKAANJRtF/vd1E= X-Google-Smtp-Source: AAOMgpfLoD1TmhQc5U0zfo+owc8RFC//C1GY/M0Szx60NYvO1hu9hbDgPUIAgxWj6HCmDgZb99HfSg== X-Received: by 2002:a62:d8c:: with SMTP id 12-v6mr20764914pfn.202.1531153965067; Mon, 09 Jul 2018 09:32:45 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:43 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:21 -0700 Message-Id: <1531153945-121300-6-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 5/9] Userspace datapath: Add fragmentation handling. 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 Fragmentation handling is added for supporting conntrack. Both v4 and v6 are supported. After discussion with several people, I decided to not store configuration state in the database to be more consistent with the kernel in future, similarity with other conntrack configuration which will not be in the database as well and overall simplicity. Accordingly, fragmentation handling is enabled by default. This patch enables fragmentation tests for the userspace datapath. Signed-off-by: Darrell Ball --- NEWS | 2 + include/sparse/netinet/ip6.h | 1 + lib/automake.mk | 2 + lib/conntrack.c | 13 +- lib/ipf.c | 1266 ++++++++++++++++++++++++++++++++++++++ lib/ipf.h | 60 ++ tests/system-kmod-macros.at | 10 +- tests/system-traffic.at | 30 +- tests/system-userspace-macros.at | 26 +- 9 files changed, 1365 insertions(+), 45 deletions(-) create mode 100644 lib/ipf.c create mode 100644 lib/ipf.h diff --git a/NEWS b/NEWS index 92e9b92..e0418a5 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ Post-v2.9.0 * ovs-ofctl now accepts and display table names in place of numbers. By default it always accepts names and in interactive use it displays them; use --names or --no-names to override. See ovs-ofctl(8) for details. + - Userspace datapath: + * Add v4/v6 fragmentation support for conntrack. - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". - OpenFlow: * OFPT_ROLE_STATUS is now available in OpenFlow 1.3. diff --git a/include/sparse/netinet/ip6.h b/include/sparse/netinet/ip6.h index d2a54de..bfa637a 100644 --- a/include/sparse/netinet/ip6.h +++ b/include/sparse/netinet/ip6.h @@ -64,5 +64,6 @@ struct ip6_frag { }; #define IP6F_OFF_MASK ((OVS_FORCE ovs_be16) 0xfff8) +#define IP6F_MORE_FRAG ((OVS_FORCE ovs_be16) 0x0001) #endif /* netinet/ip6.h sparse */ diff --git a/lib/automake.mk b/lib/automake.mk index fb43aa1..142587f 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -107,6 +107,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/hmapx.h \ lib/id-pool.c \ lib/id-pool.h \ + lib/ipf.c \ + lib/ipf.h \ lib/jhash.c \ lib/jhash.h \ lib/json.c \ diff --git a/lib/conntrack.c b/lib/conntrack.c index 30941ff..e1c1f2e 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -30,6 +30,7 @@ #include "ct-dpif.h" #include "dp-packet.h" #include "flow.h" +#include "ipf.h" #include "netdev.h" #include "odp-netlink.h" #include "openvswitch/hmap.h" @@ -339,6 +340,7 @@ conntrack_init(struct conntrack *ct) atomic_init(&ct->n_conn_limit, DEFAULT_N_CONN_LIMIT); latch_init(&ct->clean_thread_exit); ct->clean_thread = ovs_thread_create("ct_clean", clean_thread_main, ct); + ipf_init(); } /* Destroys the connection tracker 'ct' and frees all the allocated memory. */ @@ -381,6 +383,7 @@ conntrack_destroy(struct conntrack *ct) hindex_destroy(&ct->alg_expectation_refs); ct_rwlock_unlock(&ct->resources_lock); ct_rwlock_destroy(&ct->resources_lock); + ipf_destroy(); } static unsigned hash_to_bucket(uint32_t hash) @@ -1292,7 +1295,8 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, /* Sends the packets in '*pkt_batch' through the connection tracker 'ct'. All * the packets must have the same 'dl_type' (IPv4 or IPv6) and should have - * the l3 and and l4 offset properly set. + * the l3 and and l4 offset properly set. Performs fragment reassembly with + * the help of ipf_preprocess_conntrack(). * * If 'commit' is true, the packets are allowed to create new entries in the * connection tables. 'setmark', if not NULL, should point to a two @@ -1307,11 +1311,14 @@ conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch, const struct nat_action_info_t *nat_action_info, long long now) { + ipf_preprocess_conntrack(pkt_batch, now, dl_type, zone, ct->hash_basis); + struct dp_packet *packet; struct conn_lookup_ctx ctx; DP_PACKET_BATCH_FOR_EACH (i, packet, pkt_batch) { - if (!conn_key_extract(ct, packet, dl_type, &ctx, zone)) { + if (packet->md.ct_state == CS_INVALID + || !conn_key_extract(ct, packet, dl_type, &ctx, zone)) { packet->md.ct_state = CS_INVALID; write_ct_md(packet, zone, NULL, NULL, NULL); continue; @@ -1320,6 +1327,8 @@ conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch, setlabel, nat_action_info, tp_src, tp_dst, helper); } + ipf_postprocess_conntrack(pkt_batch, now, dl_type); + return 0; } diff --git a/lib/ipf.c b/lib/ipf.c new file mode 100644 index 0000000..2c26e1f --- /dev/null +++ b/lib/ipf.c @@ -0,0 +1,1266 @@ +/* + * Copyright (c) 2018 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coverage.h" +#include "csum.h" +#include "ipf.h" +#include "openvswitch/hmap.h" +#include "openvswitch/vlog.h" +#include "ovs-atomic.h" +#include "packets.h" +#include "util.h" + +VLOG_DEFINE_THIS_MODULE(ipf); +COVERAGE_DEFINE(ipf_stuck_frag_list_purged); + +enum { + IPV4_PACKET_MAX_HDR_SIZE = 60, + IPV4_PACKET_MAX_SIZE = 65535, + IPV6_PACKET_MAX_DATA = 65535, +}; + +enum ipf_list_state { + IPF_LIST_STATE_UNUSED, + IPF_LIST_STATE_REASS_FAIL, + IPF_LIST_STATE_OTHER_SEEN, + IPF_LIST_STATE_FIRST_SEEN, + IPF_LIST_STATE_LAST_SEEN, + IPF_LIST_STATE_FIRST_LAST_SEEN, + IPF_LIST_STATE_COMPLETED, + IPF_LIST_STATE_NUM, +}; + +enum ipf_list_type { + IPF_FRAG_COMPLETED_LIST, + IPF_FRAG_EXPIRY_LIST, +}; + +enum { + IPF_INVALID_IDX = -1, + IPF_V4_FRAG_SIZE_LBOUND = 400, + IPF_V4_FRAG_SIZE_MIN_DEF = 1200, + IPF_V6_FRAG_SIZE_LBOUND = 400, /* Useful for testing. */ + IPF_V6_FRAG_SIZE_MIN_DEF = 1280, + IPF_MAX_FRAGS_DEFAULT = 1000, + IPF_NFRAG_UBOUND = 5000, +}; + +enum ipf_counter_type { + IPF_COUNTER_NFRAGS, + IPF_COUNTER_NFRAGS_ACCEPTED, + IPF_COUNTER_NFRAGS_COMPL_SENT, + IPF_COUNTER_NFRAGS_EXPD_SENT, + IPF_COUNTER_NFRAGS_TOO_SMALL, + IPF_COUNTER_NFRAGS_OVERLAP, +}; + +struct ipf_addr { + union { + ovs_16aligned_be32 ipv4; + union ovs_16aligned_in6_addr ipv6; + ovs_be32 ipv4_aligned; + struct in6_addr ipv6_aligned; + }; +}; + +struct ipf_frag { + struct dp_packet *pkt; + uint16_t start_data_byte; + uint16_t end_data_byte; +}; + +struct ipf_list_key { + struct ipf_addr src_addr; + struct ipf_addr dst_addr; + uint32_t recirc_id; + ovs_be32 ip_id; /* V6 is 32 bits. */ + ovs_be16 dl_type; + uint16_t zone; + uint8_t nw_proto; +}; + +struct ipf_list { + struct hmap_node node; + struct ovs_list list_node; + struct ipf_frag *frag_list; + struct ipf_list_key key; + struct dp_packet *reass_execute_ctx; /* reassembled packet. */ + long long expiration; + int last_sent_idx; /* last sent fragment idx. */ + int last_inuse_idx; /* last inuse fragment idx. */ + int size; /* fragment list size. */ + uint8_t state; /* frag list state; see ipf_list_state. */ +}; + +struct reassembled_pkt { + struct ovs_list rp_list_node; + struct dp_packet *pkt; + struct ipf_list *list; +}; + +struct OVS_LOCKABLE ipf_lock { + struct ovs_mutex lock; +}; + +static struct ipf_lock ipf_lock; + +static int max_v4_frag_list_size; + +static struct hmap frag_lists OVS_GUARDED_BY(ipf_lock); +static struct ovs_list frag_exp_list OVS_GUARDED_BY(ipf_lock); +static struct ovs_list frag_complete_list OVS_GUARDED_BY(ipf_lock); +static struct ovs_list reassembled_pkt_list OVS_GUARDED_BY(ipf_lock); + +static atomic_bool ifp_v4_enabled; +static atomic_bool ifp_v6_enabled; +static atomic_uint nfrag_max; +/* Will be clamped above 400 bytes; the value chosen should handle + * alg control packets of interest that use string encoding of mutable + * IP fields; meaning, the control packets should not be fragmented. */ +static atomic_uint min_v4_frag_size; +static atomic_uint min_v6_frag_size; + +static atomic_count nfrag; +static atomic_count n4frag_accepted; +static atomic_count n4frag_completed_sent; +static atomic_count n4frag_expired_sent; +static atomic_count n4frag_too_small; +static atomic_count n4frag_overlap; +static atomic_count n6frag_accepted; +static atomic_count n6frag_completed_sent; +static atomic_count n6frag_expired_sent; +static atomic_count n6frag_too_small; +static atomic_count n6frag_overlap; + +static void +ipf_print_reass_packet(char *es, void *pkt) +{ + const unsigned char *b = (const unsigned char *) pkt; + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10); + VLOG_WARN_RL(&rl, "%s 91 bytes from specified part of packet " + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + es, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], + b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], + b[17], b[18], b[19], b[20], b[21], b[22], b[23], b[24], + b[25], b[26], b[27], b[28], b[29], b[30], b[31], b[32], + b[33], b[34], b[35], b[36], b[37], b[38], b[39], b[40], + b[41], b[42], b[43], b[44], b[45], b[46], b[47], b[48], + b[49], b[50], b[51], b[52], b[53], b[54], b[55], b[56], + b[57], b[58], b[59], b[60], b[61], b[62], b[63], b[64], + b[65], b[66], b[67], b[68], b[69], b[70], b[71], b[72], + b[73], b[74], b[75], b[76], b[77], b[77], b[79], b[80], + b[81], b[82], b[83], b[84], b[85], b[86], b[87], b[88], + b[89], b[90]); +} + +static void ipf_lock_init(struct ipf_lock *lock) +{ + ovs_mutex_init_adaptive(&lock->lock); +} + +static void ipf_lock_lock(struct ipf_lock *lock) + OVS_ACQUIRES(lock) + OVS_NO_THREAD_SAFETY_ANALYSIS +{ + ovs_mutex_lock(&lock->lock); +} + +static void ipf_lock_unlock(struct ipf_lock *lock) + OVS_RELEASES(lock) + OVS_NO_THREAD_SAFETY_ANALYSIS +{ + ovs_mutex_unlock(&lock->lock); +} + +static void ipf_lock_destroy(struct ipf_lock *lock) +{ + ovs_mutex_destroy(&lock->lock); +} + +static void +ipf_count(bool v6, enum ipf_counter_type cntr) +{ + switch (cntr) { + case IPF_COUNTER_NFRAGS_ACCEPTED: + atomic_count_inc(v6 ? &n6frag_accepted : &n4frag_accepted); + break; + case IPF_COUNTER_NFRAGS_COMPL_SENT: + atomic_count_inc(v6 ? &n6frag_completed_sent + : &n4frag_completed_sent); + break; + case IPF_COUNTER_NFRAGS_EXPD_SENT: + atomic_count_inc(v6 ? &n6frag_expired_sent + : &n4frag_expired_sent); + break; + case IPF_COUNTER_NFRAGS_TOO_SMALL: + atomic_count_inc(v6 ? &n6frag_too_small : &n4frag_too_small); + break; + case IPF_COUNTER_NFRAGS_OVERLAP: + atomic_count_inc(v6 ? &n6frag_overlap : &n4frag_overlap); + break; + case IPF_COUNTER_NFRAGS: + default: + OVS_NOT_REACHED(); + } +} + +static bool +ipf_get_v4_enabled(void) +{ + bool ifp_v4_enabled_; + atomic_read_relaxed(&ifp_v4_enabled, &ifp_v4_enabled_); + return ifp_v4_enabled_; +} + +static bool +ipf_get_v6_enabled(void) +{ + bool ifp_v6_enabled_; + atomic_read_relaxed(&ifp_v6_enabled, &ifp_v6_enabled_); + return ifp_v6_enabled_; +} + +static bool +ipf_get_enabled(void) +{ + return ipf_get_v4_enabled() || ipf_get_v6_enabled(); +} + +static uint32_t +ipf_addr_hash_add(uint32_t hash, const struct ipf_addr *addr) +{ + BUILD_ASSERT_DECL(sizeof *addr % 4 == 0); + return hash_add_bytes32(hash, (const uint32_t *) addr, sizeof *addr); +} + +static void +ipf_expiry_list_add(struct ipf_list *ipf_list, long long now) + OVS_REQUIRES(ipf_lock) +{ + enum { + IPF_FRAG_LIST_TIMEOUT_DEFAULT = 15000, + }; + + ipf_list->expiration = now + IPF_FRAG_LIST_TIMEOUT_DEFAULT; + ovs_list_push_back(&frag_exp_list, &ipf_list->list_node); +} + +static void +ipf_completed_list_add(struct ipf_list *ipf_list) + OVS_REQUIRES(ipf_lock) +{ + ovs_list_push_back(&frag_complete_list, &ipf_list->list_node); +} + +static void +ipf_reassembled_list_add(struct reassembled_pkt *rp) + OVS_REQUIRES(ipf_lock) +{ + ovs_list_push_back(&reassembled_pkt_list, &rp->rp_list_node); +} + +static void +ipf_list_clean(struct ipf_list *ipf_list) + OVS_REQUIRES(ipf_lock) +{ + ovs_list_remove(&ipf_list->list_node); + hmap_remove(&frag_lists, &ipf_list->node); + free(ipf_list->frag_list); + free(ipf_list); +} + +static void +ipf_expiry_list_clean(struct ipf_list *ipf_list) + OVS_REQUIRES(ipf_lock) +{ + ipf_list_clean(ipf_list); +} + +static void +ipf_completed_list_clean(struct ipf_list *ipf_list) + OVS_REQUIRES(ipf_lock) +{ + ipf_list_clean(ipf_list); +} + +static void +ipf_expiry_list_remove(struct ipf_list *ipf_list) + OVS_REQUIRES(ipf_lock) +{ + ovs_list_remove(&ipf_list->list_node); +} + +static void +ipf_reassembled_list_remove(struct reassembled_pkt *rp) + OVS_REQUIRES(ipf_lock) +{ + ovs_list_remove(&rp->rp_list_node); +} + +/* Symmetric */ +static uint32_t +ipf_list_key_hash(const struct ipf_list_key *key, uint32_t basis) +{ + uint32_t hsrc, hdst, hash; + hsrc = hdst = basis; + hsrc = ipf_addr_hash_add(hsrc, &key->src_addr); + hdst = ipf_addr_hash_add(hdst, &key->dst_addr); + hash = hsrc ^ hdst; + + /* Hash the rest of the key. */ + hash = hash_words((uint32_t *) (&key->dst_addr + 1), + (uint32_t *) (key + 1) - + (uint32_t *) (&key->dst_addr + 1), + hash); + + return hash_finish(hash, 0); +} + +static bool +ipf_is_first_v4_frag(const struct dp_packet *pkt) +{ + const struct ip_header *l3 = dp_packet_l3(pkt); + if (!(l3->ip_frag_off & htons(IP_FRAG_OFF_MASK)) && + l3->ip_frag_off & htons(IP_MORE_FRAGMENTS)) { + return true; + } + return false; +} + +static bool +ipf_is_last_v4_frag(const struct dp_packet *pkt) +{ + const struct ip_header *l3 = dp_packet_l3(pkt); + if (l3->ip_frag_off & htons(IP_FRAG_OFF_MASK) && + !(l3->ip_frag_off & htons(IP_MORE_FRAGMENTS))) { + return true; + } + return false; +} + +static bool +ipf_is_v6_frag(ovs_be16 ip6f_offlg) +{ + if (ip6f_offlg & (IP6F_OFF_MASK | IP6F_MORE_FRAG)) { + return true; + } + return false; +} + +static bool +ipf_is_first_v6_frag(ovs_be16 ip6f_offlg) +{ + if (!(ip6f_offlg & IP6F_OFF_MASK) && + ip6f_offlg & IP6F_MORE_FRAG) { + return true; + } + return false; +} + +static bool +ipf_is_last_v6_frag(ovs_be16 ip6f_offlg) +{ + if ((ip6f_offlg & IP6F_OFF_MASK) && + !(ip6f_offlg & IP6F_MORE_FRAG)) { + return true; + } + return false; +} + +static bool +ipf_list_complete(const struct ipf_list *ipf_list) + OVS_REQUIRES(ipf_lock) +{ + for (int i = 0; i < ipf_list->last_inuse_idx; i++) { + if (ipf_list->frag_list[i].end_data_byte + 1 + != ipf_list->frag_list[i + 1].start_data_byte) { + return false; + } + } + return true; +} + +/* Runs O(n) for a sorted or almost sorted list. */ +static void +ipf_sort(struct ipf_frag *frag_list, size_t last_idx) + OVS_REQUIRES(ipf_lock) +{ + int running_last_idx = 1; + struct ipf_frag ipf_frag; + while (running_last_idx <= last_idx) { + ipf_frag = frag_list[running_last_idx]; + int frag_list_idx = running_last_idx - 1; + while (frag_list_idx >= 0 && + frag_list[frag_list_idx].start_data_byte > + ipf_frag.start_data_byte) { + frag_list[frag_list_idx + 1] = frag_list[frag_list_idx]; + frag_list_idx -= 1; + } + frag_list[frag_list_idx + 1] = ipf_frag; + running_last_idx++; + } +} + +/* Called on a sorted complete list of fragments. */ +static struct dp_packet * +ipf_reassemble_v4_frags(struct ipf_list *ipf_list) + OVS_REQUIRES(ipf_lock) +{ + struct ipf_frag *frag_list = ipf_list->frag_list; + struct dp_packet *pkt = dp_packet_clone(frag_list[0].pkt); + struct ip_header *l3 = dp_packet_l3(pkt); + int len = ntohs(l3->ip_tot_len); + size_t add_len; + size_t ip_hdr_len = IP_IHL(l3->ip_ihl_ver) * 4; + + for (int i = 1; i <= ipf_list->last_inuse_idx; i++) { + add_len = frag_list[i].end_data_byte - + frag_list[i].start_data_byte + 1; + len += add_len; + if (len > IPV4_PACKET_MAX_SIZE) { + ipf_print_reass_packet( + "Unsupported big reassmbled v4 packet; v4 hdr:", l3); + dp_packet_delete(pkt); + return NULL; + } + l3 = dp_packet_l3(frag_list[i].pkt); + dp_packet_put(pkt, (char *)l3 + ip_hdr_len, add_len); + } + l3 = dp_packet_l3(pkt); + ovs_be16 new_ip_frag_off = l3->ip_frag_off & ~htons(IP_MORE_FRAGMENTS); + l3->ip_csum = recalc_csum16(l3->ip_csum, l3->ip_frag_off, + new_ip_frag_off); + l3->ip_csum = recalc_csum16(l3->ip_csum, l3->ip_tot_len, htons(len)); + l3->ip_tot_len = htons(len); + l3->ip_frag_off = new_ip_frag_off; + + return pkt; +} + +/* Called on a sorted complete list of fragments. */ +static struct dp_packet * +ipf_reassemble_v6_frags(struct ipf_list *ipf_list) + OVS_REQUIRES(ipf_lock) +{ + struct ipf_frag *frag_list = ipf_list->frag_list; + struct dp_packet *pkt = dp_packet_clone(frag_list[0].pkt); + struct ovs_16aligned_ip6_hdr *l3 = dp_packet_l3(pkt); + int pl = ntohs(l3->ip6_plen) - sizeof(struct ovs_16aligned_ip6_frag); + const char *tail = dp_packet_tail(pkt); + uint8_t pad = dp_packet_l2_pad_size(pkt); + const char *l4 = dp_packet_l4(pkt); + size_t l3_size = tail - (char *)l3 - pad; + size_t l4_size = tail - (char *)l4 - pad; + size_t l3_hlen = l3_size - l4_size; + size_t add_len; + + for (int i = 1; i <= ipf_list->last_inuse_idx; i++) { + add_len = frag_list[i].end_data_byte - + frag_list[i].start_data_byte + 1; + pl += add_len; + if (pl > IPV6_PACKET_MAX_DATA) { + ipf_print_reass_packet( + "Unsupported big reassmbled v6 packet; v6 hdr:", l3); + dp_packet_delete(pkt); + return NULL; + } + l3 = dp_packet_l3(frag_list[i].pkt); + dp_packet_put(pkt, (char *)l3 + l3_hlen, add_len); + } + l3 = dp_packet_l3(pkt); + l4 = dp_packet_l4(pkt); + tail = dp_packet_tail(pkt); + pad = dp_packet_l2_pad_size(pkt); + l3_size = tail - (char *)l3 - pad; + + uint8_t nw_proto = l3->ip6_nxt; + uint8_t nw_frag = 0; + const void *data = l3 + 1; + size_t datasize = l3_size - sizeof *l3; + + const struct ovs_16aligned_ip6_frag *frag_hdr = NULL; + if (!parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag, &frag_hdr) + || !nw_frag || !frag_hdr) { + + ipf_print_reass_packet("Unparsed reassmbled v6 packet; v6 hdr:", l3); + dp_packet_delete(pkt); + return NULL; + } + + struct ovs_16aligned_ip6_frag *fh = + CONST_CAST(struct ovs_16aligned_ip6_frag *, frag_hdr); + fh->ip6f_offlg = 0; + l3->ip6_plen = htons(pl); + l3->ip6_ctlun.ip6_un1.ip6_un1_nxt = nw_proto; + return pkt; +} + +/* Called when a valid fragment is added. */ +static void +ipf_list_state_transition(struct ipf_list *ipf_list, bool ff, bool lf, + bool v6) + OVS_REQUIRES(ipf_lock) +{ + enum ipf_list_state curr_state = ipf_list->state; + enum ipf_list_state next_state; + switch (curr_state) { + case IPF_LIST_STATE_UNUSED: + case IPF_LIST_STATE_OTHER_SEEN: + if (ff) { + next_state = IPF_LIST_STATE_FIRST_SEEN; + } else if (lf) { + next_state = IPF_LIST_STATE_LAST_SEEN; + } else { + next_state = IPF_LIST_STATE_OTHER_SEEN; + } + break; + case IPF_LIST_STATE_FIRST_SEEN: + if (ff) { + next_state = IPF_LIST_STATE_FIRST_SEEN; + } else if (lf) { + next_state = IPF_LIST_STATE_FIRST_LAST_SEEN; + } else { + next_state = IPF_LIST_STATE_FIRST_SEEN; + } + break; + case IPF_LIST_STATE_LAST_SEEN: + if (ff) { + next_state = IPF_LIST_STATE_FIRST_LAST_SEEN; + } else if (lf) { + next_state = IPF_LIST_STATE_LAST_SEEN; + } else { + next_state = IPF_LIST_STATE_LAST_SEEN; + } + break; + case IPF_LIST_STATE_FIRST_LAST_SEEN: + next_state = IPF_LIST_STATE_FIRST_LAST_SEEN; + break; + case IPF_LIST_STATE_COMPLETED: + case IPF_LIST_STATE_REASS_FAIL: + case IPF_LIST_STATE_NUM: + default: + OVS_NOT_REACHED(); + } + + if (next_state == IPF_LIST_STATE_FIRST_LAST_SEEN) { + ipf_sort(ipf_list->frag_list, ipf_list->last_inuse_idx); + if (ipf_list_complete(ipf_list)) { + struct dp_packet *reass_pkt = NULL; + if (v6) { + reass_pkt = ipf_reassemble_v6_frags(ipf_list); + } else { + reass_pkt = ipf_reassemble_v4_frags(ipf_list); + } + if (reass_pkt) { + struct reassembled_pkt *rp = xzalloc(sizeof *rp); + rp->pkt = reass_pkt; + rp->list = ipf_list; + ipf_reassembled_list_add(rp); + ipf_expiry_list_remove(ipf_list); + next_state = IPF_LIST_STATE_COMPLETED; + } else { + next_state = IPF_LIST_STATE_REASS_FAIL; + } + } + } + ipf_list->state = next_state; +} + +static bool +ipf_return_invalid(struct dp_packet *pkt) +{ + pkt->md.ct_state = CS_INVALID; + return false; +} + +static bool +ipf_v4_key_extract(struct dp_packet *pkt, ovs_be16 dl_type, uint16_t zone, + struct ipf_list_key *key, uint16_t *start_data_byte, + uint16_t *end_data_byte, bool *ff, bool *lf) +{ + if (OVS_UNLIKELY(dp_packet_ip_checksum_bad(pkt))) { + return ipf_return_invalid(pkt); + } + + const struct eth_header *l2 = dp_packet_eth(pkt); + const struct ip_header *l3 = dp_packet_l3(pkt); + + if (OVS_UNLIKELY(!l2 || !l3)) { + return ipf_return_invalid(pkt); + } + + const char *tail = dp_packet_tail(pkt); + uint8_t pad = dp_packet_l2_pad_size(pkt); + size_t size = tail - (char *)l3 - pad; + if (OVS_UNLIKELY(size < IP_HEADER_LEN)) { + return ipf_return_invalid(pkt); + } + + if (!(IP_IS_FRAGMENT(l3->ip_frag_off))) { + return false; + } + + uint16_t ip_tot_len = ntohs(l3->ip_tot_len); + if (OVS_UNLIKELY(ip_tot_len != size)) { + return ipf_return_invalid(pkt); + } + + size_t ip_hdr_len = IP_IHL(l3->ip_ihl_ver) * 4; + if (OVS_UNLIKELY(ip_hdr_len < IP_HEADER_LEN)) { + return ipf_return_invalid(pkt); + } + if (OVS_UNLIKELY(size < ip_hdr_len)) { + return ipf_return_invalid(pkt); + } + + if (OVS_UNLIKELY(!dp_packet_ip_checksum_valid(pkt) + && csum(l3, ip_hdr_len) != 0)) { + return ipf_return_invalid(pkt); + } + + uint32_t min_v4_frag_size_; + atomic_read_relaxed(&min_v4_frag_size, &min_v4_frag_size_); + *lf = ipf_is_last_v4_frag(pkt); + if (OVS_UNLIKELY(!*lf && dp_packet_size(pkt) < min_v4_frag_size_)) { + ipf_count(false, IPF_COUNTER_NFRAGS_TOO_SMALL); + return ipf_return_invalid(pkt); + } + + *start_data_byte = ntohs(l3->ip_frag_off & htons(IP_FRAG_OFF_MASK)) * 8; + *end_data_byte = *start_data_byte + ip_tot_len - ip_hdr_len - 1; + *ff = ipf_is_first_v4_frag(pkt); + memset(key, 0, sizeof *key); + key->ip_id = be16_to_be32(l3->ip_id); + key->dl_type = dl_type; + key->src_addr.ipv4 = l3->ip_src; + key->dst_addr.ipv4 = l3->ip_dst; + key->nw_proto = l3->ip_proto; + key->zone = zone; + key->recirc_id = pkt->md.recirc_id; + return true; +} + +static bool +ipf_v6_key_extract(struct dp_packet *pkt, ovs_be16 dl_type, uint16_t zone, + struct ipf_list_key *key, uint16_t *start_data_byte, + uint16_t *end_data_byte, bool *ff, bool *lf) +{ + const struct eth_header *l2 = dp_packet_eth(pkt); + const struct ovs_16aligned_ip6_hdr *l3 = dp_packet_l3(pkt); + const char *l4 = dp_packet_l4(pkt); + + if (OVS_UNLIKELY(!l2 || !l3 || !l4)) { + return ipf_return_invalid(pkt); + } + + const char *tail = dp_packet_tail(pkt); + uint8_t pad = dp_packet_l2_pad_size(pkt); + size_t l3_size = tail - (char *)l3 - pad; + size_t l4_size = tail - (char *)l4 - pad; + size_t l3_hdr_size = sizeof *l3; + + if (OVS_UNLIKELY(l3_size < l3_hdr_size)) { + return ipf_return_invalid(pkt); + } + + uint8_t nw_frag = 0; + uint8_t nw_proto = l3->ip6_nxt; + const void *data = l3 + 1; + size_t datasize = l3_size - l3_hdr_size; + const struct ovs_16aligned_ip6_frag *frag_hdr = NULL; + if (!parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag, + &frag_hdr) || !nw_frag || !frag_hdr) { + return false; + } + + int pl = ntohs(l3->ip6_plen); + if (OVS_UNLIKELY(pl + l3_hdr_size != l3_size)) { + return ipf_return_invalid(pkt); + } + + ovs_be16 ip6f_offlg = frag_hdr->ip6f_offlg; + + if (OVS_UNLIKELY(!ipf_is_v6_frag(ip6f_offlg))) { + return false; + } + + uint32_t min_v6_frag_size_; + atomic_read_relaxed(&min_v6_frag_size, &min_v6_frag_size_); + *lf = ipf_is_last_v6_frag(ip6f_offlg); + + if (OVS_UNLIKELY(!(*lf) && dp_packet_size(pkt) < min_v6_frag_size_)) { + ipf_count(true, IPF_COUNTER_NFRAGS_TOO_SMALL); + return ipf_return_invalid(pkt); + } + + *start_data_byte = ntohs(ip6f_offlg & IP6F_OFF_MASK) + + sizeof (struct ovs_16aligned_ip6_frag); + *end_data_byte = *start_data_byte + l4_size - 1; + *ff = ipf_is_first_v6_frag(ip6f_offlg); + memset(key, 0, sizeof *key); + key->ip_id = get_16aligned_be32(&frag_hdr->ip6f_ident); + key->dl_type = dl_type; + key->src_addr.ipv6 = l3->ip6_src; + /* We are not supporting parsing of the routing header to use as the + * dst address part of the key. */ + key->dst_addr.ipv6 = l3->ip6_dst; + key->nw_proto = 0; /* Not used for key for V6. */ + key->zone = zone; + key->recirc_id = pkt->md.recirc_id; + return true; +} + +static int +ipf_list_key_cmp(const struct ipf_list_key *key1, + const struct ipf_list_key *key2) + OVS_REQUIRES(ipf_lock) +{ + if (!memcmp(&key1->src_addr, &key2->src_addr, sizeof key1->src_addr) && + !memcmp(&key1->dst_addr, &key2->dst_addr, sizeof key1->dst_addr) && + (key1->dl_type == key2->dl_type) && + (key1->ip_id == key2->ip_id) && + (key1->zone == key2->zone) && + (key1->nw_proto == key2->nw_proto) && + (key1->recirc_id == key2->recirc_id)) { + return 0; + } + return 1; +} + +static struct ipf_list * +ipf_list_key_lookup(const struct ipf_list_key *key, + uint32_t hash) + OVS_REQUIRES(ipf_lock) +{ + struct ipf_list *ipf_list; + HMAP_FOR_EACH_WITH_HASH (ipf_list, node, hash, &frag_lists) { + if (!ipf_list_key_cmp(&ipf_list->key, key)) { + return ipf_list; + } + } + return NULL; +} + +static bool +ipf_is_frag_duped(const struct ipf_frag *frag_list, int last_inuse_idx, + size_t start_data_byte, size_t end_data_byte) + OVS_REQUIRES(ipf_lock) +{ + for (int i = 0; i <= last_inuse_idx; i++) { + if (((start_data_byte >= frag_list[i].start_data_byte) && + (start_data_byte <= frag_list[i].end_data_byte)) || + ((end_data_byte >= frag_list[i].start_data_byte) && + (end_data_byte <= frag_list[i].end_data_byte))) { + return true; + } + } + return false; +} + +static bool +ipf_process_frag(struct ipf_list *ipf_list, struct dp_packet *pkt, + uint16_t start_data_byte, uint16_t end_data_byte, + bool ff, bool lf, bool v6) + OVS_REQUIRES(ipf_lock) +{ + bool duped_frag = ipf_is_frag_duped(ipf_list->frag_list, + ipf_list->last_inuse_idx, start_data_byte, end_data_byte); + int last_inuse_idx = ipf_list->last_inuse_idx; + + if (!duped_frag) { + if (last_inuse_idx < ipf_list->size - 1) { + /* In the case of dpdk, it would be unfortunate if we had + * to create a clone fragment outside the dpdk mp due to the + * mempool size being too limited. We will otherwise need to + * recommend not setting the mempool number of buffers too low + * and also clamp the number of fragments. */ + ipf_list->frag_list[last_inuse_idx + 1].pkt = pkt; + ipf_list->frag_list[last_inuse_idx + 1].start_data_byte = + start_data_byte; + ipf_list->frag_list[last_inuse_idx + 1].end_data_byte = + end_data_byte; + ipf_list->last_inuse_idx++; + atomic_count_inc(&nfrag); + ipf_count(v6, IPF_COUNTER_NFRAGS_ACCEPTED); + ipf_list_state_transition(ipf_list, ff, lf, v6); + } else { + OVS_NOT_REACHED(); + } + } else { + ipf_count(v6, IPF_COUNTER_NFRAGS_OVERLAP); + pkt->md.ct_state = CS_INVALID; + return false; + } + return true; +} + +static bool +ipf_handle_frag(struct dp_packet *pkt, ovs_be16 dl_type, uint16_t zone, + long long now, uint32_t hash_basis) + OVS_REQUIRES(ipf_lock) +{ + struct ipf_list_key key; + /* Initialize 4 variables for some versions of GCC. */ + uint16_t start_data_byte = 0; + uint16_t end_data_byte = 0; + bool ff = false; + bool lf = false; + bool v6 = dl_type == htons(ETH_TYPE_IPV6); + bool v4 = dl_type == htons(ETH_TYPE_IP); + + if (v4 && ipf_get_v4_enabled()) { + if (!ipf_v4_key_extract(pkt, dl_type, zone, &key, &start_data_byte, + &end_data_byte, &ff, &lf)) { + return false; + } + } else if (v6 && ipf_get_v6_enabled()) { + if (!ipf_v6_key_extract(pkt, dl_type, zone, &key, &start_data_byte, + &end_data_byte, &ff, &lf)) { + return false; + } + } else { + return false; + } + + unsigned int nfrag_max_; + atomic_read_relaxed(&nfrag_max, &nfrag_max_); + if (atomic_count_get(&nfrag) >= nfrag_max_) { + return false; + } + + uint32_t hash = ipf_list_key_hash(&key, hash_basis); + struct ipf_list *ipf_list = ipf_list_key_lookup(&key, hash); + enum { + IPF_FRAG_LIST_MIN_INCREMENT = 4, + IPF_IPV6_MAX_FRAG_LIST_SIZE = 65535, + }; + + int max_frag_list_size; + if (v6) { + /* Because the calculation with extension headers is variable, + * we don't calculate a hard maximum fragment list size upfront. The + * fragment list size is practically limited by the code, however. */ + max_frag_list_size = IPF_IPV6_MAX_FRAG_LIST_SIZE; + } else { + max_frag_list_size = max_v4_frag_list_size; + } + + if (!ipf_list) { + ipf_list = xzalloc(sizeof *ipf_list); + ipf_list->key = key; + ipf_list->last_inuse_idx = IPF_INVALID_IDX; + ipf_list->last_sent_idx = IPF_INVALID_IDX; + ipf_list->size = + MIN(max_frag_list_size, IPF_FRAG_LIST_MIN_INCREMENT); + ipf_list->frag_list = + xzalloc(ipf_list->size * sizeof *ipf_list->frag_list); + hmap_insert(&frag_lists, &ipf_list->node, hash); + ipf_expiry_list_add(ipf_list, now); + } else if (ipf_list->state == IPF_LIST_STATE_REASS_FAIL) { + /* Bail out as early as possible. */ + return false; + } else if (ipf_list->last_inuse_idx + 1 >= ipf_list->size) { + int increment = MIN(IPF_FRAG_LIST_MIN_INCREMENT, + max_frag_list_size - ipf_list->size); + /* Enforce limit. */ + if (increment > 0) { + ipf_list->frag_list = + xrealloc(ipf_list->frag_list, (ipf_list->size + increment) * + sizeof *ipf_list->frag_list); + ipf_list->size += increment; + } else { + return false; + } + } + + return ipf_process_frag(ipf_list, pkt, start_data_byte, end_data_byte, ff, + lf, v6); +} + +static void +ipf_extract_frags_from_batch(struct dp_packet_batch *pb, ovs_be16 dl_type, + uint16_t zone, long long now, uint32_t hash_basis) +{ + const size_t pb_cnt = dp_packet_batch_size(pb); + int pb_idx; /* Index in a packet batch. */ + struct dp_packet *pkt; + + DP_PACKET_BATCH_REFILL_FOR_EACH (pb_idx, pb_cnt, pkt, pb) { + ipf_lock_lock(&ipf_lock); + + if (!ipf_handle_frag(pkt, dl_type, zone, now, hash_basis)) { + dp_packet_batch_refill(pb, pkt, pb_idx); + } + + ipf_lock_unlock(&ipf_lock); + } +} + +/* In case of DPDK, a memory source check is done, as DPDK memory pool + * management has trouble dealing with multiple source types. The + * check_source paramater is used to indicate when this check is needed. */ +static bool +ipf_dp_packet_batch_add(struct dp_packet_batch *pb , struct dp_packet *pkt, + bool check_source OVS_UNUSED) + OVS_REQUIRES(ipf_lock) +{ +#ifdef DPDK_NETDEV + if ((pb->count >= NETDEV_MAX_BURST) || + /* DPDK cannot handle multiple sources in a batch. */ + (check_source && pb->count && pb->packets[0]->source != pkt->source)) { +#else + if (pb->count >= NETDEV_MAX_BURST) { +#endif + return false; + } + + dp_packet_batch_add(pb, pkt); + return true; +} + +/* This would be used in a rare case where a list cannot be sent. The only + * reason known right now is a mempool source check, which exists due to DPDK + * support, where packets are no longer being received on any port with a + * source matching the fragment. + * Returns true if the list was purged. */ +static bool +ipf_purge_list_check(struct ipf_list *ipf_list, long long now) + OVS_REQUIRES(ipf_lock) +{ + enum { + /* 10 minutes. */ + IPF_FRAG_LIST_TIMEOUT_PURGE = 600000, + }; + + if (now < ipf_list->expiration + IPF_FRAG_LIST_TIMEOUT_PURGE) { + return false; + } + + struct dp_packet *pkt; + while (ipf_list->last_sent_idx < ipf_list->last_inuse_idx) { + pkt = ipf_list->frag_list[ipf_list->last_sent_idx + 1].pkt; + dp_packet_delete(pkt); + atomic_count_dec(&nfrag); + ipf_list->last_sent_idx++; + } + + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + VLOG_WARN_RL(&rl, "Fragments dropped due to stuck fragment list purge."); + COVERAGE_INC(ipf_stuck_frag_list_purged); + return true; +} + +static bool +ipf_send_frags_in_list(struct ipf_list *ipf_list, struct dp_packet_batch *pb, + enum ipf_list_type list_type, bool v6, long long now) + OVS_REQUIRES(ipf_lock) +{ + if (ipf_purge_list_check(ipf_list, now)) { + return true; + } + + struct dp_packet *pkt; + while (ipf_list->last_sent_idx < ipf_list->last_inuse_idx) { + pkt = ipf_list->frag_list[ipf_list->last_sent_idx + 1].pkt; + if (ipf_dp_packet_batch_add(pb, pkt, true)) { + + ipf_list->last_sent_idx++; + atomic_count_dec(&nfrag); + + if (list_type == IPF_FRAG_COMPLETED_LIST) { + ipf_count(v6, IPF_COUNTER_NFRAGS_COMPL_SENT); + } else { + ipf_count(v6, IPF_COUNTER_NFRAGS_EXPD_SENT); + pkt->md.ct_state = CS_INVALID; + } + + if (ipf_list->last_sent_idx == ipf_list->last_inuse_idx) { + return true; + } + } else { + return false; + } + } + OVS_NOT_REACHED(); +} + +static void +ipf_send_completed_frags(struct dp_packet_batch *pb, long long now, bool v6) +{ + if (ovs_list_is_empty(&frag_complete_list)) { + return; + } + + ipf_lock_lock(&ipf_lock); + struct ipf_list *ipf_list, *next; + + LIST_FOR_EACH_SAFE (ipf_list, next, list_node, &frag_complete_list) { + if (ipf_send_frags_in_list(ipf_list, pb, IPF_FRAG_COMPLETED_LIST, + v6, now)) { + ipf_completed_list_clean(ipf_list); + } else { + break; + } + } + ipf_lock_unlock(&ipf_lock); +} + +static void +ipf_send_expired_frags(struct dp_packet_batch *pb, long long now, bool v6) +{ + enum { + /* Very conservative, due to DOS probability. */ + IPF_FRAG_LIST_MAX_EXPIRED = 1, + }; + + + if (ovs_list_is_empty(&frag_exp_list)) { + return; + } + + ipf_lock_lock(&ipf_lock); + struct ipf_list *ipf_list, *next; + size_t lists_removed = 0; + + LIST_FOR_EACH_SAFE (ipf_list, next, list_node, &frag_exp_list) { + if (!(now > ipf_list->expiration) || + lists_removed >= IPF_FRAG_LIST_MAX_EXPIRED) { + break; + } + + if (ipf_send_frags_in_list(ipf_list, pb, IPF_FRAG_EXPIRY_LIST, v6, + now)) { + ipf_expiry_list_clean(ipf_list); + lists_removed++; + } else { + break; + } + } + ipf_lock_unlock(&ipf_lock); +} + +static void +ipf_execute_reass_pkts(struct dp_packet_batch *pb) +{ + if (ovs_list_is_empty(&reassembled_pkt_list)) { + return; + } + + ipf_lock_lock(&ipf_lock); + struct reassembled_pkt *rp, *next; + + LIST_FOR_EACH_SAFE (rp, next, rp_list_node, &reassembled_pkt_list) { + if (!rp->list->reass_execute_ctx && + ipf_dp_packet_batch_add(pb, rp->pkt, false)) { + rp->list->reass_execute_ctx = rp->pkt; + } + } + ipf_lock_unlock(&ipf_lock); +} + +static void +ipf_post_execute_reass_pkts(struct dp_packet_batch *pb, bool v6) +{ + if (ovs_list_is_empty(&reassembled_pkt_list)) { + return; + } + + ipf_lock_lock(&ipf_lock); + struct reassembled_pkt *rp, *next; + + LIST_FOR_EACH_SAFE (rp, next, rp_list_node, &reassembled_pkt_list) { + const size_t pb_cnt = dp_packet_batch_size(pb); + int pb_idx; + struct dp_packet *pkt; + /* Inner batch loop is constant time since batch size is <= + * NETDEV_MAX_BURST. */ + DP_PACKET_BATCH_REFILL_FOR_EACH (pb_idx, pb_cnt, pkt, pb) { + if (pkt == rp->list->reass_execute_ctx) { + for (int i = 0; i <= rp->list->last_inuse_idx; i++) { + rp->list->frag_list[i].pkt->md.ct_label = pkt->md.ct_label; + rp->list->frag_list[i].pkt->md.ct_mark = pkt->md.ct_mark; + rp->list->frag_list[i].pkt->md.ct_state = pkt->md.ct_state; + rp->list->frag_list[i].pkt->md.ct_zone = pkt->md.ct_zone; + rp->list->frag_list[i].pkt->md.ct_orig_tuple_ipv6 = + pkt->md.ct_orig_tuple_ipv6; + if (pkt->md.ct_orig_tuple_ipv6) { + rp->list->frag_list[i].pkt->md.ct_orig_tuple.ipv6 = + pkt->md.ct_orig_tuple.ipv6; + } else { + rp->list->frag_list[i].pkt->md.ct_orig_tuple.ipv4 = + pkt->md.ct_orig_tuple.ipv4; + } + } + + const char *tail_frag = + dp_packet_tail(rp->list->frag_list[0].pkt); + uint8_t pad_frag = + dp_packet_l2_pad_size(rp->list->frag_list[0].pkt); + + void *l4_frag = dp_packet_l4(rp->list->frag_list[0].pkt); + void *l4_reass = dp_packet_l4(pkt); + memcpy(l4_frag, l4_reass, + tail_frag - (char *) l4_frag - pad_frag); + + if (v6) { + struct ovs_16aligned_ip6_hdr *l3_frag = + dp_packet_l3(rp->list->frag_list[0].pkt); + struct ovs_16aligned_ip6_hdr *l3_reass = + dp_packet_l3(pkt); + l3_frag->ip6_src = l3_reass->ip6_src; + l3_frag->ip6_dst = l3_reass->ip6_dst; + } else { + struct ip_header *l3_frag = + dp_packet_l3(rp->list->frag_list[0].pkt); + struct ip_header *l3_reass = dp_packet_l3(pkt); + ovs_be32 reass_ip = get_16aligned_be32(&l3_reass->ip_src); + ovs_be32 frag_ip = get_16aligned_be32(&l3_frag->ip_src); + l3_frag->ip_csum = recalc_csum32(l3_frag->ip_csum, + frag_ip, reass_ip); + l3_frag->ip_src = l3_reass->ip_src; + + reass_ip = get_16aligned_be32(&l3_reass->ip_dst); + frag_ip = get_16aligned_be32(&l3_frag->ip_dst); + l3_frag->ip_csum = recalc_csum32(l3_frag->ip_csum, + frag_ip, reass_ip); + l3_frag->ip_dst = l3_reass->ip_dst; + } + + ipf_completed_list_add(rp->list); + ipf_reassembled_list_remove(rp); + dp_packet_delete(rp->pkt); + free(rp); + } else { + dp_packet_batch_refill(pb, pkt, pb_idx); + } + } + } + ipf_lock_unlock(&ipf_lock); +} + +/* Extracts any fragments from the batch and reassembles them when a + * complete packet is received. Completed packets are attempted to + * be added to the batch to be sent thru. conntrack. */ +void +ipf_preprocess_conntrack(struct dp_packet_batch *pb, long long now, + ovs_be16 dl_type, uint16_t zone, uint32_t hash_basis) +{ + if (ipf_get_enabled()) { + ipf_extract_frags_from_batch(pb, dl_type, zone, now, hash_basis); + } + + if (ipf_get_enabled() || atomic_count_get(&nfrag)) { + ipf_execute_reass_pkts(pb); + } +} + +/* Updates fragments based on the processing of the reassembled packet sent + * thru. conntrack and adds these fragments to any batches seen. Expired + * fragments are marked as invalid and also added to the batches seen + * with low priority. Reassembled packets are freed. */ +void +ipf_postprocess_conntrack(struct dp_packet_batch *pb, long long now, + ovs_be16 dl_type) +{ + if (ipf_get_enabled() || atomic_count_get(&nfrag)) { + bool v6 = dl_type == htons(ETH_TYPE_IPV6); + ipf_post_execute_reass_pkts(pb, v6); + ipf_send_completed_frags(pb, now, v6); + ipf_send_expired_frags(pb, now, v6); + } +} + +void +ipf_init(void) +{ + ipf_lock_init(&ipf_lock); + ipf_lock_lock(&ipf_lock); + hmap_init(&frag_lists); + ovs_list_init(&frag_exp_list); + ovs_list_init(&frag_complete_list); + ovs_list_init(&reassembled_pkt_list); + atomic_init(&min_v4_frag_size, IPF_V4_FRAG_SIZE_MIN_DEF); + atomic_init(&min_v6_frag_size, IPF_V6_FRAG_SIZE_MIN_DEF); + max_v4_frag_list_size = DIV_ROUND_UP( + IPV4_PACKET_MAX_SIZE - IPV4_PACKET_MAX_HDR_SIZE, + min_v4_frag_size - IPV4_PACKET_MAX_HDR_SIZE); + ipf_lock_unlock(&ipf_lock); + atomic_count_init(&nfrag, 0); + atomic_count_init(&n4frag_accepted, 0); + atomic_count_init(&n4frag_completed_sent, 0); + atomic_count_init(&n4frag_expired_sent, 0); + atomic_count_init(&n4frag_too_small, 0); + atomic_count_init(&n4frag_overlap, 0); + atomic_count_init(&n6frag_accepted, 0); + atomic_count_init(&n6frag_completed_sent, 0); + atomic_count_init(&n6frag_expired_sent, 0); + atomic_count_init(&n6frag_too_small, 0); + atomic_count_init(&n6frag_overlap, 0); + atomic_init(&nfrag_max, IPF_MAX_FRAGS_DEFAULT); + atomic_init(&ifp_v4_enabled, true); + atomic_init(&ifp_v6_enabled, true); +} + +void +ipf_destroy(void) +{ + ipf_lock_lock(&ipf_lock); + + struct ipf_list *ipf_list; + HMAP_FOR_EACH_POP (ipf_list, node, &frag_lists) { + struct dp_packet *pkt; + while (ipf_list->last_sent_idx < ipf_list->last_inuse_idx) { + pkt = ipf_list->frag_list[ipf_list->last_sent_idx + 1].pkt; + dp_packet_delete(pkt); + atomic_count_dec(&nfrag); + ipf_list->last_sent_idx++; + } + free(ipf_list->frag_list); + free(ipf_list); + } + + if (atomic_count_get(&nfrag)) { + VLOG_WARN("ipf destroy with non-zero fragment count. "); + } + + struct reassembled_pkt * rp; + LIST_FOR_EACH_POP (rp, rp_list_node, &reassembled_pkt_list) { + dp_packet_delete(rp->pkt); + free(rp); + } + + hmap_destroy(&frag_lists); + ovs_list_poison(&frag_exp_list); + ovs_list_poison(&frag_complete_list); + ovs_list_poison(&reassembled_pkt_list); + ipf_lock_unlock(&ipf_lock); + ipf_lock_destroy(&ipf_lock); +} diff --git a/lib/ipf.h b/lib/ipf.h new file mode 100644 index 0000000..212d1b3 --- /dev/null +++ b/lib/ipf.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IPF_H +#define IPF_H 1 + +#include "dp-packet.h" +#include "openvswitch/types.h" + +struct ipf_status { + bool ifp_v4_enabled; + unsigned int min_v4_frag_size; + unsigned int nfrag_max; + unsigned int nfrag; + unsigned int n4frag_accepted; + unsigned int n4frag_completed_sent; + unsigned int n4frag_expired_sent; + unsigned int n4frag_too_small; + unsigned int n4frag_overlap; + bool ifp_v6_enabled; + unsigned int min_v6_frag_size; + unsigned int n6frag_accepted; + unsigned int n6frag_completed_sent; + unsigned int n6frag_expired_sent; + unsigned int n6frag_too_small; + unsigned int n6frag_overlap; +}; + +/* Collects and reassembles fragments which are to be sent through + * conntrack, if fragment processing is enabled or fragments are + * in flight. */ +void ipf_preprocess_conntrack(struct dp_packet_batch *pb, long long now, + ovs_be16 dl_type, uint16_t zone, + uint32_t hash_basis); + +/* Updates the state of fragments associated with reassembled packets and + * sends out fragments that are either associated with completed + * packets or expired, if fragment processing is enabled or fragments are + * in flight. */ +void ipf_postprocess_conntrack(struct dp_packet_batch *pb, long long now, + ovs_be16 dl_type); + +void ipf_init(void); + +void ipf_destroy(void); + +#endif /* ipf.h */ diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at index 07de0db..3ea5b87 100644 --- a/tests/system-kmod-macros.at +++ b/tests/system-kmod-macros.at @@ -77,12 +77,6 @@ m4_define([CHECK_CONNTRACK], # m4_define([CHECK_CONNTRACK_ALG]) -# CHECK_CONNTRACK_FRAG() -# -# Perform requirements checks for running conntrack fragmentations tests. -# The kernel always supports fragmentation, so no check is needed. -m4_define([CHECK_CONNTRACK_FRAG]) - # CHECK_CONNTRACK_LOCAL_STACK() # # Perform requirements checks for running conntrack tests with local stack. @@ -91,6 +85,10 @@ m4_define([CHECK_CONNTRACK_FRAG]) # needed. m4_define([CHECK_CONNTRACK_LOCAL_STACK]) +# CHECK_CONNTRACK_SMALL_FRAG() +# +m4_define([CHECK_CONNTRACK_SMALL_FRAG]) + # CHECK_CONNTRACK_FRAG_OVERLAP() # # The kernel does not support overlapping fragments checking. diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 75648d4..e17d39c 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -1905,7 +1905,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -1939,7 +1938,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation expiry]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -1970,7 +1968,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation + vlan]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2006,7 +2003,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation + cvlan]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0]) OVS_CHECK_8021AD() @@ -2081,7 +2077,7 @@ AT_CLEANUP dnl Uses same first fragment as above 'incomplete reassembled packet' test. AT_SETUP([conntrack - IPv4 fragmentation with fragments specified]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2105,7 +2101,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2129,7 +2125,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation overlapping fragments by 1 octet]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_OVERLAP() OVS_TRAFFIC_VSWITCHD_START() @@ -2153,7 +2149,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation overlapping fragments by 1 octet out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_OVERLAP() OVS_TRAFFIC_VSWITCHD_START() @@ -2177,7 +2173,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2217,7 +2212,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation expiry]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2258,7 +2252,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation + vlan]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2301,7 +2294,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation + cvlan]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() OVS_TRAFFIC_VSWITCHD_START([set Open_vSwitch . other_config:vlan-limit=0]) OVS_CHECK_8021AD() @@ -2376,7 +2368,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation with fragments specified]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2400,7 +2392,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2424,7 +2416,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() @@ -2450,7 +2442,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers + out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() @@ -2476,7 +2468,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers 2]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() @@ -2502,7 +2494,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers 2 + out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() +CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() @@ -2529,7 +2521,6 @@ AT_CLEANUP AT_SETUP([conntrack - Fragmentation over vxlan]) OVS_CHECK_VXLAN() CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() CHECK_CONNTRACK_LOCAL_STACK() OVS_TRAFFIC_VSWITCHD_START() @@ -2582,7 +2573,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 Fragmentation over vxlan]) OVS_CHECK_VXLAN() CHECK_CONNTRACK() -CHECK_CONNTRACK_FRAG() CHECK_CONNTRACK_LOCAL_STACK() OVS_TRAFFIC_VSWITCHD_START() diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at index 11eac8f..40b7567 100644 --- a/tests/system-userspace-macros.at +++ b/tests/system-userspace-macros.at @@ -73,15 +73,6 @@ m4_define([CHECK_CONNTRACK], # m4_define([CHECK_CONNTRACK_ALG]) -# CHECK_CONNTRACK_FRAG() -# -# Perform requirements checks for running conntrack fragmentations tests. -# The userspace doesn't support fragmentation yet, so skip the tests. -m4_define([CHECK_CONNTRACK_FRAG], -[ - AT_SKIP_IF([:]) -]) - # CHECK_CONNTRACK_LOCAL_STACK() # # Perform requirements checks for running conntrack tests with local stack. @@ -93,21 +84,22 @@ m4_define([CHECK_CONNTRACK_LOCAL_STACK], AT_SKIP_IF([:]) ]) -# CHECK_CONNTRACK_FRAG_OVERLAP() +# CHECK_CONNTRACK_SMALL_FRAG() # -# The userspace datapath does not support fragments yet. -m4_define([CHECK_CONNTRACK_FRAG_OVERLAP], +m4_define([CHECK_CONNTRACK_SMALL_FRAG], [ AT_SKIP_IF([:]) ]) +# CHECK_CONNTRACK_FRAG_OVERLAP() +# +# The userspace datapath supports fragment overlap checking. +m4_define([CHECK_CONNTRACK_FRAG_OVERLAP]) + # CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() # -# The userspace datapath does not support fragments yet. -m4_define([CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN], -[ - AT_SKIP_IF([:]) -]) +# The userspace datapath supports fragments with multiple extension headers. +m4_define([CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN]) # CHECK_CONNTRACK_NAT() # From patchwork Mon Jul 9 16:32:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941438 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="fRzi89qL"; 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 41PWF24CV5z9rxs for ; Tue, 10 Jul 2018 02:35:20 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id E998FDB4; Mon, 9 Jul 2018 16:32:48 +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 F2D38D99 for ; Mon, 9 Jul 2018 16:32:47 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f195.google.com (mail-pf0-f195.google.com [209.85.192.195]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 3BF97791 for ; Mon, 9 Jul 2018 16:32:47 +0000 (UTC) Received: by mail-pf0-f195.google.com with SMTP id u16-v6so14038546pfh.3 for ; Mon, 09 Jul 2018 09:32:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=KavJxRLFHFETtbqWgVdVY0TAjjxAa0ClsRWh2Ajm5rk=; b=fRzi89qLkZFt8DdyFSpio8vwEuun6iejMcYng3YG4hHDf9dOE8KrT04lObOd9g3LuB xlKbU7EX0HQ4HLjtqTUNeSlF8wcv9pEtS1toI330GMMEsFz9/hnkPZuQZzVbdymDQQmE NZW/s3jl3z1Lwf9EnEEO/c9f/JzwOWLYhGZNTUzws5a27wQRC4N7ZzxdIkItNa+LrGyV L6jxUOONBBdCURNnxCI+A0xSJd0R1TB+kmiraNHp8qX7YuxFHMN1FnEDpUow2rsxfXTs OSqbvZnxZjvHk54ml3uXrejt5wB+YmDxi1C/GuidMTgPIoVMFG5dprmYwBUjLa8c8cGW IckQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=KavJxRLFHFETtbqWgVdVY0TAjjxAa0ClsRWh2Ajm5rk=; b=HkME8mrhwxg/Hx89zGL1zlgbySchzCvT6wUM8WQN7TwkNbmNNRMnxvvoaLOHkz2/+U ZXlLUCLALkdo35VuURHM3GCaYcAk9Iv0NgYrWRv9ARpM+orrwTMtgV0QI3R0q4f7vFIU 0l0rDLCi+dV3CbZET8h6pYQ8KV1a1bvqYxO4wdRLrXJiLYn8VHZcn1oXIsoyiWR8t6/2 MmhnKSnUzG8TCijG3A1nWJ8nIGf05CV8tXtP+2bHJqz9V0GlOArtWn1VDdc8GOTw8TIa otQ5XAdQr3LfCDJjx4KKCsiOcgO59KCW131LJn+qmH/LxacwC/QoVMdbA6d8jIDWHP7Q W0Gg== X-Gm-Message-State: APt69E11fHxRn4IjFHh6pDBYylcq/nSIZ5nEx8Hb6WN0WPOEjgmxAQ6h Nst/1r+kdo3odDI9tDPFriw2Mw== X-Google-Smtp-Source: AAOMgpfwaCEkUcxHiGTYibvNWJfr3QIf4uUzHDLAJH/m6WS/P/H1m/5WnEOF+2Eg6O6GMsGRBOH0rQ== X-Received: by 2002:a62:cac5:: with SMTP id y66-v6mr1695990pfk.187.1531153966743; Mon, 09 Jul 2018 09:32:46 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:45 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:22 -0700 Message-Id: <1531153945-121300-7-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 6/9] ipf: Add command to disable fragmentation handling. 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 Commands are added to disable and also enable fragmentation handling for conntrack. Signed-off-by: Darrell Ball --- NEWS | 4 ++++ lib/ct-dpif.c | 8 ++++++++ lib/ct-dpif.h | 1 + lib/dpctl.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/dpctl.man | 15 +++++++++++++++ lib/dpif-netdev.c | 9 +++++++++ lib/dpif-netlink.c | 1 + lib/dpif-provider.h | 4 +++- lib/ipf.c | 7 +++++++ lib/ipf.h | 2 ++ 10 files changed, 100 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index e0418a5..96fa05b 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,10 @@ Post-v2.9.0 use --names or --no-names to override. See ovs-ofctl(8) for details. - Userspace datapath: * Add v4/v6 fragmentation support for conntrack. + * New "ovs-appctl dpctl/ipf-set-enabled" command for userspace datapath + conntrack fragmentation support. + * New "ovs-appctl dpctl/ipf-set-disabled" command for userspace datapath + conntrack fragmentation support. - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". - OpenFlow: * OFPT_ROLE_STATUS is now available in OpenFlow 1.3. diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index 5fa3a97..b1f29dc 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -164,6 +164,14 @@ ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns) : EOPNOTSUPP); } +int +ct_dpif_ipf_set_enabled(struct dpif *dpif, bool v6, bool enable) +{ + return (dpif->dpif_class->ipf_set_enabled + ? dpif->dpif_class->ipf_set_enabled(dpif, v6, enable) + : EOPNOTSUPP); +} + void ct_dpif_entry_uninit(struct ct_dpif_entry *entry) { diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index 09e7698..bd6234d 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -200,6 +200,7 @@ int ct_dpif_flush(struct dpif *, const uint16_t *zone, int ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns); int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns); int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns); +int ct_dpif_ipf_set_enabled(struct dpif *, bool v6, bool enable); 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 4f1e443..ad7ca8d 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -35,6 +35,7 @@ #include "dpif.h" #include "openvswitch/dynamic-string.h" #include "flow.h" +#include "ipf.h" #include "openvswitch/match.h" #include "netdev.h" #include "netdev-dpdk.h" @@ -1680,6 +1681,51 @@ dpctl_ct_get_nconns(int argc, const char *argv[], return error; } +static int +ipf_set_enabled__(int argc, const char *argv[], struct dpctl_params *dpctl_p, + bool enabled) +{ + struct dpif *dpif; + int error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif); + if (!error) { + char v4_or_v6[3] = {0}; + if (ovs_scan(argv[argc - 2], "%2s", v4_or_v6) && + (!strncmp(v4_or_v6, "v4", 2) || !strncmp(v4_or_v6, "v6", 2))) { + error = ct_dpif_ipf_set_enabled( + dpif, !strncmp(v4_or_v6, "v6", 2), enabled); + if (!error) { + dpctl_print(dpctl_p, + "%s fragmentation reassembly successful", + enabled ? "enabling" : "disabling"); + } else { + dpctl_error(dpctl_p, error, + "%s fragmentation reassembly failed", + enabled ? "enabling" : "disabling"); + } + } else { + error = EINVAL; + dpctl_error(dpctl_p, error, + "parameter missing: 'v4' for ipv4 or 'v6' for ipv6"); + } + dpif_close(dpif); + } + return error; +} + +static int +dpctl_ipf_set_enabled(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + return ipf_set_enabled__(argc, argv, dpctl_p, true); +} + +static int +dpctl_ipf_set_disabled(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + return ipf_set_enabled__(argc, argv, dpctl_p, false); +} + /* Undocumented commands for unit testing. */ static int @@ -1979,6 +2025,10 @@ static const struct dpctl_command all_commands[] = { { "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns, DP_RW }, { "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, DP_RO }, { "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns, DP_RO }, + { "ipf-set-enabled", "[dp] v4 | v6", 1, 2, + dpctl_ipf_set_enabled, DP_RW }, + { "ipf-set-disabled", "[dp] v4 | v6", 1, 2, + dpctl_ipf_set_disabled, DP_RW }, { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, diff --git a/lib/dpctl.man b/lib/dpctl.man index 5d987e6..43d161a 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -272,3 +272,18 @@ Only supported for userspace datapath. \*(DX\fBct\-get\-nconns\fR [\fIdp\fR] Prints the current number of connection tracker entries on \fIdp\fR. Only supported for userspace datapath. +. +.TP +\*(DX\fBipf\-set\-enabled\fR [\fIdp\fR] \fBv4\fR | \fBv6\fR +Enables fragmentation handling for the userspace datapath connection +tracker. Either \fBv4\fR or \fBv6\fR must be specified. When fragmentation +handling is enabled, the rules for handling fragments before entering +conntrack should not differentiate between first and other fragments. If +there is a need to differentiate between first and other fragments, do it +after conntrack. Both v4 and v6 are enabled by default. +. +.TP +\*(DX\fBipf\-set\-disabled\fR [\fIdp\fR] \fBv4\fR | \fBv6\fR +Disables fragmentation handling for the userspace datapath connection +tracker. Either \fBv4\fR or \fBv6\fR must be specified. Both v4 and v6 are +enabled by default. diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 8b3556d..ddab09e 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -47,6 +47,7 @@ #include "flow.h" #include "hmapx.h" #include "id-pool.h" +#include "ipf.h" #include "latch.h" #include "netdev.h" #include "netdev-provider.h" @@ -6531,6 +6532,13 @@ dpif_netdev_ct_get_nconns(struct dpif *dpif, uint32_t *nconns) return conntrack_get_nconns(&dp->conntrack, nconns); } +static int +dpif_netdev_ipf_set_enabled(struct dpif *dpif OVS_UNUSED, bool v6, + bool enable) +{ + return ipf_set_enabled(v6, enable); +} + const struct dpif_class dpif_netdev_class = { "netdev", dpif_netdev_init, @@ -6579,6 +6587,7 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_ct_set_maxconns, dpif_netdev_ct_get_maxconns, dpif_netdev_ct_get_nconns, + dpif_netdev_ipf_set_enabled, dpif_netdev_meter_get_features, dpif_netdev_meter_set, dpif_netdev_meter_get, diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index aa9bbd9..e1331e4 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -3006,6 +3006,7 @@ const struct dpif_class dpif_netlink_class = { NULL, /* ct_set_maxconns */ NULL, /* ct_get_maxconns */ NULL, /* ct_get_nconns */ + NULL, /* ipf_set_enabled */ dpif_netlink_meter_get_features, dpif_netlink_meter_set, dpif_netlink_meter_get, diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 62b3598..db65227 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -444,8 +444,10 @@ struct dpif_class { /* Get number of connections tracked. */ int (*ct_get_nconns)(struct dpif *, uint32_t *nconns); - /* Meters */ + /* IP Fragmentation. */ + int (*ipf_set_enabled)(struct dpif *, bool v6, bool enabled); + /* Meters */ /* Queries 'dpif' for supported meter features. * NULL pointer means no meter features are supported. */ void (*meter_get_features)(const struct dpif *, diff --git a/lib/ipf.c b/lib/ipf.c index 2c26e1f..dfb51e4 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -1264,3 +1264,10 @@ ipf_destroy(void) ipf_lock_unlock(&ipf_lock); ipf_lock_destroy(&ipf_lock); } + +int +ipf_set_enabled(bool v6, bool enable) +{ + atomic_store_relaxed(v6 ? &ifp_v6_enabled : &ifp_v4_enabled, enable); + return 0; +} diff --git a/lib/ipf.h b/lib/ipf.h index 212d1b3..da47dcb 100644 --- a/lib/ipf.h +++ b/lib/ipf.h @@ -57,4 +57,6 @@ void ipf_init(void); void ipf_destroy(void); +int ipf_set_enabled(bool v6, bool enable); + #endif /* ipf.h */ From patchwork Mon Jul 9 16:32:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941435 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="OsfW5TDp"; 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 41PWF24clmz9s1R for ; Tue, 10 Jul 2018 02:36:35 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 98A14E18; Mon, 9 Jul 2018 16:32:52 +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 87635DA8 for ; Mon, 9 Jul 2018 16:32:50 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg1-f196.google.com (mail-pg1-f196.google.com [209.85.215.196]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 0F27D78D for ; Mon, 9 Jul 2018 16:32:48 +0000 (UTC) Received: by mail-pg1-f196.google.com with SMTP id y5-v6so1365190pgv.1 for ; Mon, 09 Jul 2018 09:32:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=FdH0BkTZiedYTwDi38nywGxVYXw89PUWkIA6qCvBkVw=; b=OsfW5TDpv/gEDtksmQvF11wHDPDg3Q3ib+lqugat1yRQAZIFazuGPE8fx0PL7x8WGt wEFkw2e4+OtKqvXtOQXkxBHjb0D+xmrz3/Idpv9Qyt6MkLOyOZ8ouMosKl4KClUKa8zy z771iEZsHsi6uS5FzBh327M5bVu6SsQ9vL+7yye5tVZzCJJQKzslgJ4qQKfDtvLeL6KN mxbCrK0bBLyxEKwcXK1Hs3LlEWBpvIRyFOG/iuwFSzKNSWAMiZog26UazDXuT+slSXlf /8xacWJ976fE+XF4j70rJtTUDlntPn6mz+EOpr6MXtGIP7zyaQILqWsb1+xRz8+z0/bB M1Sw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=FdH0BkTZiedYTwDi38nywGxVYXw89PUWkIA6qCvBkVw=; b=EVC0/xnJTyIWGrPsx2qg3/3xpHgE4ygrvL0miimxmAtviMAygVkhSr9w6+Y83uUQ0H U13NL9K2e6SZBj/MGzrWRtLNyU+WZQSPrGSxldNbKIZa9NODWQ8G9qF2Y2kvBtl52xwW BJZZSDVEl8C5obMUez0NpX1ftUnjodlUi6cidHn3P+Ut7RLDd4E6ylnb5kboGzkTTHj3 CVA2vjohRZkHrWfWk/Zr1I/pr2kTtI5SMRqswRi71vXfXjtMpKA5r84in8AMZmQRl0L9 8wOtnv6JdP1Pqn9fsMfZmGx+B8hs4C32k/oPZHq8JSsgdasbxoC/d+0bmMlsVnGTHdXx qOBg== X-Gm-Message-State: APt69E2V4T8rWdlqWpE29lpyND+W6zDlC5EXf1qSpS5KDnUbctSfuPmB WVuZMjiuxNFbB7bPsc0mJfGqDQ== X-Google-Smtp-Source: AAOMgpcWjYzJPj4cwCNzhWKUpFflMWw4hokxhhR3dARiQG6VXsZkGJ+fsgdiTG7CzPJUHegb5XnLnQ== X-Received: by 2002:a62:3b03:: with SMTP id i3-v6mr21974181pfa.197.1531153968379; Mon, 09 Jul 2018 09:32:48 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:47 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:23 -0700 Message-Id: <1531153945-121300-8-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 7/9] ipf: Add set minimum fragment size command. 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 A new command "ovs-appctl dpctl/ipf-set-min-frag" is added for userspace datapath conntrack fragmentation support. Signed-off-by: Darrell Ball --- NEWS | 2 ++ lib/ct-dpif.c | 8 ++++++++ lib/ct-dpif.h | 1 + lib/dpctl.c | 40 ++++++++++++++++++++++++++++++++++++++++ lib/dpctl.man | 9 +++++++++ lib/dpif-netdev.c | 8 ++++++++ lib/dpif-netlink.c | 1 + lib/dpif-provider.h | 2 ++ lib/ipf.c | 23 +++++++++++++++++++++++ lib/ipf.h | 2 ++ tests/system-kmod-macros.at | 8 ++++++++ tests/system-traffic.at | 34 ++++++++++++++++++++++++---------- tests/system-userspace-macros.at | 13 +++++++++++++ 13 files changed, 141 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index 96fa05b..9ab9970 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,8 @@ Post-v2.9.0 conntrack fragmentation support. * New "ovs-appctl dpctl/ipf-set-disabled" command for userspace datapath conntrack fragmentation support. + * New "ovs-appctl dpctl/ipf-set-min-frag" command for userspace + datapath conntrack fragmentation support. - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". - OpenFlow: * OFPT_ROLE_STATUS is now available in OpenFlow 1.3. diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index b1f29dc..d5596af 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -172,6 +172,14 @@ ct_dpif_ipf_set_enabled(struct dpif *dpif, bool v6, bool enable) : EOPNOTSUPP); } +int +ct_dpif_ipf_set_min_frag(struct dpif *dpif, bool v6, uint32_t min_frag) +{ + return (dpif->dpif_class->ipf_set_min_frag + ? dpif->dpif_class->ipf_set_min_frag(dpif, v6, min_frag) + : EOPNOTSUPP); +} + void ct_dpif_entry_uninit(struct ct_dpif_entry *entry) { diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index bd6234d..f8a3192 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -201,6 +201,7 @@ int ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns); int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns); int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns); int ct_dpif_ipf_set_enabled(struct dpif *, bool v6, bool enable); +int ct_dpif_ipf_set_min_frag(struct dpif *, bool, uint32_t); 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 ad7ca8d..e74d713 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -1726,6 +1726,44 @@ dpctl_ipf_set_disabled(int argc, const char *argv[], return ipf_set_enabled__(argc, argv, dpctl_p, false); } +static int +dpctl_ipf_set_min_frag(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + struct dpif *dpif; + int error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif); + if (!error) { + char v4_or_v6[3] = {0}; + if (ovs_scan(argv[argc - 2], "%2s", v4_or_v6) && + (!strncmp(v4_or_v6, "v4", 2) || !strncmp(v4_or_v6, "v6", 2))) { + uint32_t min_fragment; + if (ovs_scan(argv[argc - 1], "%"SCNu32, &min_fragment)) { + error = ct_dpif_ipf_set_min_frag( + dpif, !strncmp(v4_or_v6, "v6", 2), min_fragment); + if (!error) { + dpctl_print(dpctl_p, + "setting minimum fragment size successful"); + } else { + dpctl_error(dpctl_p, error, + "requested minimum fragment size too small;" + " see documentation"); + } + } else { + error = EINVAL; + dpctl_error(dpctl_p, error, + "parameter missing for minimum fragment size"); + } + } else { + error = EINVAL; + dpctl_error(dpctl_p, error, + "parameter missing: v4 for ipv4 or v6 for ipv6"); + } + dpif_close(dpif); + } + + return error; +} + /* Undocumented commands for unit testing. */ static int @@ -2029,6 +2067,8 @@ static const struct dpctl_command all_commands[] = { dpctl_ipf_set_enabled, DP_RW }, { "ipf-set-disabled", "[dp] v4 | v6", 1, 2, dpctl_ipf_set_disabled, DP_RW }, + { "ipf-set-min-frag", "[dp] v4 | v6 minfragment", 2, 3, + dpctl_ipf_set_min_frag, DP_RW }, { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, diff --git a/lib/dpctl.man b/lib/dpctl.man index 43d161a..900900d 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -287,3 +287,12 @@ after conntrack. Both v4 and v6 are enabled by default. Disables fragmentation handling for the userspace datapath connection tracker. Either \fBv4\fR or \fBv6\fR must be specified. Both v4 and v6 are enabled by default. +. +.TP +\*(DX\fBipf\-set\-min\-frag\fR [\fIdp\fR] \fBv4\fR | \fBv6\fR \fIminfrag\fR +Sets the minimum fragment size, which applies to non-last fragments, +supported by the userspace datapath connection tracker. Either v4 or v6 +must be specified. The default v4 value is 1200 and the clamped minimum is +400. The default v6 value is 1280, with a clamped minimum of 400, for +testing flexibility. The maximum frag size is not clamped, however setting +this value too high might result in valid fragments being dropped. diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index ddab09e..653c313 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -6539,6 +6539,13 @@ dpif_netdev_ipf_set_enabled(struct dpif *dpif OVS_UNUSED, bool v6, return ipf_set_enabled(v6, enable); } +static int +dpif_netdev_ipf_set_min_frag(struct dpif *dpif OVS_UNUSED, bool v6, + uint32_t min_frag) +{ + return ipf_set_min_frag(v6, min_frag); +} + const struct dpif_class dpif_netdev_class = { "netdev", dpif_netdev_init, @@ -6588,6 +6595,7 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_ct_get_maxconns, dpif_netdev_ct_get_nconns, dpif_netdev_ipf_set_enabled, + dpif_netdev_ipf_set_min_frag, dpif_netdev_meter_get_features, dpif_netdev_meter_set, dpif_netdev_meter_get, diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index e1331e4..043398d 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -3007,6 +3007,7 @@ const struct dpif_class dpif_netlink_class = { NULL, /* ct_get_maxconns */ NULL, /* ct_get_nconns */ NULL, /* ipf_set_enabled */ + NULL, /* ipf_set_min_frag */ dpif_netlink_meter_get_features, dpif_netlink_meter_set, dpif_netlink_meter_get, diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index db65227..2bd375b 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -446,6 +446,8 @@ struct dpif_class { /* IP Fragmentation. */ int (*ipf_set_enabled)(struct dpif *, bool v6, bool enabled); + /* Set minimum fragment allowed. */ + int (*ipf_set_min_frag)(struct dpif *, bool v6, uint32_t min_frag); /* Meters */ /* Queries 'dpif' for supported meter features. diff --git a/lib/ipf.c b/lib/ipf.c index dfb51e4..2b435c7 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -1271,3 +1271,26 @@ ipf_set_enabled(bool v6, bool enable) atomic_store_relaxed(v6 ? &ifp_v6_enabled : &ifp_v4_enabled, enable); return 0; } + +int +ipf_set_min_frag(bool v6, uint32_t value) +{ + /* If the user specifies an unreasonably large number, fragmentation + * will not work well but it will not blow up. */ + if ((!v6 && value < IPF_V4_FRAG_SIZE_LBOUND) || + (v6 && value < IPF_V6_FRAG_SIZE_LBOUND)) { + return 1; + } + + ipf_lock_lock(&ipf_lock); + if (v6) { + atomic_store_relaxed(&min_v6_frag_size, value); + } else { + atomic_store_relaxed(&min_v4_frag_size, value); + max_v4_frag_list_size = DIV_ROUND_UP( + IPV4_PACKET_MAX_SIZE - IPV4_PACKET_MAX_HDR_SIZE, + min_v4_frag_size - IPV4_PACKET_MAX_HDR_SIZE); + } + ipf_lock_unlock(&ipf_lock); + return 0; +} diff --git a/lib/ipf.h b/lib/ipf.h index da47dcb..fa6da5d 100644 --- a/lib/ipf.h +++ b/lib/ipf.h @@ -59,4 +59,6 @@ void ipf_destroy(void); int ipf_set_enabled(bool v6, bool enable); +int ipf_set_min_frag(bool v6, uint32_t value); + #endif /* ipf.h */ diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at index 3ea5b87..f1bf27a 100644 --- a/tests/system-kmod-macros.at +++ b/tests/system-kmod-macros.at @@ -130,3 +130,11 @@ m4_define([CHECK_CT_DPIF_GET_NCONNS], [ AT_SKIP_IF([:]) ]) + +# DPCTL_SET_MIN_FRAG_SIZE() +# +# The kernel does not support this command. +m4_define([DPCTL_SET_MIN_FRAG_SIZE], +[ + +]) diff --git a/tests/system-traffic.at b/tests/system-traffic.at index e17d39c..3f44904 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -2062,6 +2062,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") +DPCTL_SET_MIN_FRAG_SIZE() + AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809, actions=ct(commit) ]) @@ -2077,7 +2079,6 @@ AT_CLEANUP dnl Uses same first fragment as above 'incomplete reassembled packet' test. AT_SETUP([conntrack - IPv4 fragmentation with fragments specified]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2085,6 +2086,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") +DPCTL_SET_MIN_FRAG_SIZE() + AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809, actions=ct(commit) packet-out in_port=1, packet=50540000000a505400000009080045000030000100320011a4860a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit) @@ -2101,7 +2104,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2109,6 +2111,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") +DPCTL_SET_MIN_FRAG_SIZE() + AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a505400000009080045000030000100320011a4860a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit) packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809, actions=ct(commit) @@ -2125,7 +2129,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation overlapping fragments by 1 octet]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_OVERLAP() OVS_TRAFFIC_VSWITCHD_START() @@ -2134,6 +2137,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") +DPCTL_SET_MIN_FRAG_SIZE() + AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809, actions=ct(commit) packet-out in_port=1, packet=50540000000a505400000009080045000030000100310011a4870a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit) @@ -2149,7 +2154,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation overlapping fragments by 1 octet out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_OVERLAP() OVS_TRAFFIC_VSWITCHD_START() @@ -2158,6 +2162,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") +DPCTL_SET_MIN_FRAG_SIZE() + AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a505400000009080045000030000100310011a4870a0101010a01010200010002000800000010203040506070809000010203040506070809, actions=ct(commit) packet-out in_port=1, packet=50540000000a5054000000090800450001a400012000001183440a0101010a01010200010002000800000304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809, actions=ct(commit) @@ -2354,6 +2360,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "fc00::1/96") ADD_VETH(p1, at_ns1, br0, "fc00::2/96") +DPCTL_SET_MIN_FRAG_SIZE() + AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a50540000000986dd6000000001a02cfffc000000000000000000000000000001fc0000000000000000000000000000021100000100000001000100020008f62900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809, actions=ct(commit ) ]) @@ -2368,7 +2376,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation with fragments specified]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2376,6 +2383,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "fc00::1/96") ADD_VETH(p1, at_ns1, br0, "fc00::2/96") +DPCTL_SET_MIN_FRAG_SIZE() + AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a50540000000986dd6000000001a02cfffc000000000000000000000000000001fc0000000000000000000000000000021100000100000001000100020008ba0200010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809, actions=ct(commit ) packet-out in_port=1, packet=50540000000a50540000000986dd6000000000242cfffc000000000000000000000000000001fc000000000000000000000000000002110001980000000100010002000800000001020304050607080900010203040506070809, actions=ct(commit) @@ -2392,7 +2401,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2400,6 +2408,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "fc00::1/96") ADD_VETH(p1, at_ns1, br0, "fc00::2/96") +DPCTL_SET_MIN_FRAG_SIZE() + AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a50540000000986dd6000000000242cfffc000000000000000000000000000001fc000000000000000000000000000002110001980000000100010002000800000001020304050607080900010203040506070809, actions=ct(commit) packet-out in_port=1, packet=50540000000a50540000000986dd6000000001a02cfffc000000000000000000000000000001fc0000000000000000000000000000021100000100000001000100020008ba0200010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809, actions=ct(commit ) @@ -2416,7 +2426,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() @@ -2425,6 +2434,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "fc00::1/96") ADD_VETH(p1, at_ns1, br0, "fc00::2/96") +DPCTL_SET_MIN_FRAG_SIZE() + # Add different extension headers AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a50540000000986dd60000000019800fffc000000000000000000000000000001fc0000000000000000000000000000022c000000000000001100000100000001000100020008d62c00010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607, actions=ct(commit) @@ -2442,7 +2453,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers + out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() @@ -2451,6 +2461,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "fc00::1/96") ADD_VETH(p1, at_ns1, br0, "fc00::2/96") +DPCTL_SET_MIN_FRAG_SIZE() + # Add different extension headers AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a50540000000986dd60000000002c00fffc000000000000000000000000000001fc0000000000000000000000000000022c00000000000000110001880000000100010002000800000001020304050607080900010203040506070809, actions=ct(commit) @@ -2468,7 +2480,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers 2]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() @@ -2477,6 +2488,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "fc00::1/96") ADD_VETH(p1, at_ns1, br0, "fc00::2/96") +DPCTL_SET_MIN_FRAG_SIZE() + # Add different extension headers AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a50540000000986dd60000000019800fffc000000000000000000000000000001fc0000000000000000000000000000022c000000050200001100000100000001000100020008d62c00010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607080900010203040506070809000102030405060708090001020304050607, actions=ct(commit) @@ -2494,7 +2507,6 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers 2 + out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() @@ -2503,6 +2515,8 @@ ADD_NAMESPACES(at_ns0, at_ns1) ADD_VETH(p0, at_ns0, br0, "fc00::1/96") ADD_VETH(p1, at_ns1, br0, "fc00::2/96") +DPCTL_SET_MIN_FRAG_SIZE() + # Add different extension headers AT_DATA([bundle.txt], [dnl packet-out in_port=1, packet=50540000000a50540000000986dd60000000002c00fffc000000000000000000000000000001fc0000000000000000000000000000022c00000005020000110001880000000100010002000800000001020304050607080900010203040506070809, actions=ct(commit) diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at index 40b7567..6986bcb 100644 --- a/tests/system-userspace-macros.at +++ b/tests/system-userspace-macros.at @@ -119,3 +119,16 @@ m4_define([CHECK_CT_DPIF_SET_GET_MAXCONNS]) # Perform requirements checks for running ovs-dpctl ct-get-nconns. The # userspace datapath does support this feature. m4_define([CHECK_CT_DPIF_GET_NCONNS]) + +# DPCTL_SET_MIN_FRAG_SIZE() +# +# The userspace datapath supports this command. +m4_define([DPCTL_SET_MIN_FRAG_SIZE], +[ +AT_CHECK([ovs-appctl dpctl/ipf-set-min-frag v4 400], [], [dnl +setting minimum fragment size successful +]) +AT_CHECK([ovs-appctl dpctl/ipf-set-min-frag v6 400], [], [dnl +setting minimum fragment size successful +]) +]) From patchwork Mon Jul 9 16:32:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941440 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="rSAKle06"; 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 41PWFk144wz9rxs for ; Tue, 10 Jul 2018 02:37:14 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 9B486E0E; Mon, 9 Jul 2018 16:32:53 +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 12040D99 for ; Mon, 9 Jul 2018 16:32:51 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f67.google.com (mail-pl0-f67.google.com [209.85.160.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 88C7A78D for ; Mon, 9 Jul 2018 16:32:50 +0000 (UTC) Received: by mail-pl0-f67.google.com with SMTP id k1-v6so6278996plt.2 for ; Mon, 09 Jul 2018 09:32:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=QESsjqj5agyxLpQ4jr7wZYJ14U1tCGyO/NyZ5c8MJEQ=; b=rSAKle06PdA0jchCe1DYddwteq/5HnshLiZWe2AA8kFd7d8BlgxH+7PVo+MsYWgiCo /FR4HD9pnD0CrXVE53hZGy/EHuEsl06JClIJE58BgRZurRDHvnIkBEvAanA5PrX80Hzm pMJwE8d4qwbGl6giRuEhMSylLaKKdlLYUrFs0G3ax+k61c93cVBVtMUsZcARDEbpaj5l Zoy3JBaQDhOmpfVG1pr2SXYvb5KwulpzUvI6AuEZDPQD7wz8/+h5plFDGdfzf0jntYXo T2Cp9RZixrQ++mx+Ld+4RqAYO03meD8JZVXRZcfGYzezCISK8KvzAoXmzpQCKuEUIVVB yxKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=QESsjqj5agyxLpQ4jr7wZYJ14U1tCGyO/NyZ5c8MJEQ=; b=mdr6pMZK4M5nwOmCC3GdDD7mG7MEB+opPIpUlnsvEOcLQDrh3Jj4A9gsdkZeYbmtEP NDTaa01qDoojnjMZlInxNNvItllRMyZwXgjWKqrwfEeF/VV+hNlJAx1MV/AVLMbqLLWv ZuO5freHPQRAUcmRu9Vak1Djv/cbdEoHlfm/bub+/0Nr40f1UPdqIN6AhrR91JNIgH/2 9q0GYVMDTXeRbjwVpYy91B3RDTbDb966gPrVU6OCli+ejaK+uSdTli1uakDh332qXCU7 6liSBqWCmb1iToKWVGDDEZGSHrwvieT7CNdUvNnlNFqIrITd1FkKxjVIeOX3IRD0g+bd 3Alg== X-Gm-Message-State: APt69E24ybu7zQRCblk11zWWBcjhSuLghVE8BWsbtfXZixFsnx2tzPy/ y4R80lY+OZeqDzVls/JK0yw= X-Google-Smtp-Source: AAOMgpeVN0oSsmEIOZeYKOenGjYPcUUAYfeVW0vdkcDYGExmifbOYEt5HzGqI6BjF9M8XxjzvirkFA== X-Received: by 2002:a17:902:3f81:: with SMTP id a1-v6mr21310354pld.29.1531153970181; Mon, 09 Jul 2018 09:32:50 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:48 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:24 -0700 Message-Id: <1531153945-121300-9-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 8/9] ipf: Add set maximum fragments supported command. 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 A new command "ovs-appctl dpctl/ipf-set-max-nfrags" is added for userspace datapath conntrack fragmentation support. Signed-off-by: Darrell Ball --- NEWS | 2 ++ lib/ct-dpif.c | 8 ++++++++ lib/ct-dpif.h | 1 + lib/dpctl.c | 30 ++++++++++++++++++++++++++++++ lib/dpctl.man | 8 ++++++++ lib/dpif-netdev.c | 8 ++++++++ lib/dpif-netlink.c | 1 + lib/dpif-provider.h | 2 ++ lib/ipf.c | 10 ++++++++++ lib/ipf.h | 2 ++ 10 files changed, 72 insertions(+) diff --git a/NEWS b/NEWS index 9ab9970..2b22a84 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,8 @@ Post-v2.9.0 conntrack fragmentation support. * New "ovs-appctl dpctl/ipf-set-min-frag" command for userspace datapath conntrack fragmentation support. + * New "ovs-appctl dpctl/ipf-set-max-nfrags" command for userspace datapath + conntrack fragmentation support. - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". - OpenFlow: * OFPT_ROLE_STATUS is now available in OpenFlow 1.3. diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index d5596af..ee23a4d 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -180,6 +180,14 @@ ct_dpif_ipf_set_min_frag(struct dpif *dpif, bool v6, uint32_t min_frag) : EOPNOTSUPP); } +int +ct_dpif_ipf_set_max_nfrags(struct dpif *dpif, uint32_t max_frags) +{ + return (dpif->dpif_class->ipf_set_max_nfrags + ? dpif->dpif_class->ipf_set_max_nfrags(dpif, max_frags) + : EOPNOTSUPP); +} + void ct_dpif_entry_uninit(struct ct_dpif_entry *entry) { diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index f8a3192..2286dfb 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -202,6 +202,7 @@ int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns); int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns); int ct_dpif_ipf_set_enabled(struct dpif *, bool v6, bool enable); int ct_dpif_ipf_set_min_frag(struct dpif *, bool, uint32_t); +int ct_dpif_ipf_set_max_nfrags(struct dpif *, uint32_t); 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 e74d713..ab0f60b 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -1764,6 +1764,34 @@ dpctl_ipf_set_min_frag(int argc, const char *argv[], return error; } +static int +dpctl_ipf_set_max_nfrags(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + struct dpif *dpif; + int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif); + if (!error) { + uint32_t nfrags_max; + if (ovs_scan(argv[argc - 1], "%"SCNu32, &nfrags_max)) { + error = ct_dpif_ipf_set_max_nfrags(dpif, nfrags_max); + if (!error) { + dpctl_print(dpctl_p, + "setting maximum fragments successful"); + } else { + dpctl_error(dpctl_p, error, + "setting maximum fragments failed"); + } + } else { + error = EINVAL; + dpctl_error(dpctl_p, error, + "parameter missing for maximum fragments"); + } + dpif_close(dpif); + } + + return error; +} + /* Undocumented commands for unit testing. */ static int @@ -2069,6 +2097,8 @@ static const struct dpctl_command all_commands[] = { dpctl_ipf_set_disabled, DP_RW }, { "ipf-set-min-frag", "[dp] v4 | v6 minfragment", 2, 3, dpctl_ipf_set_min_frag, DP_RW }, + { "ipf-set-max-nfrags", "[dp] maxfrags", 1, 2, + dpctl_ipf_set_max_nfrags, DP_RW }, { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, diff --git a/lib/dpctl.man b/lib/dpctl.man index 900900d..c6c4a87 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -296,3 +296,11 @@ must be specified. The default v4 value is 1200 and the clamped minimum is 400. The default v6 value is 1280, with a clamped minimum of 400, for testing flexibility. The maximum frag size is not clamped, however setting this value too high might result in valid fragments being dropped. +. +.TP +\*(DX\fBipf\-set\-max\-nfrags\fR [\fIdp\fR] \fImaxfrags\fR +Sets the maximum number of fragments tracked by the userspace datapath +connection tracker. The default value is 1000 and the clamped maximum +is 5000. Note that packet buffers can be held by the fragmentation +module while fragments are incomplete, but will timeout after 15 seconds. +Memory pool sizing should be set accordingly when fragmentation is enabled. diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 653c313..76bc1d9 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -6546,6 +6546,13 @@ dpif_netdev_ipf_set_min_frag(struct dpif *dpif OVS_UNUSED, bool v6, return ipf_set_min_frag(v6, min_frag); } +static int +dpif_netdev_ipf_set_max_nfrags(struct dpif *dpif OVS_UNUSED, + uint32_t max_frags) +{ + return ipf_set_max_nfrags(max_frags); +} + const struct dpif_class dpif_netdev_class = { "netdev", dpif_netdev_init, @@ -6596,6 +6603,7 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_ct_get_nconns, dpif_netdev_ipf_set_enabled, dpif_netdev_ipf_set_min_frag, + dpif_netdev_ipf_set_max_nfrags, dpif_netdev_meter_get_features, dpif_netdev_meter_set, dpif_netdev_meter_get, diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 043398d..80c54f5 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -3008,6 +3008,7 @@ const struct dpif_class dpif_netlink_class = { NULL, /* ct_get_nconns */ NULL, /* ipf_set_enabled */ NULL, /* ipf_set_min_frag */ + NULL, /* ipf_set_max_nfrags */ dpif_netlink_meter_get_features, dpif_netlink_meter_set, dpif_netlink_meter_get, diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 2bd375b..10b39ca 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -448,6 +448,8 @@ struct dpif_class { int (*ipf_set_enabled)(struct dpif *, bool v6, bool enabled); /* Set minimum fragment allowed. */ int (*ipf_set_min_frag)(struct dpif *, bool v6, uint32_t min_frag); + /* Set maximum number of fragments tracked. */ + int (*ipf_set_max_nfrags)(struct dpif *, uint32_t max_nfrags); /* Meters */ /* Queries 'dpif' for supported meter features. diff --git a/lib/ipf.c b/lib/ipf.c index 2b435c7..ef3236a 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -1294,3 +1294,13 @@ ipf_set_min_frag(bool v6, uint32_t value) ipf_lock_unlock(&ipf_lock); return 0; } + +int +ipf_set_max_nfrags(uint32_t value) +{ + if (value > IPF_NFRAG_UBOUND) { + return 1; + } + atomic_store_relaxed(&nfrag_max, value); + return 0; +} diff --git a/lib/ipf.h b/lib/ipf.h index fa6da5d..4289e5e 100644 --- a/lib/ipf.h +++ b/lib/ipf.h @@ -61,4 +61,6 @@ int ipf_set_enabled(bool v6, bool enable); int ipf_set_min_frag(bool v6, uint32_t value); +int ipf_set_max_nfrags(uint32_t value); + #endif /* ipf.h */ From patchwork Mon Jul 9 16:32:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 941441 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; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="V74ttQ2w"; 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 41PWGW42RTz9rxs for ; Tue, 10 Jul 2018 02:37:55 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 7F6A6E3B; Mon, 9 Jul 2018 16:32:55 +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 0EF71DC2 for ; Mon, 9 Jul 2018 16:32:54 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f193.google.com (mail-pf0-f193.google.com [209.85.192.193]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 7AC5478E for ; Mon, 9 Jul 2018 16:32:52 +0000 (UTC) Received: by mail-pf0-f193.google.com with SMTP id j3-v6so14029149pfh.11 for ; Mon, 09 Jul 2018 09:32:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=8OHYamZ2JQeWkHeboKSBhFucdsIvHcM9irEC+EA0LLA=; b=V74ttQ2wouJveJyTmyPKVKwxm83qZn1krfoOPAi3QAAEucbi74UKQau3U2h10If5Ar OehxX3YPiGGRlDR4kzuh7yfUTbkfJkBBHjP9QZOcm2k/+gCCc3sQA88Sc82723+P3IDZ aqnlHSdf0F+8Bo85/vKPihuoh2lnt7Pf/eMdA1OsxeFSUsv/zaeSPv0nCj8uWOGNKxy0 VH1s1ynwyV5QHGVXd0tPFMC5Yoi8nl1H6LFn8n9Nk44kagKbTaKxGUXjidgjZINJ1EIt jPqChq0Q8EeUjlJwaq22Q2fxADnLm+wCEHeZTs84i1rFZRTkjkLKfxRsCNILMmuKRfai DWpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=8OHYamZ2JQeWkHeboKSBhFucdsIvHcM9irEC+EA0LLA=; b=TAe1t2WazRCldhdfI/cHwGtjgPhANfdG+/CmvpsXK3TF/08mjXjwhdyk+PUjCCTyxl nJAUuAIYDO0JRCoW4aMSpVO/4MpoDZ4SI83Nl1gIfsY1gi5h7y/Y7Yg2ipqX/Y0IIKgO 9cSwMeGUl7EQoLzvTtEWEaQPhcdPVkYVMDTSt8cxXntrstAk04hOEyPtj9ekg9/F+SKs MFxUKwVTqpNNbu6q9aZc/qKed3HDIr4a/K6abeiufq07I4N+HriepO9zNmLs7yYO2fdN sTp857GHzj4AsLu0P9u8NnqlsUAtKrHkPBcCMymMkuEIe1QiIYOuxRRSA3DVGwud+XGj 4KeQ== X-Gm-Message-State: APt69E0we7K42Xirruc+gHf7eUAgdrblZu9zn9ik4q73wI/T+3/4Y9PV 7gHk4I5nIyzTz2W5BnF/IZg= X-Google-Smtp-Source: AAOMgpfk8v01Z+H+qS2CwjoSassIh2RLTyEKzFl1B8DYGo79K5UAsYxf8rrZSOPdnX504XPUuHvQPQ== X-Received: by 2002:a62:c542:: with SMTP id j63-v6mr10442899pfg.100.1531153971759; Mon, 09 Jul 2018 09:32:51 -0700 (PDT) Received: from ubuntu.localdomain (c-73-162-236-45.hsd1.ca.comcast.net. [73.162.236.45]) by smtp.gmail.com with ESMTPSA id u2-v6sm23828301pfn.59.2018.07.09.09.32.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 09 Jul 2018 09:32:50 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org Date: Mon, 9 Jul 2018 09:32:25 -0700 Message-Id: <1531153945-121300-10-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531153945-121300-1-git-send-email-dlu998@gmail.com> References: <1531153945-121300-1-git-send-email-dlu998@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [patch v7 9/9] ipf: Add fragmentation status reporting. 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 A new command "ovs-appctl dpctl/ipf-get-status" is added for userspace datapath conntrack fragmentation support. The command shows the configuration status, fragment counters and ipf lists state. Signed-off-by: Darrell Ball --- NEWS | 2 + lib/ct-dpif.c | 45 ++++++++++++++++ lib/ct-dpif.h | 10 ++++ lib/dpctl.c | 107 ++++++++++++++++++++++++++++++++++++++ lib/dpctl.man | 6 +++ lib/dpif-netdev.c | 58 +++++++++++++++++++++ lib/dpif-netlink.c | 4 ++ lib/dpif-provider.h | 17 ++++++ lib/ipf.c | 107 ++++++++++++++++++++++++++++++++++++++ lib/ipf.h | 10 ++++ tests/system-kmod-macros.at | 24 +++++++++ tests/system-traffic.at | 18 +++++++ tests/system-userspace-macros.at | 109 +++++++++++++++++++++++++++++++++++++++ 13 files changed, 517 insertions(+) diff --git a/NEWS b/NEWS index 2b22a84..af8f9a8 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,8 @@ Post-v2.9.0 datapath conntrack fragmentation support. * New "ovs-appctl dpctl/ipf-set-max-nfrags" command for userspace datapath conntrack fragmentation support. + * New "ovs-appctl dpctl/ipf-get-status" command for userspace datapath + conntrack fragmentation support. - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". - OpenFlow: * OFPT_ROLE_STATUS is now available in OpenFlow 1.3. diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index ee23a4d..a59bc1e 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -188,6 +188,51 @@ ct_dpif_ipf_set_max_nfrags(struct dpif *dpif, uint32_t max_frags) : EOPNOTSUPP); } +int ct_dpif_ipf_get_status(struct dpif *dpif, bool *ipf_v4_enabled, + unsigned int *min_v4_frag_size, unsigned int *nfrag_max, + unsigned int *nfrag, unsigned int *n4frag_accepted, + unsigned int *n4frag_completed_sent, + unsigned int *n4frag_expired_sent, unsigned int *n4frag_too_small, + unsigned int *n4frag_overlap, bool *ipf_v6_enabled, + unsigned int *min_v6_frag_size, unsigned int *n6frag_accepted, + unsigned int *n6frag_completed_sent, + unsigned int *n6frag_expired_sent, unsigned int *n6frag_too_small, + unsigned int *n6frag_overlap) +{ + return (dpif->dpif_class->ipf_get_status + ? dpif->dpif_class->ipf_get_status(dpif, ipf_v4_enabled, + min_v4_frag_size, nfrag_max, nfrag, n4frag_accepted, + n4frag_completed_sent, n4frag_expired_sent, n4frag_too_small, + n4frag_overlap, ipf_v6_enabled, min_v6_frag_size, n6frag_accepted, + n6frag_completed_sent, n6frag_expired_sent, n6frag_too_small, + n6frag_overlap) + : EOPNOTSUPP); +} + +int +ct_dpif_ipf_dump_start(struct dpif *dpif, struct ipf_dump_ctx **dump_ctx) +{ + return (dpif->dpif_class->ipf_dump_start + ? dpif->dpif_class->ipf_dump_start(dpif, dump_ctx) + : EOPNOTSUPP); +} + +int +ct_dpif_ipf_dump_next(struct dpif *dpif, void *dump_ctx, char **dump) +{ + return (dpif->dpif_class->ipf_dump_next + ? dpif->dpif_class->ipf_dump_next(dpif, dump_ctx, dump) + : EOPNOTSUPP); +} + +int +ct_dpif_ipf_dump_done(struct dpif *dpif, void *dump_ctx) +{ + return (dpif->dpif_class->ipf_dump_done + ? dpif->dpif_class->ipf_dump_done(dpif, dump_ctx) + : EOPNOTSUPP); +} + void ct_dpif_entry_uninit(struct ct_dpif_entry *entry) { diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index 2286dfb..2ff7e26 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -17,6 +17,7 @@ #ifndef CT_DPIF_H #define CT_DPIF_H +#include "ipf.h" #include "openvswitch/types.h" #include "packets.h" @@ -203,6 +204,15 @@ int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns); int ct_dpif_ipf_set_enabled(struct dpif *, bool v6, bool enable); int ct_dpif_ipf_set_min_frag(struct dpif *, bool, uint32_t); int ct_dpif_ipf_set_max_nfrags(struct dpif *, uint32_t); +int ct_dpif_ipf_get_status(struct dpif *dpif, bool *, unsigned int *, + unsigned int *, unsigned int *, unsigned int *, + unsigned int *, unsigned int *, unsigned int *, + unsigned int *, bool *, unsigned int *, + unsigned int *, unsigned int *, unsigned int *, + unsigned int *, unsigned int *); +int ct_dpif_ipf_dump_start(struct dpif *dpif, struct ipf_dump_ctx **); +int ct_dpif_ipf_dump_next(struct dpif *dpif, void *, char **); +int ct_dpif_ipf_dump_done(struct dpif *dpif, void *); 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 ab0f60b..2b2a74a 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -1792,6 +1792,111 @@ dpctl_ipf_set_max_nfrags(int argc, const char *argv[], return error; } +static void +dpctl_dump_ipf(struct dpif *dpif, struct dpctl_params *dpctl_p) +{ + struct ipf_dump_ctx *dump_ctx; + char *dump; + + int error = ct_dpif_ipf_dump_start(dpif, &dump_ctx); + if (error) { + dpctl_error(dpctl_p, error, "starting ipf list dump"); + /* Nothing to clean up, just return. */ + return; + } + + dpctl_print(dpctl_p, "\n Fragment Lists:\n\n"); + while (!(error = ct_dpif_ipf_dump_next(dpif, dump_ctx, &dump))) { + dpctl_print(dpctl_p, "%s\n", dump); + free(dump); + } + + if (error && error != EOF) { + dpctl_error(dpctl_p, error, "dumping ipf lists failed"); + } + + ct_dpif_ipf_dump_done(dpif, dump_ctx); +} + +static int +dpctl_ct_ipf_get_status(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + struct dpif *dpif; + int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif); + if (!error) { + bool ipf_v4_enabled; + unsigned int min_v4_frag_size; + unsigned int nfrag_max; + unsigned int nfrag; + unsigned int n4frag_accepted; + unsigned int n4frag_completed_sent; + unsigned int n4frag_expired_sent; + unsigned int n4frag_too_small; + unsigned int n4frag_overlap; + unsigned int min_v6_frag_size; + bool ipf_v6_enabled; + unsigned int n6frag_accepted; + unsigned int n6frag_completed_sent; + unsigned int n6frag_expired_sent; + unsigned int n6frag_too_small; + unsigned int n6frag_overlap; + error = ct_dpif_ipf_get_status(dpif, &ipf_v4_enabled, + &min_v4_frag_size, &nfrag_max, &nfrag, &n4frag_accepted, + &n4frag_completed_sent, &n4frag_expired_sent, &n4frag_too_small, + &n4frag_overlap, &ipf_v6_enabled, &min_v6_frag_size, + &n6frag_accepted, &n6frag_completed_sent, &n6frag_expired_sent, + &n6frag_too_small, &n6frag_overlap); + + if (!error) { + dpctl_print(dpctl_p, " Fragmentation Module Status\n"); + dpctl_print(dpctl_p, " ---------------------------\n"); + dpctl_print(dpctl_p, " v4 enabled: %u\n", ipf_v4_enabled); + dpctl_print(dpctl_p, " v6 enabled: %u\n", ipf_v6_enabled); + dpctl_print(dpctl_p, " max num frags (v4/v6): %u\n", + nfrag_max); + dpctl_print(dpctl_p, " num frag: %u\n", nfrag); + dpctl_print(dpctl_p, " min v4 frag size: %u\n", + min_v4_frag_size); + dpctl_print(dpctl_p, " v4 frags accepted: %u\n", + n4frag_accepted); + dpctl_print(dpctl_p, " v4 frags completed: %u\n", + n4frag_completed_sent); + dpctl_print(dpctl_p, " v4 frags expired: %u\n", + n4frag_expired_sent); + dpctl_print(dpctl_p, " v4 frags too small: %u\n", + n4frag_too_small); + dpctl_print(dpctl_p, " v4 frags overlapped: %u\n", + n4frag_overlap); + dpctl_print(dpctl_p, " min v6 frag size: %u\n", + min_v6_frag_size); + dpctl_print(dpctl_p, " v6 frags accepted: %u\n", + n6frag_accepted); + dpctl_print(dpctl_p, " v6 frags completed: %u\n", + n6frag_completed_sent); + dpctl_print(dpctl_p, " v6 frags expired: %u\n", + n6frag_expired_sent); + dpctl_print(dpctl_p, " v6 frags too small: %u\n", + n6frag_too_small); + dpctl_print(dpctl_p, " v6 frags overlapped: %u\n", + n6frag_overlap); + } else { + dpctl_error(dpctl_p, error, + "ipf status could not be retrieved"); + return error; + } + + if (argc > 0 && (!strncmp(argv[argc - 1], "-m", 2) + || !strncmp(argv[argc - 1], "--more", 6))) { + dpctl_dump_ipf(dpif, dpctl_p); + } + + dpif_close(dpif); + } + + return error; +} + /* Undocumented commands for unit testing. */ static int @@ -2099,6 +2204,8 @@ static const struct dpctl_command all_commands[] = { dpctl_ipf_set_min_frag, DP_RW }, { "ipf-set-max-nfrags", "[dp] maxfrags", 1, 2, dpctl_ipf_set_max_nfrags, DP_RW }, + { "ipf-get-status", "[dp] [-m | --more]", 0, 2, dpctl_ct_ipf_get_status, + DP_RO }, { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, diff --git a/lib/dpctl.man b/lib/dpctl.man index c6c4a87..fb66b58 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -304,3 +304,9 @@ connection tracker. The default value is 1000 and the clamped maximum is 5000. Note that packet buffers can be held by the fragmentation module while fragments are incomplete, but will timeout after 15 seconds. Memory pool sizing should be set accordingly when fragmentation is enabled. +. +.TP +.DO "[\fB\-m\fR | \fB\-\-more\fR]" "\*(DX\fBipf\-get\-status\fR [\fIdp\fR]" +Gets the configuration settings and fragment counters associated with the +fragmentation handling of the userspace datapath connection tracker. With +\fB\-m\fR or \fB\-\-more\fR, also dumps the ipf lists. diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 76bc1d9..db551ea 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -6553,6 +6553,60 @@ dpif_netdev_ipf_set_max_nfrags(struct dpif *dpif OVS_UNUSED, return ipf_set_max_nfrags(max_frags); } +static int +dpif_netdev_ipf_get_status(struct dpif *dpif OVS_UNUSED, + bool *ipf_v4_enabled, unsigned int *min_v4_frag_size, + unsigned int *nfrag_max, unsigned int *nfrag, + unsigned int *n4frag_accepted, unsigned int *n4frag_completed_sent, + unsigned int *n4frag_expired_sent, unsigned int *n4frag_too_small, + unsigned int *n4frag_overlap, bool *ipf_v6_enabled, + unsigned int *min_v6_frag_size, unsigned int *n6frag_accepted, + unsigned int *n6frag_completed_sent, unsigned int *n6frag_expired_sent, + unsigned int *n6frag_too_small, unsigned int *n6frag_overlap) +{ + struct ipf_status ipf_status; + ipf_get_status(&ipf_status); + *ipf_v4_enabled = ipf_status.ifp_v4_enabled; + *min_v4_frag_size = ipf_status.min_v4_frag_size; + *nfrag_max = ipf_status.nfrag_max; + *nfrag = ipf_status.nfrag; + *n4frag_accepted = ipf_status.n4frag_accepted; + *n4frag_completed_sent = ipf_status.n4frag_completed_sent; + *n4frag_expired_sent = ipf_status.n4frag_expired_sent; + *n4frag_too_small = ipf_status.n4frag_too_small; + *n4frag_overlap = ipf_status.n4frag_overlap; + *ipf_v6_enabled = ipf_status.ifp_v6_enabled; + *min_v6_frag_size = ipf_status.min_v6_frag_size; + *n6frag_accepted = ipf_status.n6frag_accepted; + *n6frag_completed_sent = ipf_status.n6frag_completed_sent; + *n6frag_expired_sent = ipf_status.n6frag_expired_sent; + *n6frag_too_small = ipf_status.n6frag_too_small; + *n6frag_overlap = ipf_status.n6frag_overlap; + return 0; +} + +static int +dpif_netdev_ipf_dump_start(struct dpif *dpif OVS_UNUSED, + struct ipf_dump_ctx **ipf_dump_ctx) +{ + return ipf_dump_start(ipf_dump_ctx); +} + +static int +dpif_netdev_ipf_dump_next(struct dpif *dpif OVS_UNUSED, + void *ipf_dump_ctx, char **dump) +{ + return ipf_dump_next(ipf_dump_ctx, dump); +} + +static int +dpif_netdev_ipf_dump_done(struct dpif *dpif OVS_UNUSED, + void *ipf_dump_ctx) +{ + return ipf_dump_done(ipf_dump_ctx); + +} + const struct dpif_class dpif_netdev_class = { "netdev", dpif_netdev_init, @@ -6604,6 +6658,10 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_ipf_set_enabled, dpif_netdev_ipf_set_min_frag, dpif_netdev_ipf_set_max_nfrags, + dpif_netdev_ipf_get_status, + dpif_netdev_ipf_dump_start, + dpif_netdev_ipf_dump_next, + dpif_netdev_ipf_dump_done, dpif_netdev_meter_get_features, dpif_netdev_meter_set, dpif_netdev_meter_get, diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 80c54f5..42ac01d 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -3009,6 +3009,10 @@ const struct dpif_class dpif_netlink_class = { NULL, /* ipf_set_enabled */ NULL, /* ipf_set_min_frag */ NULL, /* ipf_set_max_nfrags */ + NULL, /* ipf_get_status */ + NULL, /* ipf_dump_start */ + NULL, /* ipf_dump_next */ + NULL, /* ipf_dump_done */ dpif_netlink_meter_get_features, dpif_netlink_meter_set, dpif_netlink_meter_get, diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 10b39ca..2e0d596 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -24,6 +24,7 @@ #include "openflow/openflow.h" #include "dpif.h" +#include "ipf.h" #include "util.h" #ifdef __cplusplus @@ -450,6 +451,22 @@ struct dpif_class { int (*ipf_set_min_frag)(struct dpif *, bool v6, uint32_t min_frag); /* Set maximum number of fragments tracked. */ int (*ipf_set_max_nfrags)(struct dpif *, uint32_t max_nfrags); + /* Get fragmentation configuration status and counters. */ + int (*ipf_get_status)(struct dpif *, bool *ipf_v4_enabled, + unsigned int *min_v4_frag_size, + unsigned int *nfrag_max, unsigned int *nfrag, + unsigned int *n4frag_accepted, unsigned int *n4frag_completed_sent, + unsigned int *n4frag_expired_sent, unsigned int *n4frag_too_small, + unsigned int *n4frag_overlap, bool *ipf_v6_enabled, + unsigned int *min_v6_frag_size, unsigned int *n6frag_accepted, + unsigned int *n6frag_completed_sent, + unsigned int *n6frag_expired_sent, unsigned int *n6frag_too_small, + unsigned int *n6frag_overlap); + int (*ipf_dump_start)(struct dpif *, struct ipf_dump_ctx **ipf_dump_ctx); + /* Finds the next ipf list and creates a string representation of the + * state of an ipf list, to which 'dump' is pointed to. */ + int (*ipf_dump_next)(struct dpif *, void *, char **dump); + int (*ipf_dump_done)(struct dpif *, void *ipf_dump_ctx); /* Meters */ /* Queries 'dpif' for supported meter features. diff --git a/lib/ipf.c b/lib/ipf.c index ef3236a..9beaaa1 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -52,6 +52,10 @@ enum ipf_list_state { IPF_LIST_STATE_NUM, }; +static char *ipf_state_name[IPF_LIST_STATE_NUM] = + {"unused", "reassemble fail", "other frag", "first frag", "last frag", + "first/last frag", "complete"}; + enum ipf_list_type { IPF_FRAG_COMPLETED_LIST, IPF_FRAG_EXPIRY_LIST, @@ -1304,3 +1308,106 @@ ipf_set_max_nfrags(uint32_t value) atomic_store_relaxed(&nfrag_max, value); return 0; } + +int +ipf_get_status(struct ipf_status *ipf_status) +{ + atomic_read_relaxed(&ifp_v4_enabled, &ipf_status->ifp_v4_enabled); + atomic_read_relaxed(&min_v4_frag_size, &ipf_status->min_v4_frag_size); + atomic_read_relaxed(&nfrag_max, &ipf_status->nfrag_max); + ipf_status->nfrag = atomic_count_get(&nfrag); + ipf_status->n4frag_accepted = atomic_count_get(&n4frag_accepted); + ipf_status->n4frag_completed_sent = + atomic_count_get(&n4frag_completed_sent); + ipf_status->n4frag_expired_sent = + atomic_count_get(&n4frag_expired_sent); + ipf_status->n4frag_too_small = atomic_count_get(&n4frag_too_small); + ipf_status->n4frag_overlap = atomic_count_get(&n4frag_overlap); + atomic_read_relaxed(&ifp_v6_enabled, &ipf_status->ifp_v6_enabled); + atomic_read_relaxed(&min_v6_frag_size, &ipf_status->min_v6_frag_size); + ipf_status->n6frag_accepted = atomic_count_get(&n6frag_accepted); + ipf_status->n6frag_completed_sent = + atomic_count_get(&n6frag_completed_sent); + ipf_status->n6frag_expired_sent = + atomic_count_get(&n6frag_expired_sent); + ipf_status->n6frag_too_small = atomic_count_get(&n6frag_too_small); + ipf_status->n6frag_overlap = atomic_count_get(&n6frag_overlap); + return 0; +} + +struct ipf_dump_ctx { + struct hmap_position bucket_pos; +}; + +/* Allocates an 'ipf_dump_ctx' to keep track of an hmap position. */ +int +ipf_dump_start(struct ipf_dump_ctx **ipf_dump_ctx) +{ + *ipf_dump_ctx = xzalloc(sizeof **ipf_dump_ctx); + return 0; +} + +/* Creates a string representation of the state of an 'ipf_list' and puts + * it in 'ds'. */ +static void +ipf_dump_create(const struct ipf_list *ipf_list, struct ds *ds) +{ + + ds_put_cstr(ds, "("); + if (ipf_list->key.dl_type == htons(ETH_TYPE_IP)) { + ds_put_format(ds, "src="IP_FMT",dst="IP_FMT",", + IP_ARGS(ipf_list->key.src_addr.ipv4_aligned), + IP_ARGS(ipf_list->key.dst_addr.ipv4_aligned)); + } else { + ds_put_cstr(ds, "src="); + ipv6_format_addr(&ipf_list->key.src_addr.ipv6_aligned, ds); + ds_put_cstr(ds, ",dst="); + ipv6_format_addr(&ipf_list->key.dst_addr.ipv6_aligned, ds); + ds_put_cstr(ds, ","); + } + + ds_put_format(ds, "recirc_id=%u,ip_id=%u,dl_type=0x%x,zone=%u,nw_proto=%u", + ipf_list->key.recirc_id, ntohl(ipf_list->key.ip_id), + ntohs(ipf_list->key.dl_type), ipf_list->key.zone, + ipf_list->key.nw_proto); + + ds_put_format(ds, ",num_fragments=%u,state=%s", + ipf_list->last_inuse_idx + 1, + ipf_state_name[ipf_list->state]); + + ds_put_cstr(ds, ")"); +} + +/* Finds the next ipf list starting from 'ipf_dump_ctx->bucket_pos' and uses + * ipf_dump_create() to create a string representation of the state of an + * ipf list, to which 'dump' is pointed to. */ +int +ipf_dump_next(struct ipf_dump_ctx *ipf_dump_ctx, char **dump) +{ + ipf_lock_lock(&ipf_lock); + + struct hmap_node *node = hmap_at_position(&frag_lists, + &ipf_dump_ctx->bucket_pos); + if (!node) { + ipf_lock_unlock(&ipf_lock); + return EOF; + } else { + struct ipf_list *ipf_list_; + INIT_CONTAINER(ipf_list_, node, node); + struct ipf_list ipf_list = *ipf_list_; + ipf_lock_unlock(&ipf_lock); + struct ds ds = DS_EMPTY_INITIALIZER; + ipf_dump_create(&ipf_list, &ds); + *dump = xstrdup(ds.string); + ds_destroy(&ds); + return 0; + } +} + +/* Frees an ipf_dump_ctx allocated by ipf_dump_start. */ +int +ipf_dump_done(struct ipf_dump_ctx *ipf_dump_ctx) +{ + free(ipf_dump_ctx); + return 0; +} diff --git a/lib/ipf.h b/lib/ipf.h index 4289e5e..36a182a 100644 --- a/lib/ipf.h +++ b/lib/ipf.h @@ -63,4 +63,14 @@ int ipf_set_min_frag(bool v6, uint32_t value); int ipf_set_max_nfrags(uint32_t value); +int ipf_get_status(struct ipf_status *ipf_status); + +struct ipf_dump_ctx; + +int ipf_dump_start(struct ipf_dump_ctx **ipf_dump_ctx); + +int ipf_dump_next(struct ipf_dump_ctx *ipf_dump_ctx, char **dump); + +int ipf_dump_done(struct ipf_dump_ctx *ipf_dump_ctx); + #endif /* ipf.h */ diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at index f1bf27a..736a643 100644 --- a/tests/system-kmod-macros.at +++ b/tests/system-kmod-macros.at @@ -138,3 +138,27 @@ m4_define([DPCTL_SET_MIN_FRAG_SIZE], [ ]) + +# DPCTL_MODIFY_FRAGMENTATION() +# +# The kernel does not support this command. +m4_define([DPCTL_MODIFY_FRAGMENTATION], +[ + +]) + +# DPCTL_CHECK_FRAGMENTATION_PASS() +# +# The kernel does not support this command. +m4_define([DPCTL_CHECK_FRAGMENTATION_PASS], +[ + +]) + +# DPCTL_CHECK_FRAGMENTATION_FAIL() +# +# The kernel does not support this command. +m4_define([DPCTL_CHECK_FRAGMENTATION_FAIL], +[ + +]) diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 3f44904..f727825 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -1923,6 +1923,9 @@ priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) +dnl Modify userspace conntrack fragmentation handling. +DPCTL_MODIFY_FRAGMENTATION() + dnl Ipv4 fragmentation connectivity check. NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl 3 packets transmitted, 3 received, 0% packet loss, time 0ms @@ -1933,6 +1936,9 @@ NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) +dnl Check userspace conntrack fragmentation counters. +DPCTL_CHECK_FRAGMENTATION_PASS() + OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP @@ -1958,11 +1964,17 @@ priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) +dnl Modify userspace conntrack fragmentation handling. +DPCTL_MODIFY_FRAGMENTATION() + dnl Ipv4 fragmentation connectivity check. NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 1 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl 7 packets transmitted, 0 received, 100% packet loss, time 0ms ]) +dnl Check userspace conntrack fragmentation counters. +DPCTL_CHECK_FRAGMENTATION_FAIL() + OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP @@ -1988,6 +2000,9 @@ priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) +dnl Modify userspace conntrack fragmentation handling. +DPCTL_MODIFY_FRAGMENTATION() + dnl Ipv4 fragmentation connectivity check. NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -w 2 10.2.2.2 | FORMAT_PING], [0], [dnl 3 packets transmitted, 3 received, 0% packet loss, time 0ms @@ -1998,6 +2013,9 @@ NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 2 10.2.2.2 | FORMAT_PING 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) +dnl Check userspace conntrack fragmentation counters. +DPCTL_CHECK_FRAGMENTATION_PASS() + OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at index 6986bcb..fcae3cc 100644 --- a/tests/system-userspace-macros.at +++ b/tests/system-userspace-macros.at @@ -132,3 +132,112 @@ AT_CHECK([ovs-appctl dpctl/ipf-set-min-frag v6 400], [], [dnl setting minimum fragment size successful ]) ]) + +# DPCTL_MODIFY_FRAGMENTATION() +# +# The userspace datapath supports this command. +m4_define([DPCTL_MODIFY_FRAGMENTATION], +[ +AT_CHECK([ovs-appctl dpctl/ipf-set-min-frag v4 1000], [], [dnl +setting minimum fragment size successful +]) +AT_CHECK([ovs-appctl dpctl/ipf-set-max-nfrags 500], [], [dnl +setting maximum fragments successful +]) +AT_CHECK([ovs-appctl dpctl/ipf-get-status], [], [dnl + Fragmentation Module Status + --------------------------- + v4 enabled: 1 + v6 enabled: 1 + max num frags (v4/v6): 500 + num frag: 0 + min v4 frag size: 1000 + v4 frags accepted: 0 + v4 frags completed: 0 + v4 frags expired: 0 + v4 frags too small: 0 + v4 frags overlapped: 0 + min v6 frag size: 1280 + v6 frags accepted: 0 + v6 frags completed: 0 + v6 frags expired: 0 + v6 frags too small: 0 + v6 frags overlapped: 0 +]) +]) + +# DPCTL_CHECK_FRAGMENTATION_PASS() +# +# Used to check fragmentation counters for some fragmentation tests using +# the userspace datapath. +m4_define([DPCTL_CHECK_FRAGMENTATION_PASS], +[ +AT_CHECK([ovs-appctl dpctl/ipf-get-status --more], [], [dnl + Fragmentation Module Status + --------------------------- + v4 enabled: 1 + v6 enabled: 1 + max num frags (v4/v6): 500 + num frag: 0 + min v4 frag size: 1000 + v4 frags accepted: 30 + v4 frags completed: 30 + v4 frags expired: 0 + v4 frags too small: 0 + v4 frags overlapped: 0 + min v6 frag size: 1280 + v6 frags accepted: 0 + v6 frags completed: 0 + v6 frags expired: 0 + v6 frags too small: 0 + v6 frags overlapped: 0 + + Fragment Lists: + +]) +]) + +# FORMAT_FRAG_LIST([]) +# +# Strip content from the piped input which can differ from test to test; recirc_id +# and ip_id fields in an ipf_list vary from test to test and hence are cleared. +m4_define([FORMAT_FRAG_LIST], + [[sed -e 's/ip_id=[0-9]*/ip_id=/g' -e 's/recirc_id=[0-9]*/recirc_id=/g']]) + +# DPCTL_CHECK_FRAGMENTATION_FAIL() +# +# Used to check fragmentation counters for some fragmentation tests using +# the userspace datapath, when failure to transmit fragments is expected. +m4_define([DPCTL_CHECK_FRAGMENTATION_FAIL], +[ +AT_CHECK([ovs-appctl dpctl/ipf-get-status -m | FORMAT_FRAG_LIST()], [], [dnl + Fragmentation Module Status + --------------------------- + v4 enabled: 1 + v6 enabled: 1 + max num frags (v4/v6): 500 + num frag: 7 + min v4 frag size: 1000 + v4 frags accepted: 7 + v4 frags completed: 0 + v4 frags expired: 0 + v4 frags too small: 0 + v4 frags overlapped: 0 + min v6 frag size: 1280 + v6 frags accepted: 0 + v6 frags completed: 0 + v6 frags expired: 0 + v6 frags too small: 0 + v6 frags overlapped: 0 + + Fragment Lists: + +(src=10.1.1.1,dst=10.1.1.2,recirc_id=,ip_id=,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag) +(src=10.1.1.1,dst=10.1.1.2,recirc_id=,ip_id=,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag) +(src=10.1.1.1,dst=10.1.1.2,recirc_id=,ip_id=,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag) +(src=10.1.1.1,dst=10.1.1.2,recirc_id=,ip_id=,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag) +(src=10.1.1.1,dst=10.1.1.2,recirc_id=,ip_id=,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag) +(src=10.1.1.1,dst=10.1.1.2,recirc_id=,ip_id=,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag) +(src=10.1.1.1,dst=10.1.1.2,recirc_id=,ip_id=,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag) +]) +])