From patchwork Tue Jul 17 02:39:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944680 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="OKaXusUn"; 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 41V4Jq6NvNz9s1R for ; Tue, 17 Jul 2018 12:40:43 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 52A72CBF; Tue, 17 Jul 2018 02:40:18 +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 484F4CBE for ; Tue, 17 Jul 2018 02:40:15 +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 04F2F466 for ; Tue, 17 Jul 2018 02:40:14 +0000 (UTC) Received: by mail-pl0-f66.google.com with SMTP id w3-v6so3005054plq.2 for ; Mon, 16 Jul 2018 19:40:14 -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=OKaXusUnQe5dlKzeSIpnDtnMLWMbFPpZhrsBCbubC/+xviuCDUEfZgX/qNthuhH9k0 4a25FuzXirjugArQNRU/Hk3C14KJ25q4wnLpU6W3BU90O1o2v3boDAcVa5vt0OL42XPn AD/lRMsfw2YOoz8wdXTVk/3Qg97Z0XDDYeqwcRIU4YHdV48HkeMEEuOpRxhmuEacDmZR qf9BtyKtaxXqiCl/dO0Pu84xsfftSoYU6GqRrRNsng+eBMaPhIHjGHERYxgvK9ovkaWO wlYxkJSCCk8PJqtdvfHoAiAll4nMu/zSTohF+qYkL3GIIPT+Ad9lgFpfggURWw5xpqFr C7Nw== 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=rwVyVZEgQy6LTzsOiDmvsq3R8sjWE90VwzMCn1WHQcC7V/ibcoHfvbilkOzFQ/saed weS4DdSzv1NL8+cAAmKDG5p+yDh0qYbNcwqkJvvprJ+qLAMcfk0+Zbk6iGyyj5Os3UIq 5QXT9OaLPLYvQjmdfpF6iwly2brizK6dsDPfsB/mCgLzFRRArJ9ZyxnyyhwiGC/oI71Y t875TT+Rti7tS0lDI8O0bmMdeh1C2Z0S+G3G4pt4LeuD6whOJK1LE7RE6z3YsSrMSfeD QGI6GyM5mSO89caNd2Nm7ogyCL+4ou1hEEh7oqDblHpMzIyYR8gPYRVhuTN5R+1KOXGj wCvQ== X-Gm-Message-State: AOUpUlG5DFBNvyyPu4BuBM3aJzAumWmq/Xf3+iuJ1d+yuuvp96OrEciS FOt01JGH4VCcoug6MakyQEM= X-Google-Smtp-Source: AAOMgpd1V2lswfjCVbrr5ZRDox4b4IFFztaSTc2xFIM/4WEjAQeUcyTd8FM3CAa3etd5yVUcbnjJ7Q== X-Received: by 2002:a17:902:8ecb:: with SMTP id x11-v6mr19459756plo.308.1531795214687; Mon, 16 Jul 2018 19:40:14 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:13 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:43 -0700 Message-Id: <1531795191-58140-2-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 Tue Jul 17 02:39:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944681 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="hxXPDJeO"; 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 41V4KM5b05z9s0w for ; Tue, 17 Jul 2018 12:41:11 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 230C8CC7; Tue, 17 Jul 2018 02:40:19 +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 B8135CBE for ; Tue, 17 Jul 2018 02:40:17 +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 5614967E for ; Tue, 17 Jul 2018 02:40:17 +0000 (UTC) Received: by mail-pf0-f193.google.com with SMTP id k19-v6so1886418pfi.1 for ; Mon, 16 Jul 2018 19:40:17 -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=fTZnzOJq4CQs+mf0nffqwcwZGVk5UiVgeMTKr1pzSCM=; b=hxXPDJeOYkncyeBkxTbJy9wXAdH8KQt6gy6Ndo6xZV6SQKqMq6L/UZZ9USblMo+9Yz uNaUcBR3qC7cuG8OfFIUom3ZOgNufEs/T7XZ2NdYONGfpANlSfaN3j15IBSyEKjC+g+p ML259ZBMY1uATYsw8uI+zQ7DlPfH8+Ym/ZUyew92X7Zt8Ees1wyVXuUVBKlEajKEQ/7L MUEu4cGO0u/OtGyEMre2Dr2zYzJfJoQwJ8H1S28sWXMKp+Yv7iuwRIG7TOpXDEPqQvKY +khea5jBf0T4TOMPqO881CSdwHm1yQKeMnfT2qnRU5C1iizOo0Bkok0WjTx81GJg2NtY bpvQ== 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=fTZnzOJq4CQs+mf0nffqwcwZGVk5UiVgeMTKr1pzSCM=; b=NvjphqXB5Q1eoxc4XXES7O+dC7UbajzVBkxHCu5mP1hXtlGhMt0KfWefDNwlksqAlG ElIAgWncrbG1AE+0k+uek8Efnq3mh8E1UKtSc12P85Xbx6srYQUAyX6CRm6siX3NvgN+ +hUxT3NFJtFCK27e4NdqX0yOkj3gRG/0qBio2YxypXJAvHQJAZIrtVCl/BebhkPwXe/a 9jymUqO7XcPKQ/kRsezeRodqfmg44fsN9y4xWSfqBIV24/m+HKR5PqEYMwnsyR06kNYL Og+BdCYS+p5vLJh6aJ/hGNks649PxUzUZ+WdEv9e1u+UtmYx7f3wzuldO5XRZUP36e1C OBWA== X-Gm-Message-State: AOUpUlFEaj1oXOiA3Zwl4NvKRC8aRHruwrFDoV4AR4Oa9+TCcKnJndjd +YacAd6jRiIpg+OPOBPUXbvZpg== X-Google-Smtp-Source: AAOMgpd50ez2o8eLZG0huk9vnkmT4rV0Xwc1JsN8VZl3JuwFy9SFIsUSejEEOPXeWEefbTJBHIdKXA== X-Received: by 2002:a63:1644:: with SMTP id 4-v6mr18046603pgw.103.1531795216718; Mon, 16 Jul 2018 19:40:16 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:15 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:44 -0700 Message-Id: <1531795191-58140-3-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 974f985..682feb9 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -1310,7 +1310,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; @@ -1558,7 +1557,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 76a8b9a..e84a40d 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 Tue Jul 17 02:39:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944686 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="oEmX4T+1"; 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 41V4L73TX1z9rxx for ; Tue, 17 Jul 2018 12:41:51 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 1E911CD5; Tue, 17 Jul 2018 02:40:21 +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 1A1ABCC6 for ; Tue, 17 Jul 2018 02:40:19 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f68.google.com (mail-pl0-f68.google.com [209.85.160.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id DBB8B67E for ; Tue, 17 Jul 2018 02:40:18 +0000 (UTC) Received: by mail-pl0-f68.google.com with SMTP id e11-v6so3170286plb.3 for ; Mon, 16 Jul 2018 19:40:18 -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=O5t82OmDxHtvCSGePYMj9J+6rZ0aw0wsyASreOUVk8k=; b=oEmX4T+1l5i218J/2QzQcOS0p7TEIwUfZGq7d3/mU8cG/BES8vjL1Gg492eZA+GdXx QdOrQxlmEJNiGIiutWJL2GYJh6kLCvAjoD6uQosqZP+dPxQ/F0r8CVgWuro95yoPlAlY TJhxwXkta/ugRnSBovkKY4pqna2ww/CSxTrMgZfhg2fWu1sqjpu1GDlqJ9ggL7tVvc3M Qhc47hkHd5xUbvCcoXQdlmrljMR0LdrzkEXDeGbzY2A6qh2pKEUT1YCmlYRVkSLkIuVT DvbUZI+p7RyuQtB46/S1sQrWGgs3fSIrzatlG9/uHBoATvvEq22EQEfgJzI4amFr+FG5 nIJw== 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=O5t82OmDxHtvCSGePYMj9J+6rZ0aw0wsyASreOUVk8k=; b=Qinyt0kLKekfVJzHiE8uOvdlFXPje0w2eQIxUbis0xsOGin+bvGo2OISuYDg0EZOsD jaziSIVq84ebmXqh0zLJtjNeP4roTyqbRGCyYpe4GxaNtTLeWaQzlzJotar+qyot5PXb BbZsqBMv+/uXxN8mYPDjFj5PfIUalk80D1GfETtPqNZzOJzw+88KA1w1iBuDgGurGTX8 NLZPhNEgLQDQX5x40QZ6eF//zyPCB1NDGbaEvguL6G2QRqasYMI0QriW2bMs/jJPndHQ Fja6A5SGjZJezlprsaDiusRO1z6cYPrsnbaRuCsgNwVwNChNk8r7WOptxcCWNYVBKkqt FZPA== X-Gm-Message-State: AOUpUlHq/Pb1zZhB9RHG7PetyUrsGTKyTUG8PrgkzM3bteg8inG+5eKE yhUmSyUPR5r6QVvtI6cOIVI= X-Google-Smtp-Source: AAOMgpdd2Xij1niaVyEGWu6SEk1+nS6PXh+YyxWP049MDzMl7ljDDNMMETjxPpzGWHXgPhPV2iuzqw== X-Received: by 2002:a17:902:e093:: with SMTP id cb19-v6mr19184881plb.189.1531795218586; Mon, 16 Jul 2018 19:40:18 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:17 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:45 -0700 Message-Id: <1531795191-58140-4-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 cbd9542..43a104d 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 Tue Jul 17 02:39:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944687 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="qJUWe9gc"; 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 41V4Lc4dJzz9rxx for ; Tue, 17 Jul 2018 12:42:16 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C8E9ECDD; Tue, 17 Jul 2018 02:40:23 +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 C1966CD2 for ; Tue, 17 Jul 2018 02:40:20 +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 826AD6D6 for ; Tue, 17 Jul 2018 02:40:20 +0000 (UTC) Received: by mail-pg1-f196.google.com with SMTP id g2-v6so3452730pgs.6 for ; Mon, 16 Jul 2018 19:40:20 -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=jHN5r3p3iVK/juJFFqx/YDI7PfXp19PPC/7WlqU5+lg=; b=qJUWe9gcB9rujuil/soMyPvpxsqoZfM4GjhtHDUf/b+WwliGQJKn6IN6ScOaC5+L5H f2Uy7E9JSD9z/Bbq5CDFwM7n2XjHbXgmsbEsw6rbQWH+mCz0GlhJ8R5CG92ARBA506RB nAKqX+vAhcG3gDlEiftVGIzeNlEQfIbBIz8fbUTxvA/k4OeDPM6bzLLQUvMV+9iqWT5v kNc5RpEfP8WpsxJXClhzhyyig5NeXKkapb3eDIRWnCKLowbvf9lcsudd5K4/Lo4EBO8x 7xRHn3/TXiluZjRU80MRlF3sUuhRBXmzHRqP+olCSXLOpGDAa2dAxb1Q/NZfmsUAOvT8 azEQ== 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=jHN5r3p3iVK/juJFFqx/YDI7PfXp19PPC/7WlqU5+lg=; b=TZ3Q3T0sK835DrZXGS2f53VloaNN89cDpxpEj0leZorqdsiYE/l39/8NAn1NilrvyS KnUTEP09YtJqdrU9ch8OFQsZudZ9ia91Wi8XBnaJYF4SkFiszqPNGrNUWSRdjSjU+klO NX5bElVvu7gespiZyRCESjJQEuLSm+0smni+qky9UWPo4G14Fsk8yfPCgx+tPw3b5hkQ 4xpNoyoPArIjgvW25dQfZyowhV3PdekXOcBY5MHubA9OMX+6zUkuPoJhCwFVmcbsCfnL 9btyDsCXQZNJE3BM6zW1mRMkjwecefuHQQXoLVTHi7BVcvgPMd7bz4WQQyQHPWSzvhJl dZ2w== X-Gm-Message-State: AOUpUlGZ7yRqZ1Gl7OAI5VtDaygpkF7nNQJ/zj9d9PfGATJsvOFwCcsh z15PUAhx3NBBVFgZwY92rk4= X-Google-Smtp-Source: AAOMgpeOL/LaSrTq2+uQuqF9LH7/cZbahF14Yb2ePy1LJ/hmO0TkTgpCCbgJz3DnO5MTUQItvQ/q4Q== X-Received: by 2002:a63:5350:: with SMTP id t16-v6mr17380257pgl.196.1531795220307; Mon, 16 Jul 2018 19:40:20 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:19 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:46 -0700 Message-Id: <1531795191-58140-5-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 682feb9..3f50fc8 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -1294,7 +1294,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 Tue Jul 17 02:39:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944689 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="Ck2qABYf"; 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 41V4MT2h29z9rxx for ; Tue, 17 Jul 2018 12:43:01 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 66FA5CEE; Tue, 17 Jul 2018 02:40:27 +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 15703CE5 for ; Tue, 17 Jul 2018 02:40:26 +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 30FBE6D6 for ; Tue, 17 Jul 2018 02:40:23 +0000 (UTC) Received: by mail-pf0-f194.google.com with SMTP id q7-v6so26146323pff.2 for ; Mon, 16 Jul 2018 19:40:23 -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=6KCGn6lhhYhylBjaclBDYd9RfK8QttEXvcsf2g/McBI=; b=Ck2qABYf+Ks5ArRpwrTrWoNNxvxGJpqnPosZl+aNvoZv8WQ6eJA+Wh6JPyIj90gG+c robNjnsv73TMJJdcBmR69wrda4hQ9z/6tgvagRqB8WIb1rg9Z34F0Ffd2+zuCTfHYLBm +GYCXjGjuywEJDCZ4nqDbUnCYegC9wl1r01bwze1NojNe4p3tJPikUIQSH9anmFQo9ZH Eb947W/mnbSgzFa6uv3asfPBpRNVe6DpJPnNKVK58cIvRyYPiPCGj3hkxr66stfuofC3 Hn8RV+mttCZZbc5M0gugTUcDfF2ylM1X4EDGslxDpNo3Am64b47er5QqRZbaSPt0FmmQ t0Ng== 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=6KCGn6lhhYhylBjaclBDYd9RfK8QttEXvcsf2g/McBI=; b=qL0uNR5lIj+n6Am1g+B/CtonRfnJeOIo9UxDbDk2Rhvvo/S8ANwy16O1MCvDGaWtfV WNr8ocrXBQZakvS+Iygad7G7148rZwD60nCzMmnWLrYN8fbaq8EjQUqbXJX53wZ1CO7V 9tSwEyn5nGiia+P00cVBMxmfcWebN5SejbI675pzBJbwobJdVm9oYh8ZSKomZVn/OAfh OaPAbCtIlJzjP1I8qlcNZ6GSMDRCjrh4YjLKO36vg1HzwaLMMpkQ4wuv/p7o0NHqJO/1 CvWTi6zl85zJAo2W3iStA65+PWLjPUKZuNM4ASX5MxgMqoz0bUyRPWFS4QwzsBfcFNSk eLtA== X-Gm-Message-State: AOUpUlHrwG5MWkYWzGLEHOgpUNLlmQowxzr9J1LW2RPphUgpFJuKYC+u 7Cx7iUK+zXsNAhFyU/+ewAlLRw== X-Google-Smtp-Source: AAOMgpfYCcMkmLA8o7wwfbFQnelX/EOgT76lP6XJzsDb3HHS162eH/cjaWriAsDJ3h91nA5dA3TeoA== X-Received: by 2002:a63:6d8b:: with SMTP id i133-v6mr18013953pgc.215.1531795222193; Mon, 16 Jul 2018 19:40:22 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:20 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:47 -0700 Message-Id: <1531795191-58140-6-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 | 1299 ++++++++++++++++++++++++++++++++++++++ lib/ipf.h | 60 ++ tests/system-kmod-macros.at | 10 +- tests/system-traffic.at | 30 +- tests/system-userspace-macros.at | 26 +- 9 files changed, 1398 insertions(+), 45 deletions(-) create mode 100644 lib/ipf.c create mode 100644 lib/ipf.h diff --git a/NEWS b/NEWS index 057e8bf..9c82234 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 3f50fc8..be8debb 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) @@ -1295,7 +1298,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 @@ -1310,11 +1314,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; @@ -1323,6 +1330,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..1169a8a --- /dev/null +++ b/lib/ipf.c @@ -0,0 +1,1299 @@ +/* + * 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_is_valid_v4_frag(struct dp_packet *pkt) +{ + 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_); + bool 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); + } + return true; +} + +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) +{ + const struct ip_header *l3 = dp_packet_l3(pkt); + uint16_t ip_tot_len = ntohs(l3->ip_tot_len); + size_t ip_hdr_len = IP_IHL(l3->ip_ihl_ver) * 4; + + *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); + *lf = ipf_is_last_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_is_valid_v6_frag(struct dp_packet *pkt OVS_UNUSED) +{ + 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 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_); + bool 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); + } + + return true; +} + +static void +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 ovs_16aligned_ip6_hdr *l3 = dp_packet_l3(pkt); + const char *l4 = dp_packet_l4(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; + 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; + parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag, &frag_hdr); + ovs_assert(nw_frag && frag_hdr); + ovs_be16 ip6f_offlg = frag_hdr->ip6f_offlg; + *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); + *lf = ipf_is_last_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; +} + +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); + + if (v6 && ipf_get_v6_enabled()) { + ipf_v6_key_extract(pkt, dl_type, zone, &key, &start_data_byte, + &end_data_byte, &ff, &lf); + } else if (!v6 && ipf_get_v4_enabled()) { + ipf_v4_key_extract(pkt, dl_type, zone, &key, &start_data_byte, + &end_data_byte, &ff, &lf); + } else { + OVS_NOT_REACHED(); + } + + 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) { + + if (OVS_UNLIKELY((dl_type == htons(ETH_TYPE_IP) && + ipf_is_valid_v4_frag(pkt)) || + (dl_type == htons(ETH_TYPE_IPV6) && + ipf_is_valid_v6_frag(pkt)))) { + + 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); + } else { + dp_packet_batch_refill(pb, pkt, pb_idx); + } + + } +} + +/* 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 43a104d..556a6a0 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 Tue Jul 17 02:39:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944688 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="N2J3C/XT"; 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 41V4M23wl4z9rxx for ; Tue, 17 Jul 2018 12:42:38 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 8F39BCC6; Tue, 17 Jul 2018 02:40:26 +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 29A74CC6 for ; Tue, 17 Jul 2018 02:40:25 +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 5B46E67E for ; Tue, 17 Jul 2018 02:40:24 +0000 (UTC) Received: by mail-pf0-f193.google.com with SMTP id a26-v6so5172271pfo.4 for ; Mon, 16 Jul 2018 19:40:24 -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=sK/iJRqyZaZEorKKailHaFdyUwCr/pybzGYRRzuHILs=; b=N2J3C/XTyWLVBc+b0O8B9ywb8IcXHNlqAjIp5yMfpyDe7rGTNzMzedJ/ng4kjuh0zf lDiJn0f4e2gBN6vQ3tn6OcsZv4wvi0h/a30IH+TdL7XsJjPXWrDQy9kvsBzawDzdPH0N tSlLpj4nDnhnUEZqa9409c/XRtBV1asIJ7M3gJJ93wmKRl6FG9gRmyjRirLoRnAaJq91 b6cLUJ1FUSqptLN+GD89iHIt7Zz3IHvNIudm9amA8ibzEPFFS3RdZAKnF2wHLtHKzQx9 fmKEVU0LnWQhrOB9/e6KAYjZauCY9v/aonVNp7XHigEzWQyX96xy8CxpHVc3j2MqheSd WX4A== 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=sK/iJRqyZaZEorKKailHaFdyUwCr/pybzGYRRzuHILs=; b=NN9EB0PmpkXcEt0avtKNxMRJvjtGJiUCMqHWg/jCuthLw9L7vmxR2OX9v/6KwMBxOf DqgFKPtQxVzh9OV7u7KS89oK2s8jlemtuRq6h13VcZN6jb7zUhkrPIBTtX2afv2ZSFvz PLQI2Vq7iSyveeMLWxxuuRB3yvayucto6BkPQEB8L9dbG2o4mHaVWrHseJZk7mSiKFLX sLRV26YEL9FBJENkrtCT9GStYfz6KCA/4wPFrSdzKLaw+5aJqnauvl85NFey3NSKIO5i JXBdb2kuweGD+4p27uulQfj3PPesN7eRXfsxboepXwgv6qPxtp+7Ga3FvTJDxN/YRrM7 jVjA== X-Gm-Message-State: AOUpUlHUvAeErVWG5m/YdGmATXoZu9NMkv3z8M1EB/DiEosAsQOhxq6A 6Q6mIgvm6ZQ5ob+CEfrmK4E= X-Google-Smtp-Source: AAOMgpdBPVNrmdjYddRmSUkXZt2flTOIgjMpd0BprJWve/cTaDggtoc7Oo3VSSfT4SS8oIedaijkXw== X-Received: by 2002:a63:5a5e:: with SMTP id k30-v6mr18064490pgm.123.1531795223939; Mon, 16 Jul 2018 19:40:23 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:22 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:48 -0700 Message-Id: <1531795191-58140-7-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 9c82234..104b16f 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..d6800fb 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 - 1], "%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..a1eb026 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 1169a8a..cc76c99 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -1297,3 +1297,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 Tue Jul 17 02:39:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944690 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="GbyQqRg/"; 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 41V4N31Qbrz9rxx for ; Tue, 17 Jul 2018 12:43:31 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 8806ECEC; Tue, 17 Jul 2018 02:40:30 +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 D45F5CEE for ; Tue, 17 Jul 2018 02:40:26 +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 483C9466 for ; Tue, 17 Jul 2018 02:40:26 +0000 (UTC) Received: by mail-pf0-f194.google.com with SMTP id a26-v6so5172313pfo.4 for ; Mon, 16 Jul 2018 19:40:26 -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=90hrkEPFEGQ1wvA7+iHNMISvY0rovRjtSDT5HEjs2iY=; b=GbyQqRg/ylideEu2z2+eJzeSKL1L1YfPdAf1PUXsPDlbBFAYsdjWE421CVSfDjhjff xz186WbCBkH5Z8wKQNx67G0o6S0E7FPgYLXyRnrxmWrOpFs/H9qj3LziOMA2hJiQIFNf 9HieDFfiltZcclrXOsfRoxEbrclCjSd0Uvi9dCE7+v0Y435sXg/mSsWCCBbtC2vjRRyL rrQ87lR5gwsm9bf73x28REq8JYV4L0xOSNQbg8OU/q0j2FaxHbZkf1HchI4yw2iqN8BU I2qHwXsEgqC5NYPEL4vwLT5+Kgq3XBqijIFIQ4sJSERZLe6Goc0fF7NfUNUMKyz4F2ym CdGw== 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=90hrkEPFEGQ1wvA7+iHNMISvY0rovRjtSDT5HEjs2iY=; b=t1POJWF5qYdLw0NfIL9RzPo//9D+HHEUGS52NTgAYoq80Wgezuc2J2GH3mjK16RaXA 6YcN/rHxTdPs2+JrDtCMpCrQCU5BM/XIsHdHFBJK4bLmS1XTDVCun28ciBRffD8jvoOL VN65xyHj7Bsa5NseueWeowzIu7+MVWcaIxsn7K1bw7cq4vNemjln3TbEsd8sqWjDtRcs qUMmS3mEnB3pK0BSWzTIEfda1Q+bKhfcR2PhhhWvvRHymExdEffzlzSIwg8Dyykazr4j +OvFfQMdmfQ0ZVFcuH/TzN44uF0xXdGsYCzHf+G53rAggzEM5uBnDKRWMnUV3lYG7rNQ DMTA== X-Gm-Message-State: AOUpUlE6PTbI6ltHqbbPZCv0IBft06cYbqy2J8yUZT64qspfOuYWt1F2 /9JApAu3A/Omq6qpk87r0FE= X-Google-Smtp-Source: AAOMgpchxLotmqbp/DoX4tZvhgcPMtdXEt9M1pCGv3LfmX1C36ZGCjIbNiBgUPDLa5IajG00FABhUA== X-Received: by 2002:a62:a119:: with SMTP id b25-v6mr20203670pff.163.1531795225838; Mon, 16 Jul 2018 19:40:25 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:24 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:49 -0700 Message-Id: <1531795191-58140-8-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 | 2 ++ lib/dpctl.c | 40 ++++++++++++++++++++++++++++++++++++++++ lib/dpctl.man | 9 +++++++++ lib/dpif-netdev.c | 8 ++++++++ lib/dpif-netlink.c | 1 + lib/dpif-provider.h | 3 +++ lib/ipf.c | 23 +++++++++++++++++++++++ lib/ipf.h | 2 ++ 10 files changed, 98 insertions(+) diff --git a/NEWS b/NEWS index 104b16f..84bce38 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..6eb55b4 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" @@ -201,6 +202,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 d6800fb..716862e 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 a1eb026..a75fc77 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..62a4574 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 @@ -446,6 +447,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 cc76c99..e3a84c0 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -1304,3 +1304,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 */ From patchwork Tue Jul 17 02:39:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944691 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="OHmQlfnR"; 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 41V4NT2fl2z9rxx for ; Tue, 17 Jul 2018 12:43:53 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 50727CFC; Tue, 17 Jul 2018 02:40:31 +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 B6C98CCA for ; Tue, 17 Jul 2018 02:40:28 +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 1C168780 for ; Tue, 17 Jul 2018 02:40:28 +0000 (UTC) Received: by mail-pl0-f67.google.com with SMTP id 94-v6so4208694ple.12 for ; Mon, 16 Jul 2018 19:40:28 -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=pjUgnTLDJ8rTB129ZlDzFIHLVESN/7BJ9HbK7F2oUvQ=; b=OHmQlfnRICNHgRW2GNU1CV6tBmdL6lcA8qTjAujj+xbFMCUYyyrufv2HuIENhZE2+5 v8IizDawk5NG5K2xytGNymz/19u+eCW9IC7kdv5D4QGRDK1GhxjmlgsJFRKkRiDMy/cn Z5L7Fxi/AjoDvM0pORefCb5RUlCA1J+9N+MgHMB2ezvCOcJxQxEk8GgmeaT0/Xcg4V2o VQF7R8y57pHUTbnVHMIm78K/6AJVHlk4WnfL2bxE1PQksU6Kgv+Mc0zHi8ijVHUdPJ6j sI3lNCMsSWZcdh2uUf5XWDTS8VnUUzpRI1YaI0Ock+00NyZfDOB7rd3sIUvhf9zQ3vpc A0Bg== 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=pjUgnTLDJ8rTB129ZlDzFIHLVESN/7BJ9HbK7F2oUvQ=; b=dc0dL7qWeNhqc3tdJ4VT4Ny2NcjZfYsw6WfmZpSRR2mbaNPwyrU0D+zPCLZJa2yoFP CEEZMfXGWsohoBlGBgL2C15VrnxbNKw1y8iHi+yuKY/Q2Ez2K69UHamFLb9iTF5es4Kr e7wqAL9YianQc6z+PjW7LcVEyzzd/hfYG08uLMfrWlFWJYhG6nZO93aEP/HHNUK/DIaF Bv7+TZQvL3f1mLv65GuQL0GD06uEOQxQsw6T9JfLv+lMoAvGWsKM1o0tbyfRDCM/8ga5 wfq3X/FVhBWFCsj617SPjRc2Qm6mYzTc8iN+V7FGrCedEUio/toRR73iXW/rHslC81a2 AouA== X-Gm-Message-State: AOUpUlFnRGuWqzusYlQ/T57ACgr0nyCUvXJ95pn1OG5KTtxEMOs1LSZ2 CKxW/M3EaR8iINmRbyFffEf+Vw== X-Google-Smtp-Source: AAOMgpemyALqeQ5ISzpKBFsycI7kggKY4SyTfE+CvaI/V303K5iXSKbP4Vv9i+asgwluPXBQs99Osw== X-Received: by 2002:a17:902:aa01:: with SMTP id be1-v6mr18984890plb.296.1531795227716; Mon, 16 Jul 2018 19:40:27 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:26 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:50 -0700 Message-Id: <1531795191-58140-9-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 84bce38..6b82ebb 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 6eb55b4..f886ab9 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -203,6 +203,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 716862e..5ec36bd 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 a75fc77..f5a36b0 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 62a4574..214f570 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -449,6 +449,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 e3a84c0..b1d9a11 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -1327,3 +1327,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 Tue Jul 17 02:39:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrell Ball X-Patchwork-Id: 944692 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="bQO5IXCN"; 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 41V4Nw2PFwz9s1R for ; Tue, 17 Jul 2018 12:44:16 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 12C2BD08; Tue, 17 Jul 2018 02:40:33 +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 D7F5CCF7 for ; Tue, 17 Jul 2018 02:40:31 +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 3F619466 for ; Tue, 17 Jul 2018 02:40:30 +0000 (UTC) Received: by mail-pg1-f196.google.com with SMTP id z8-v6so6818191pgu.8 for ; Mon, 16 Jul 2018 19:40:30 -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=VfBzpoptQ8B7JIs8B2+Q66ipMWKa/HHLzXafOK2KYjU=; b=bQO5IXCNN47CYIXWyt9tXtgzti8sQ9eMdE2/OAMwhbSlXlPikXxFXmDQ17K80kXrcW 8kCYGZ27wv5AD49T9HMcmDr7YGIKdemOdGy467sVTO9OBoLTvZ+ANtX+c9Irw9MbqTEI QLLtgWcAwouEGpvwv7M1gcEsY/5OufpXUygYHstHsrFdP3rt9ssRD8lOIR/CoFuXowik IfiuAdzvNWG+z3kMSqZ/Ot1nLShc75TfbYK9eOiLLwsBuYJLkllphKGSldae7Zadapf5 W3xnMj23aVpqVlLnSQLgqxxvNLySobCTaxYW4qF0mTKNo5CHmdLZxXAU+1UuzOb7Ydw9 Fuxw== 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=VfBzpoptQ8B7JIs8B2+Q66ipMWKa/HHLzXafOK2KYjU=; b=DYNoBYm338B+ceOl4GEeRo9rbblLXsNPDkXifvr41TJVleEnXIiW+lfXKeLSLBUpUP ZXA5+7KM3pfBHK4t+sEVA6wY1rp1fcActS07DQ/Wec9CCEp7E0zsIqeAc5DQphDqCSER YNvXnlnPNga2XLPwV6ZnV9kjfLrcDFZOVvkqVsU2t9UeiUBYKXd9boIB8qwz1M6XWGVj w0Go590AhyZMRKPX7JFmtIVIAunvXq2X+Ot/Q3ZdLrnwF+h9m9jvqyD1pxMIcJHL+NEN w3Khcwy7xqULdsPft4foA6GYdnj5SRoe6amYEXkYf8CtxIpq3DPdrm4Gue6rvTQ8qtZz fwXA== X-Gm-Message-State: AOUpUlFYWm5hMhUjQE+JjDDWAJpaOmePZVuEfmD6muVX5DAUCDkJl90e PtggU/HF4NeaoISxE2oqlaQ= X-Google-Smtp-Source: AAOMgpe12DKISubTwoDiy77ktxGgfMLyD7LDHGAW+PJRohkh4fCRL9RY2IonLMkv9O/EllyGopbCnQ== X-Received: by 2002:a62:398c:: with SMTP id u12-v6mr20617613pfj.9.1531795229552; Mon, 16 Jul 2018 19:40:29 -0700 (PDT) Received: from ubuntu.localdomain ([208.91.2.1]) by smtp.gmail.com with ESMTPSA id n9-v6sm50224487pfg.21.2018.07.16.19.40.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Jul 2018 19:40:28 -0700 (PDT) From: Darrell Ball To: dlu998@gmail.com, dev@openvswitch.org, jpettit@ovn.org Date: Mon, 16 Jul 2018 19:39:51 -0700 Message-Id: <1531795191-58140-10-git-send-email-dlu998@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1531795191-58140-1-git-send-email-dlu998@gmail.com> References: <1531795191-58140-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 v8 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 | 9 +++ lib/dpctl.c | 107 ++++++++++++++++++++++++++++++++++ lib/dpctl.man | 6 ++ lib/dpif-netdev.c | 58 +++++++++++++++++++ lib/dpif-netlink.c | 4 ++ lib/dpif-provider.h | 16 +++++ lib/ipf.c | 107 ++++++++++++++++++++++++++++++++++ lib/ipf.h | 10 ++++ tests/system-kmod-macros.at | 32 ++++++++++ tests/system-traffic.at | 40 +++++++++---- tests/system-userspace-macros.at | 122 +++++++++++++++++++++++++++++++++++++++ 13 files changed, 548 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index 6b82ebb..b9f0959 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 f886ab9..2ff7e26 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -204,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 5ec36bd..b3e7ce7 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 f5a36b0..1074963 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 214f570..2e0d596 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -451,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 b1d9a11..44f2cd4 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, @@ -1337,3 +1341,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 3ea5b87..736a643 100644 --- a/tests/system-kmod-macros.at +++ b/tests/system-kmod-macros.at @@ -130,3 +130,35 @@ 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], +[ + +]) + +# 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 556a6a0..2a5bdb6 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 @@ -2056,6 +2074,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation incomplete reassembled packet]) CHECK_CONNTRACK() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2077,8 +2096,8 @@ 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() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2101,8 +2120,8 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2125,9 +2144,9 @@ 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() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2149,9 +2168,9 @@ 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() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2348,6 +2367,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation incomplete reassembled packet]) CHECK_CONNTRACK() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2368,8 +2388,8 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation with fragments specified]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2392,8 +2412,8 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2416,9 +2436,9 @@ 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() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2442,9 +2462,9 @@ 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() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2468,9 +2488,9 @@ 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() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2494,9 +2514,9 @@ 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() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at index 40b7567..fcae3cc 100644 --- a/tests/system-userspace-macros.at +++ b/tests/system-userspace-macros.at @@ -119,3 +119,125 @@ 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 +]) +]) + +# 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) +]) +])