From patchwork Mon Jun 21 10:06:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Valerio X-Patchwork-Id: 1494995 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=JqJLQT0t; dkim-atps=neutral Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G7lYM3mBYz9sRN for ; Mon, 21 Jun 2021 20:06:31 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 3DA994022E; Mon, 21 Jun 2021 10:06:29 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id W83nttA6XyKR; Mon, 21 Jun 2021 10:06:28 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 4E9A9400EB; Mon, 21 Jun 2021 10:06:27 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2A74DC0010; Mon, 21 Jun 2021 10:06:27 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 24DC2C000C for ; Mon, 21 Jun 2021 10:06:26 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 1338C40326 for ; Mon, 21 Jun 2021 10:06:26 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp4.osuosl.org (amavisd-new); dkim=pass (1024-bit key) header.d=redhat.com Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id CRsG_ckxvCoc for ; Mon, 21 Jun 2021 10:06:24 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by smtp4.osuosl.org (Postfix) with ESMTPS id 97C2940323 for ; Mon, 21 Jun 2021 10:06:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1624269983; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mZPsXq9v9ov4op8KQyEY9te/h6hAp0b+auz/5Z5pi+g=; b=JqJLQT0tQUeHqxxKAXKU1jNRtjFgwWBivGUVWkmddHEqW11r0uD/VLai8OPWMpxX3eYbeA a3iHFdX1zwW6llvG3V7tRubn9BXpz58D8cvT/t3OYMFqmq5sHRyTUGu8As8sQ7wXa7vK75 YevIIjX1e3VjdJuJI8TzGusBeHzXUo8= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-325-C4db3h3iMk2pEDWf1XdmgA-1; Mon, 21 Jun 2021 06:06:18 -0400 X-MC-Unique: C4db3h3iMk2pEDWf1XdmgA-1 Received: by mail-wm1-f72.google.com with SMTP id u17-20020a05600c19d1b02901af4c4deac5so6832701wmq.7 for ; Mon, 21 Jun 2021 03:06:18 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=mZPsXq9v9ov4op8KQyEY9te/h6hAp0b+auz/5Z5pi+g=; b=SmQsT+S5WZVHPw6bNVwzYG1nHmQjH0aWNbXtRkKBIHohkNHzEir0KHiqJBdsUI+M3y FFDW2Mu5HGfhjAQCUL02oHNz7jg7diXF0n54PdUunq0JUwPChyn+4raC+RiiWMT4VqD9 n09uuA2DWvgXT3hMM10WmrMsavXi8vwCIbZnjryLE6YjhaIrfQyA4BHPvLvYL8ejhGGZ ihVMCiayYlz4kJBwjRBs8HOO3pvyjGEpsfNLE4kMFt+GIImay2yzHtSz84cygN7JcR+Z 2FvTN50JQFPYcemPkijJ0Bsj30Y6HvN5jzWuOoyHXVgnhY4i+TPUv1ctpsjm4S6XfZ9u PwzA== X-Gm-Message-State: AOAM532bQfT4Fu5UhW2eJuBp/3MDkQDtMVH7IexjwKuNz//ejICV8Ekh oTWJhRRJhXuZnmVrEJ+5mxjtNe6hO5g+6bskPURpo+AT8YNtljV9FjcUSsZO6gpFBbC2lIvBBNx IHgWpS3lWVJT1uIVH6emLjNTToCXJtHlYNYRgzeMg4vpopmpjmF24e9bLmJrA04sY X-Received: by 2002:a1c:6485:: with SMTP id y127mr26575799wmb.110.1624269977391; Mon, 21 Jun 2021 03:06:17 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx22ziJA6ULi6fX5A6YOA6CpqYeVlAXbvU0lBudw3GBs9zcXJLt71h1+6HkTlNo34bYrI/QNA== X-Received: by 2002:a1c:6485:: with SMTP id y127mr26575774wmb.110.1624269977171; Mon, 21 Jun 2021 03:06:17 -0700 (PDT) Received: from localhost (net-93-146-7-51.cust.vodafonedsl.it. [93.146.7.51]) by smtp.gmail.com with ESMTPSA id j188sm18780319wmb.34.2021.06.21.03.06.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jun 2021 03:06:16 -0700 (PDT) From: Paolo Valerio To: dev@openvswitch.org Date: Mon, 21 Jun 2021 12:06:16 +0200 Message-ID: <162426995381.3650320.3787574219707223161.stgit@fed.void> In-Reply-To: <162426992691.3650320.15060936163617998030.stgit@fed.void> References: <162426992691.3650320.15060936163617998030.stgit@fed.void> User-Agent: StGit/0.23 MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=pvalerio@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: i.maximets@ovn.org Subject: [ovs-dev] [PATCH v7 1/4] conntrack: handle already natted packets X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" when a packet gets dnatted and then recirculated, it could be possible that it matches another rule that performs another nat action. The kernel datapath handles this situation turning to a no-op the second nat action, so natting only once the packet. In the userspace datapath instead, when the ct action gets executed, an initial lookup of the translated packet fails to retrieve the connection related to the packet, leading to the creation of a new entry in ct for the src nat action with a subsequent failure of the connection establishment. with the following flows: table=0,priority=30,in_port=1,ip,nw_dst=192.168.2.100,actions=ct(commit,nat(dst=10.1.1.2:80),table=1) table=0,priority=20,in_port=2,ip,actions=ct(nat,table=1) table=0,priority=10,ip,actions=resubmit(,2) table=0,priority=10,arp,actions=NORMAL table=0,priority=0,actions=drop table=1,priority=5,ip,actions=ct(commit,nat(src=10.1.1.240),table=2) table=2,in_port=ovs-l0,actions=2 table=2,in_port=ovs-r0,actions=1 establishing a connection from 10.1.1.1 to 192.168.2.100 the outcome is: tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=4000,dport=80),reply=(src=10.1.1.2,dst=10.1.1.240,sport=80,dport=4000),protoinfo=(state=ESTABLISHED) tcp,orig=(src=10.1.1.1,dst=192.168.2.100,sport=4000,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=80,dport=4000),protoinfo=(state=ESTABLISHED) with this patch applied the outcome is: tcp,orig=(src=10.1.1.1,dst=192.168.2.100,sport=4000,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=80,dport=4000),protoinfo=(state=ESTABLISHED) The patch performs, for already natted packets, a lookup of the reverse key in order to retrieve the related entry, it also adds a test case that besides testing the scenario ensures that the other ct actions are executed. Reported-by: Dumitru Ceara Signed-off-by: Paolo Valerio Acked-by: Dumitru Ceara --- lib/conntrack.c | 30 +++++++++++++++++++++++++++++- tests/system-traffic.at | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/conntrack.c b/lib/conntrack.c index 99198a601..7e8b16a3e 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -1281,6 +1281,33 @@ process_one_fast(uint16_t zone, const uint32_t *setmark, } } +static void +initial_conn_lookup(struct conntrack *ct, struct conn_lookup_ctx *ctx, + long long now, bool natted) +{ + bool found; + + if (natted) { + /* if the packet has been already natted (e.g. a previous + * action took place), retrieve it performing a lookup of its + * reverse key. */ + conn_key_reverse(&ctx->key); + } + + found = conn_key_lookup(ct, &ctx->key, ctx->hash, + now, &ctx->conn, &ctx->reply); + if (natted) { + if (OVS_LIKELY(found)) { + ctx->reply = !ctx->reply; + ctx->key = ctx->reply ? ctx->conn->rev_key : ctx->conn->key; + ctx->hash = conn_key_hash(&ctx->key, ct->hash_basis); + } else { + /* in case of failure restore the initial key. */ + conn_key_reverse(&ctx->key); + } + } +} + static void process_one(struct conntrack *ct, struct dp_packet *pkt, struct conn_lookup_ctx *ctx, uint16_t zone, @@ -1296,7 +1323,8 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, } bool create_new_conn = false; - conn_key_lookup(ct, &ctx->key, ctx->hash, now, &ctx->conn, &ctx->reply); + initial_conn_lookup(ct, ctx, now, !!(pkt->md.ct_state & + (CS_SRC_NAT | CS_DST_NAT))); struct conn *conn = ctx->conn; /* Delete found entry if in wrong direction. 'force' implies commit. */ diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 6a15d08c2..f400cfabc 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -4588,6 +4588,41 @@ tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src= OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([conntrack - DNAT with additional SNAT]) +CHECK_CONNTRACK() +OVS_TRAFFIC_VSWITCHD_START() + +ADD_NAMESPACES(at_ns0, at_ns1) +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") +ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") +NS_CHECK_EXEC([at_ns0], [ip route add 172.1.1.0/24 via 10.1.1.2]) + +OVS_START_L7([at_ns1], [http]) + +AT_DATA([flows.txt], [dnl +table=0,priority=30,in_port=1,ip,nw_dst=172.1.1.2,actions=ct(commit,nat(dst=10.1.1.2:80),table=1) +table=0,priority=20,in_port=2,ip,actions=ct(nat),1 +table=0,priority=10,arp,actions=NORMAL +table=0,priority=1,actions=drop +dnl Be sure all ct() actions but src nat are executed +table=1,ip,actions=ct(commit,nat(src=10.1.1.240),exec(set_field:0xac->ct_mark,set_field:0xac->ct_label),table=2) +table=2,in_port=1,ip,ct_mark=0xac,ct_label=0xac,actions=2 +]) +AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) + +NS_CHECK_EXEC([at_ns0], [wget http://172.1.1.2:8080 -t 5 -T 1 --retry-connrefused -v -o wget0.log]) + +dnl - make sure only dst nat has been performed +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.240)], [0], [dnl +]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.1)], [0], [dnl +tcp,orig=(src=10.1.1.1,dst=172.1.1.2,sport=,dport=),reply=(src=10.1.1.2,dst=10.1.1.1,sport=,dport=),mark=172,labels=0xac,protoinfo=(state=) +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([conntrack - more complex DNAT]) CHECK_CONNTRACK() CHECK_CONNTRACK_NAT() From patchwork Mon Jun 21 10:06:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Valerio X-Patchwork-Id: 1494996 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=PZSaMeTK; dkim-atps=neutral Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G7lYS1xhpz9sRN for ; Mon, 21 Jun 2021 20:06:36 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 204E2607FF; Mon, 21 Jun 2021 10:06:34 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id pG_ruO_YlKsH; Mon, 21 Jun 2021 10:06:33 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 4B1A8606BB; Mon, 21 Jun 2021 10:06:32 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 23E20C0010; Mon, 21 Jun 2021 10:06:32 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 23623C0010 for ; Mon, 21 Jun 2021 10:06:31 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 139026062D for ; Mon, 21 Jun 2021 10:06:31 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id QiHY06NTvqto for ; Mon, 21 Jun 2021 10:06:30 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id 62EC6606BB for ; Mon, 21 Jun 2021 10:06:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1624269989; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Lqd/WqDR/b2Eo1OZ4tYoM+J8xMTldY1ousX0lS+VSPM=; b=PZSaMeTKfvNXCDKYc0rstWsGqwr3Zsblwe6k94drowytfBcFaBhxIJXzd8jbijkAM9QeB+ Ryl/Lz4VH5LN+iuaozeiQ0nU5BYg3jJ9tlAEfUR9aNYEyaYlnRriF3RR6jeQwh/93CNz6z I0hQ99GHJrnc7N4Ai4TjtpagfWpHveU= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-26-zCHGnyAVOxKw57SveWXDeg-1; Mon, 21 Jun 2021 06:06:28 -0400 X-MC-Unique: zCHGnyAVOxKw57SveWXDeg-1 Received: by mail-wm1-f70.google.com with SMTP id h14-20020a05600c350eb02901dfc071c176so818699wmq.3 for ; Mon, 21 Jun 2021 03:06:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=Lqd/WqDR/b2Eo1OZ4tYoM+J8xMTldY1ousX0lS+VSPM=; b=EgtMjRsLAtx7Sg3hbhN7+fNgudPoByI2fgTJB+Ip9gZdqd/59X3IIXt4zN9CGaEtcu wsf62NwshJ+Du6pHUBpxVD73aXmRCilDR8pEVNBXmx3UIc5BIBIaTNhdVd1XTQY1KmzK 5ZnZZP/+6kotDV2LkJ5X8Xy4HyodoNJn96eIr9QqOBKqs7hz0FnM65XiBtSkq6btci1K SrPX7DZGN6h6KCidVQsYkOEYv7s5+znvrwYSV3CLCFyzF4OA1SKs2pavz/bWkiMEgZAX 0w0UBHT32xL3mBFQVUsznx5W+jJoYzv32sWbMfOl/P2wItYUsw2M/0m0L3OAphKwtic2 7iKg== X-Gm-Message-State: AOAM531o58V1oem3KliulI+QhpR7bLr8KcgCfWdQ5GblT65V1pXphJEb NegK6eMZv5Apr+/ln31Ap4RWyDV9hcsyg1sBd1pD5dG5NSHgkPPNxTEhIQsI1mtjrLSiT+cLnnl kZIe+PzjFtbVXBhqrPMIxxWaUoCdLc1raK1f+gF5KcUcPCIP80T4rnaEGdzT7t3Ai X-Received: by 2002:adf:ee4a:: with SMTP id w10mr27251925wro.381.1624269986699; Mon, 21 Jun 2021 03:06:26 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzCZZbDgNON26QpnyH/It2gb1KD0fV08ackDbywOUeiX/tTdciUneM3P19zNJLeaENPW6Pt6w== X-Received: by 2002:adf:ee4a:: with SMTP id w10mr27251904wro.381.1624269986499; Mon, 21 Jun 2021 03:06:26 -0700 (PDT) Received: from localhost (net-93-146-7-51.cust.vodafonedsl.it. [93.146.7.51]) by smtp.gmail.com with ESMTPSA id y16sm13626688wrp.51.2021.06.21.03.06.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jun 2021 03:06:26 -0700 (PDT) From: Paolo Valerio To: dev@openvswitch.org Date: Mon, 21 Jun 2021 12:06:25 +0200 Message-ID: <162426998225.3650320.13608181862583924371.stgit@fed.void> In-Reply-To: <162426992691.3650320.15060936163617998030.stgit@fed.void> References: <162426992691.3650320.15060936163617998030.stgit@fed.void> User-Agent: StGit/0.23 MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=pvalerio@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: i.maximets@ovn.org Subject: [ovs-dev] [PATCH v7 2/4] util.h: add token concatenation macro with argument expansion X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" this macro is handy when it comes paste two tokens when one or both are macros. Rename CURSOR_JOIN() to OVS_JOIN() and move it to util.h so that it can be reused. Signed-off-by: Paolo Valerio Acked-by: Gaetan Rivet Acked-by: Aaron Conole --- lib/cmap.h | 5 +---- lib/util.h | 7 +++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/cmap.h b/lib/cmap.h index d9db3c915..c502d2311 100644 --- a/lib/cmap.h +++ b/lib/cmap.h @@ -245,9 +245,6 @@ void cmap_cursor_advance(struct cmap_cursor *); /* Generate a unique name for the cursor with the __COUNTER__ macro to * allow nesting of CMAP_FOR_EACH loops. */ -#define CURSOR_JOIN2(x,y) x##y -#define CURSOR_JOIN(x, y) CURSOR_JOIN2(x,y) - #define CMAP_FOR_EACH__(NODE, MEMBER, CMAP, CURSOR_NAME) \ for (struct cmap_cursor CURSOR_NAME = cmap_cursor_start(CMAP); \ CMAP_CURSOR_FOR_EACH__(NODE, &CURSOR_NAME, MEMBER); \ @@ -255,7 +252,7 @@ void cmap_cursor_advance(struct cmap_cursor *); #define CMAP_FOR_EACH(NODE, MEMBER, CMAP) \ CMAP_FOR_EACH__(NODE, MEMBER, CMAP, \ - CURSOR_JOIN(cursor_, __COUNTER__)) + OVS_JOIN(cursor_, __COUNTER__)) static inline struct cmap_node *cmap_first(const struct cmap *); diff --git a/lib/util.h b/lib/util.h index 1fe8ef32b..aea19d45f 100644 --- a/lib/util.h +++ b/lib/util.h @@ -105,6 +105,13 @@ ovs_prefetch_range(const void *start, size_t size) #define OVS_NOT_REACHED() abort() +/* Joins two token expanding the arguments if they are macros. + * + * For token concatenation the circumlocution is needed for the + * expansion. */ +#define OVS_JOIN2(X, Y) X##Y +#define OVS_JOIN(X, Y) OVS_JOIN2(X, Y) + /* Use "%"PRIuSIZE to format size_t with printf(). */ #ifdef _WIN32 #define PRIdSIZE "Id" From patchwork Mon Jun 21 10:06:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Valerio X-Patchwork-Id: 1494997 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=K+VfcY5S; dkim-atps=neutral Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G7lYp66Vqz9sRN for ; Mon, 21 Jun 2021 20:06:54 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 85340403CE; Mon, 21 Jun 2021 10:06:52 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id m4Np5fEdDxIg; Mon, 21 Jun 2021 10:06:51 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 388C240218; Mon, 21 Jun 2021 10:06:50 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id EAF68C001C; Mon, 21 Jun 2021 10:06:49 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 17A4CC000C for ; Mon, 21 Jun 2021 10:06:48 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 525BA400A9 for ; Mon, 21 Jun 2021 10:06:40 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id c_D--mZtGR6W for ; Mon, 21 Jun 2021 10:06:39 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp2.osuosl.org (Postfix) with ESMTPS id E8A31403A3 for ; Mon, 21 Jun 2021 10:06:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1624269998; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5raXzCkWh0DvHQSwmhz7TWSuyALV6kNeSRJd5p46H6Y=; b=K+VfcY5SF5v+4zghhPChK3OfI9YTe3S/XggamCnXW5HNpU4jgJNacieHg4SvImqVmlsodr WrShaJ2xN/p5HH75TVumgCW90WkHsg+z1+USebSqQImgd+32I9xf30Ry5Ix/5Y/Z+nxPJn yz/ZmXK+i6DSJHyCuJd25uZGZ7k/9i8= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-584-pzd0BmDoNS2bAuR1QcOX6A-1; Mon, 21 Jun 2021 06:06:36 -0400 X-MC-Unique: pzd0BmDoNS2bAuR1QcOX6A-1 Received: by mail-wr1-f71.google.com with SMTP id u16-20020a5d51500000b029011a6a17cf62so7887611wrt.13 for ; Mon, 21 Jun 2021 03:06:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=5raXzCkWh0DvHQSwmhz7TWSuyALV6kNeSRJd5p46H6Y=; b=p8SMEU9up76rhTl+qEIJgqocAY9KqTnUFpAiyt55NTZuqilpLewPalSU1Z4cp67zFG r7j4w+vADOa3GJDdpCcDFwsdPyuMBg0IPrHXSWm2aKE26ZxkJPJxZOSRz0ffnHCuO6uP VtOSOihRKxU/wJlzsNw/kAzSZ+8YiO3VsQn8QdPUs/peQkrZ3eiARbLsjj3VJet9AxBl qVT3vkfEAo9+Zwqz9q0j5qr7nbZdOMxMK3epFRZpmuIxuCQXTpScM8IhMrFQUbE5V8Bn mC5tcoZG0B1bZqtpQIuzwY43KmGqJKXqmrw3gZaCJub4sdM90jRm2XfGKdrvjyXKFrqT BKug== X-Gm-Message-State: AOAM5336dD2gc6UOCQnPaY2laMVh6j3YYJs6b75P5S6NhgDT7JaMucqT RZlN341P/DGPUdIQCHTZFUw9iyTpfXaMk4FRhHMOLeIJ4yrNxcfP8mZVign8VYfrefzns9ctsRb q8fkI87flKV4cV2+MjL5zIDWtoMQeq5jMrQwspntbBk+nIMZNq66xFdeoVYy1x4hp X-Received: by 2002:a05:600c:4f0c:: with SMTP id l12mr26165294wmq.123.1624269995052; Mon, 21 Jun 2021 03:06:35 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxhcX3zD00DCDDVJ4O5vcZIOiH0qlfaEFh5XZsIHSlSkfi6PYfLegjCOlGxmgp5pu6WlrG1Xw== X-Received: by 2002:a05:600c:4f0c:: with SMTP id l12mr26165258wmq.123.1624269994725; Mon, 21 Jun 2021 03:06:34 -0700 (PDT) Received: from localhost (net-93-146-7-51.cust.vodafonedsl.it. [93.146.7.51]) by smtp.gmail.com with ESMTPSA id b11sm902623wmj.25.2021.06.21.03.06.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jun 2021 03:06:34 -0700 (PDT) From: Paolo Valerio To: dev@openvswitch.org Date: Mon, 21 Jun 2021 12:06:33 +0200 Message-ID: <162426999162.3650320.8139157744646493261.stgit@fed.void> In-Reply-To: <162426992691.3650320.15060936163617998030.stgit@fed.void> References: <162426992691.3650320.15060936163617998030.stgit@fed.void> User-Agent: StGit/0.23 MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=pvalerio@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: i.maximets@ovn.org Subject: [ovs-dev] [PATCH v7 3/4] conntrack: handle SNAT with all-zero IP address X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" this patch introduces for the userspace datapath the handling of rules like the following: ct(commit,nat(src=0.0.0.0),...) Kernel datapath already handle this case that is particularly handy in scenarios like the following: Given A: 10.1.1.1, B: 192.168.2.100, C: 10.1.1.2 A opens a connection toward B on port 80 selecting as source port 10000. B's IP gets dnat'ed to C's IP (10.1.1.1:10000 -> 192.168.2.100:80). This will result in: tcp,orig=(src=10.1.1.1,dst=192.168.2.100,sport=10000,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=80,dport=10000),protoinfo=(state=ESTABLISHED) A now tries to establish another connection with C using source port 10000, this time using C's IP address (10.1.1.1:10000 -> 10.1.1.2:80). This second connection, if processed by conntrack with no SNAT/DNAT involved, collides with the reverse tuple of the first connection, so the entry for this valid connection doesn't get created. With this commit, and adding a SNAT rule with 0.0.0.0 for 10.1.1.1:10000 -> 10.1.1.2:80 will allow to create the conn entry: tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=10000,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=80,dport=10001),protoinfo=(state=ESTABLISHED) tcp,orig=(src=10.1.1.1,dst=192.168.2.100,sport=10000,dport=80),reply=(src=10.1.1.2,dst=10.1.1.1,sport=80,dport=10000),protoinfo=(state=ESTABLISHED) The issue exists even in the opposite case (with A trying to connect to C using B's IP after establishing a direct connection from A to C). This commit refactors the relevant function in a way that both of the previously mentioned cases are handled as well. Suggested-by: Eelco Chaudron Signed-off-by: Paolo Valerio Acked-by: Gaetan Rivet Acked-by: Aaron Conole --- NEWS | 3 lib/conntrack-private.h | 33 ++++ lib/conntrack.c | 335 ++++++++++++++++++++++++-------------- lib/ovs-actions.xml | 3 tests/system-userspace-macros.at | 8 - 5 files changed, 251 insertions(+), 131 deletions(-) diff --git a/NEWS b/NEWS index ebba17b22..ca6f52522 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,9 @@ Post-v2.15.0 - Userspace datapath: * Auto load balancing of PMDs now partially supports cross-NUMA polling cases, e.g if all PMD threads are running on the same NUMA node. + * Add all-zero IP SNAT handling to conntrack. In case of collision, + using ct(src=0.0.0.0), the source port will be replaced with another + non-colliding port in the ephemeral range (1024, 65535). - ovs-ctl: * New option '--no-record-hostname' to disable hostname configuration in ovsdb on startup. diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h index e8332bdba..cc2fb045d 100644 --- a/lib/conntrack-private.h +++ b/lib/conntrack-private.h @@ -148,6 +148,39 @@ enum ct_update_res { CT_TIMEOUT(ICMP_FIRST) \ CT_TIMEOUT(ICMP_REPLY) +#define NAT_ACTION_SNAT_ALL (NAT_ACTION_SRC | NAT_ACTION_SRC_PORT) +#define NAT_ACTION_DNAT_ALL (NAT_ACTION_DST | NAT_ACTION_DST_PORT) + +enum ct_ephemeral_range { + MIN_NAT_EPHEMERAL_PORT = 1024, + MAX_NAT_EPHEMERAL_PORT = 65535 +}; + +#define IN_RANGE(curr, min, max) \ + (curr >= min && curr <= max) + +#define NEXT_PORT_IN_RANGE(curr, min, max) \ + (curr = (!IN_RANGE(curr, min, max) || curr == max) ? min : curr + 1) + +/* if the current port is out of range increase the attempts by + * one so that in the worst case scenario the current out of + * range port plus all the in-range ports get tested. + * Note that curr can be an out of range port only in case of + * source port (SNAT with port range unspecified or DNAT), + * furthermore the source port in the packet has to be less than + * MIN_NAT_EPHEMERAL_PORT. */ +#define N_PORT_ATTEMPTS(curr, min, max) \ + ((!IN_RANGE(curr, min, max)) ? (max - min) + 2 : (max - min) + 1) + +/* loose in-range check, the first curr port can be any port out of + * the range. */ +#define FOR_EACH_PORT_IN_RANGE__(curr, min, max, INAME) \ + for (uint16_t INAME = N_PORT_ATTEMPTS(curr, min, max); \ + INAME > 0; INAME--, NEXT_PORT_IN_RANGE(curr, min, max)) + +#define FOR_EACH_PORT_IN_RANGE(curr, min, max) \ + FOR_EACH_PORT_IN_RANGE__(curr, min, max, OVS_JOIN(idx, __COUNTER__)) + enum ct_timeout { #define CT_TIMEOUT(NAME) CT_TM_##NAME, CT_TIMEOUTS diff --git a/lib/conntrack.c b/lib/conntrack.c index 7e8b16a3e..f49382adb 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -108,8 +108,8 @@ static void set_label(struct dp_packet *, struct conn *, static void *clean_thread_main(void *f_); static bool -nat_select_range_tuple(struct conntrack *ct, const struct conn *conn, - struct conn *nat_conn); +nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, + struct conn *nat_conn); static uint8_t reverse_icmp_type(uint8_t type); @@ -728,11 +728,11 @@ pat_packet(struct dp_packet *pkt, const struct conn *conn) } } else if (conn->nat_info->nat_action & NAT_ACTION_DST) { if (conn->key.nw_proto == IPPROTO_TCP) { - struct tcp_header *th = dp_packet_l4(pkt); - packet_set_tcp_port(pkt, th->tcp_src, conn->rev_key.src.port); + packet_set_tcp_port(pkt, conn->rev_key.dst.port, + conn->rev_key.src.port); } else if (conn->key.nw_proto == IPPROTO_UDP) { - struct udp_header *uh = dp_packet_l4(pkt); - packet_set_udp_port(pkt, uh->udp_src, conn->rev_key.src.port); + packet_set_udp_port(pkt, conn->rev_key.dst.port, + conn->rev_key.src.port); } } } @@ -786,11 +786,9 @@ un_pat_packet(struct dp_packet *pkt, const struct conn *conn) } } else if (conn->nat_info->nat_action & NAT_ACTION_DST) { if (conn->key.nw_proto == IPPROTO_TCP) { - struct tcp_header *th = dp_packet_l4(pkt); - packet_set_tcp_port(pkt, conn->key.dst.port, th->tcp_dst); + packet_set_tcp_port(pkt, conn->key.dst.port, conn->key.src.port); } else if (conn->key.nw_proto == IPPROTO_UDP) { - struct udp_header *uh = dp_packet_l4(pkt); - packet_set_udp_port(pkt, conn->key.dst.port, uh->udp_dst); + packet_set_udp_port(pkt, conn->key.dst.port, conn->key.src.port); } } } @@ -810,12 +808,10 @@ reverse_pat_packet(struct dp_packet *pkt, const struct conn *conn) } } else if (conn->nat_info->nat_action & NAT_ACTION_DST) { if (conn->key.nw_proto == IPPROTO_TCP) { - struct tcp_header *th_in = dp_packet_l4(pkt); - packet_set_tcp_port(pkt, th_in->tcp_src, + packet_set_tcp_port(pkt, conn->key.src.port, conn->key.dst.port); } else if (conn->key.nw_proto == IPPROTO_UDP) { - struct udp_header *uh_in = dp_packet_l4(pkt); - packet_set_udp_port(pkt, uh_in->udp_src, + packet_set_udp_port(pkt, conn->key.src.port, conn->key.dst.port); } } @@ -1029,14 +1025,14 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, } } else { memcpy(nat_conn, nc, sizeof *nat_conn); - bool nat_res = nat_select_range_tuple(ct, nc, nat_conn); + bool nat_res = nat_get_unique_tuple(ct, nc, nat_conn); if (!nat_res) { goto nat_res_exhaustion; } /* Update nc with nat adjustments made to nat_conn by - * nat_select_range_tuple(). */ + * nat_get_unique_tuple(). */ memcpy(nc, nat_conn, sizeof *nc); } @@ -2238,130 +2234,221 @@ nat_range_hash(const struct conn *conn, uint32_t basis) return hash_finish(hash, 0); } -static bool -nat_select_range_tuple(struct conntrack *ct, const struct conn *conn, - struct conn *nat_conn) -{ - enum { MIN_NAT_EPHEMERAL_PORT = 1024, - MAX_NAT_EPHEMERAL_PORT = 65535 }; - - uint16_t min_port; - uint16_t max_port; - uint16_t first_port; - uint32_t hash = nat_range_hash(conn, ct->hash_basis); +/* Ports are stored in host byte order for convenience. */ +static void +set_sport_range(struct nat_action_info_t *ni, const struct conn_key *k, + uint32_t hash, uint16_t *curr, uint16_t *min, + uint16_t *max) +{ + if (((ni->nat_action & NAT_ACTION_SNAT_ALL) == NAT_ACTION_SRC) || + ((ni->nat_action & NAT_ACTION_DST))) { + *curr = ntohs(k->src.port); + *min = MIN_NAT_EPHEMERAL_PORT; + *max = MAX_NAT_EPHEMERAL_PORT; + } else { + *min = ni->min_port; + *max = ni->max_port; + *curr = *min + (hash % ((*max - *min) + 1)); + } +} - if ((conn->nat_info->nat_action & NAT_ACTION_SRC) && - (!(conn->nat_info->nat_action & NAT_ACTION_SRC_PORT))) { - min_port = ntohs(conn->key.src.port); - max_port = ntohs(conn->key.src.port); - first_port = min_port; - } else if ((conn->nat_info->nat_action & NAT_ACTION_DST) && - (!(conn->nat_info->nat_action & NAT_ACTION_DST_PORT))) { - min_port = ntohs(conn->key.dst.port); - max_port = ntohs(conn->key.dst.port); - first_port = min_port; +static void +set_dport_range(struct nat_action_info_t *ni, const struct conn_key *k, + uint32_t hash, uint16_t *curr, uint16_t *min, + uint16_t *max) +{ + if (ni->nat_action & NAT_ACTION_DST_PORT) { + *min = ni->min_port; + *max = ni->max_port; + *curr = *min + (hash % ((*max - *min) + 1)); } else { - uint16_t deltap = conn->nat_info->max_port - conn->nat_info->min_port; - uint32_t port_index = hash % (deltap + 1); - first_port = conn->nat_info->min_port + port_index; - min_port = conn->nat_info->min_port; - max_port = conn->nat_info->max_port; + *curr = ntohs(k->dst.port); + *min = *max = *curr; } +} - uint32_t deltaa = 0; - uint32_t address_index; - union ct_addr ct_addr; - memset(&ct_addr, 0, sizeof ct_addr); - union ct_addr max_ct_addr; - memset(&max_ct_addr, 0, sizeof max_ct_addr); - max_ct_addr = conn->nat_info->max_addr; +/* Gets the initial in range address based on the hash. + * Addresses are kept in network order. */ +static void +get_addr_in_range(union ct_addr *min, union ct_addr *max, + union ct_addr *curr, uint32_t hash, + bool ipv4) +{ + uint32_t offt, range; - if (conn->key.dl_type == htons(ETH_TYPE_IP)) { - deltaa = ntohl(conn->nat_info->max_addr.ipv4) - - ntohl(conn->nat_info->min_addr.ipv4); - address_index = hash % (deltaa + 1); - ct_addr.ipv4 = htonl( - ntohl(conn->nat_info->min_addr.ipv4) + address_index); + if (ipv4) { + range = (ntohl(max->ipv4) - ntohl(min->ipv4)) + 1; + offt = hash % range; + curr->ipv4 = htonl(ntohl(min->ipv4) + offt); } else { - deltaa = nat_ipv6_addrs_delta(&conn->nat_info->min_addr.ipv6, - &conn->nat_info->max_addr.ipv6); - /* deltaa must be within 32 bits for full hash coverage. A 64 or + range = nat_ipv6_addrs_delta(&min->ipv6, + &max->ipv6) + 1; + /* range must be within 32 bits for full hash coverage. A 64 or * 128 bit hash is unnecessary and hence not used here. Most code * is kept common with V4; nat_ipv6_addrs_delta() will do the * enforcement via max_ct_addr. */ - max_ct_addr = conn->nat_info->min_addr; - nat_ipv6_addr_increment(&max_ct_addr.ipv6, deltaa); - address_index = hash % (deltaa + 1); - ct_addr.ipv6 = conn->nat_info->min_addr.ipv6; - nat_ipv6_addr_increment(&ct_addr.ipv6, address_index); - } - - uint16_t port = first_port; - bool all_ports_tried = false; - /* For DNAT or for specified port ranges, we don't use ephemeral ports. */ - bool ephemeral_ports_tried - = conn->nat_info->nat_action & NAT_ACTION_DST || - conn->nat_info->nat_action & NAT_ACTION_SRC_PORT - ? true : false; - union ct_addr first_addr = ct_addr; - bool pat_enabled = conn->key.nw_proto == IPPROTO_TCP || - conn->key.nw_proto == IPPROTO_UDP; - - while (true) { + offt = hash % range; + curr->ipv6 = min->ipv6; + nat_ipv6_addr_increment(&curr->ipv6, offt); + } +} + +static void +get_initial_addr(const struct conn *conn, union ct_addr *min, + union ct_addr *max, union ct_addr *curr, + uint32_t hash, bool ipv4) +{ + const union ct_addr zero_ip = {0}; + + /* all-zero CASE */ + if (!memcmp(min, &zero_ip, sizeof(*min))) { if (conn->nat_info->nat_action & NAT_ACTION_SRC) { - nat_conn->rev_key.dst.addr = ct_addr; - if (pat_enabled) { - nat_conn->rev_key.dst.port = htons(port); - } - } else { - nat_conn->rev_key.src.addr = ct_addr; - if (pat_enabled) { - nat_conn->rev_key.src.port = htons(port); - } + *curr = conn->key.src.addr; + } else if (conn->nat_info->nat_action & NAT_ACTION_DST) { + *curr = conn->key.dst.addr; + } + } else { + get_addr_in_range(min, max, curr, hash, ipv4); + } +} + +static void +store_addr_to_key(union ct_addr *addr, struct conn_key *key, + uint16_t action) +{ + if (action & NAT_ACTION_SRC) { + key->dst.addr = *addr; + } else { + key->src.addr = *addr; + } +} + +static void +next_addr_in_range(union ct_addr *curr, union ct_addr *min, + union ct_addr *max, bool ipv4) +{ + if (ipv4) { + /* this check could be unified with IPv6, but let's avoid + * an unneeded memcmp() in case of IPv4. */ + if (min->ipv4 == max->ipv4) { + return; + } + + curr->ipv4 = (curr->ipv4 == max->ipv4) ? + min->ipv4 : + htonl(ntohl(curr->ipv4) + 1); + } else { + if (!memcmp(min, max, sizeof(*min))) { + return; + } + + if (!memcmp(curr, max, sizeof(*curr))) { + *curr = *min; + return; } - bool found = conn_lookup(ct, &nat_conn->rev_key, time_msec(), NULL, - NULL); - if (!found) { + nat_ipv6_addr_increment(&curr->ipv6, 1); + } +} + +static bool +next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min, + union ct_addr *max, union ct_addr *guard, + bool ipv4) +{ + bool exhausted; + + next_addr_in_range(curr, min, max, ipv4); + + if (ipv4) { + exhausted = (curr->ipv4 == guard->ipv4); + } else { + exhausted = !memcmp(curr, guard, sizeof(*curr)); + } + + return exhausted; +} + +/* This function tries to get a unique tuple. + * Every iteration checks that the reverse tuple doesn't + * collide with any existing one. + * + * in case of SNAT: + * - for each src IP address in the range (if any) + * - try to find a source port in range (if any) + * - if no port range exists, use the whole + * ephemeral range (after testing the port + * used by the sender), otherwise use the + * specified range + * + * in case of DNAT: + * - for each dst IP address in the range (if any) + * - for each dport in range (if any) + * - try to find a source port in the ephemeral range + * (after testing the port used by the sender) + * + * If none can be found, return exhaustion to the caller. */ +static bool +nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, + struct conn *nat_conn) +{ + union ct_addr min_addr = {0}, max_addr = {0}, curr_addr = {0}, + guard_addr = {0}; + uint32_t hash = nat_range_hash(conn, ct->hash_basis); + bool pat_proto = conn->key.nw_proto == IPPROTO_TCP || + conn->key.nw_proto == IPPROTO_UDP; + uint16_t min_dport, max_dport, curr_dport; + uint16_t min_sport, max_sport, curr_sport; + + min_addr = conn->nat_info->min_addr; + max_addr = conn->nat_info->max_addr; + + get_initial_addr(conn, &min_addr, &max_addr, &curr_addr, hash, + (conn->key.dl_type == htons(ETH_TYPE_IP))); + + /* save the address we started from so that + * we can stop once we reach it. */ + guard_addr = curr_addr; + + set_sport_range(conn->nat_info, &conn->key, hash, &curr_sport, + &min_sport, &max_sport); + set_dport_range(conn->nat_info, &conn->key, hash, &curr_dport, + &min_dport, &max_dport); + +another_round: + store_addr_to_key(&curr_addr, &nat_conn->rev_key, + conn->nat_info->nat_action); + + if (!pat_proto) { + if (!conn_lookup(ct, &nat_conn->rev_key, + time_msec(), NULL, NULL)) { return true; - } else if (pat_enabled && !all_ports_tried) { - if (min_port == max_port) { - all_ports_tried = true; - } else if (port == max_port) { - port = min_port; - } else { - port++; - } - if (port == first_port) { - all_ports_tried = true; - } - } else { - if (memcmp(&ct_addr, &max_ct_addr, sizeof ct_addr)) { - if (conn->key.dl_type == htons(ETH_TYPE_IP)) { - ct_addr.ipv4 = htonl(ntohl(ct_addr.ipv4) + 1); - } else { - nat_ipv6_addr_increment(&ct_addr.ipv6, 1); - } - } else { - ct_addr = conn->nat_info->min_addr; - } - if (!memcmp(&ct_addr, &first_addr, sizeof ct_addr)) { - if (pat_enabled && !ephemeral_ports_tried) { - ephemeral_ports_tried = true; - ct_addr = conn->nat_info->min_addr; - first_addr = ct_addr; - min_port = MIN_NAT_EPHEMERAL_PORT; - max_port = MAX_NAT_EPHEMERAL_PORT; - } else { - break; - } + } + + goto next_addr; + } + + FOR_EACH_PORT_IN_RANGE(curr_dport, min_dport, max_dport) { + nat_conn->rev_key.src.port = htons(curr_dport); + FOR_EACH_PORT_IN_RANGE(curr_sport, min_sport, max_sport) { + nat_conn->rev_key.dst.port = htons(curr_sport); + if (!conn_lookup(ct, &nat_conn->rev_key, + time_msec(), NULL, NULL)) { + return true; } - first_port = min_port; - port = first_port; - all_ports_tried = false; } } - return false; + + /* Check if next IP is in range and respin. Otherwise, notify + * exhaustion to the caller. */ +next_addr: + if (next_addr_in_range_guarded(&curr_addr, &min_addr, + &max_addr, &guard_addr, + conn->key.dl_type == htons(ETH_TYPE_IP))) { + return false; + } + + goto another_round; } static enum ct_update_res diff --git a/lib/ovs-actions.xml b/lib/ovs-actions.xml index 1668e5187..9bfc7ddd1 100644 --- a/lib/ovs-actions.xml +++ b/lib/ovs-actions.xml @@ -2138,8 +2138,7 @@ for i in [1,n_members]: nat(src=0.0.0.0). In this case, when a source port collision is detected during the commit, the source port will be translated to an ephemeral port. If there is no collision, no SNAT - is performed. Note that this is currently only implemented in the - Linux kernel datapath. + is performed.

diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at index 9f0d38dfb..f639ba53a 100644 --- a/tests/system-userspace-macros.at +++ b/tests/system-userspace-macros.at @@ -99,12 +99,10 @@ m4_define([CHECK_CONNTRACK_NAT]) # CHECK_CONNTRACK_ZEROIP_SNAT() # # Perform requirements checks for running conntrack all-zero IP SNAT tests. -# The userspace datapath does not support all-zero IP SNAT. +# The userspace datapath always supports all-zero IP SNAT, so no check is +# needed. # -m4_define([CHECK_CONNTRACK_ZEROIP_SNAT], -[ - AT_SKIP_IF([:]) -]) +m4_define([CHECK_CONNTRACK_ZEROIP_SNAT]) # CHECK_CONNTRACK_TIMEOUT() # From patchwork Mon Jun 21 10:06:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Valerio X-Patchwork-Id: 1494998 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=I4jWZfdg; dkim-atps=neutral Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G7lYt5xYHz9sRN for ; Mon, 21 Jun 2021 20:06:58 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 177FE834D5; Mon, 21 Jun 2021 10:06:57 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1ndxVjIBhDZ9; Mon, 21 Jun 2021 10:06:56 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 5EA048386F; Mon, 21 Jun 2021 10:06:55 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2B1CDC000C; Mon, 21 Jun 2021 10:06:55 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0FD3AC000C for ; Mon, 21 Jun 2021 10:06:54 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 487368386F for ; Mon, 21 Jun 2021 10:06:46 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id LKLqPIkshAH9 for ; Mon, 21 Jun 2021 10:06:45 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp1.osuosl.org (Postfix) with ESMTPS id AA4A7837EC for ; Mon, 21 Jun 2021 10:06:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1624270004; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cKNzfy6MNptTNWa+E+J+eNavmUJTZToMseQxrG9ui9E=; b=I4jWZfdgb0TB2zv3fAh9qboBWfnzVzIyLADtoejzLyVKey3GR1hihNsw9u+MpsUkxogvC4 oWFOmTqNtyeftmp3zk2PpiSB3P1tTky3ZtqVnv8MITvqcks09sxY/WQMwlGMTEUrUYe9AI W6zZpvWh/uixyI2xx1I06gLnemzqiss= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-306-dzneoA3qPQyUY_VDRDulKQ-1; Mon, 21 Jun 2021 06:06:44 -0400 X-MC-Unique: dzneoA3qPQyUY_VDRDulKQ-1 Received: by mail-wr1-f69.google.com with SMTP id t10-20020a5d49ca0000b029011a61d5c96bso8219631wrs.11 for ; Mon, 21 Jun 2021 03:06:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=cKNzfy6MNptTNWa+E+J+eNavmUJTZToMseQxrG9ui9E=; b=jbd/exHGtAS2wekggSxrrmMUPVfWjx4PpoWgXYvJFYpwWn5YYtVmlfIN7zMOW+WgSI 0ZNJqZ/QNj2ji4M2MzriyF0F5WHHoWSH1ikiO5VbSx3H8jVjkiyFuMKiP6DALXta7H6t cSaLRbIkeKCAQsNY8hEGINbpvOW71dAHoSYd4Y4RiXymP6PbrsmOMb4ACp4pMBsUCSFe Els2J1yTo7jS8F1xSuk6EjyUGPkG8IcRVBaV5xSUP8Bgs+J2tw6q7N8ycuo4PMiAxIq/ B7sZfjJQyg0WzvF2Isboq3zhRAh4OwKK8Kf9V7U1uB/eaGYMh903eQst+hPbTCQoT/2Q uGOQ== X-Gm-Message-State: AOAM532UH5h9lAOg86qwyyRjUrVIBMbVW/UP1YBw7WvbZLdCrhtsFgMc e+8HK7tVVPEV/RZKqpte/Xz73Uvk+ooFnw0c9a49sl13uKueXu5ihherLH20CpLTI5JTftFJ/hz edn4PJ6RTfUKxMtJJbeg3uxhhpFuW+oJfT8JBF8tXQeHOBwwzWjYiE6mQ+lb/bCSk X-Received: by 2002:adf:f20c:: with SMTP id p12mr27160900wro.257.1624270002634; Mon, 21 Jun 2021 03:06:42 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwSmo8g1tITRWsWnD92lHUMFJd1/u8r5ieAdMebCJcMuKHagsKwxN4pEI0BWWK4GNSWeeYlFg== X-Received: by 2002:adf:f20c:: with SMTP id p12mr27160882wro.257.1624270002460; Mon, 21 Jun 2021 03:06:42 -0700 (PDT) Received: from localhost (net-93-146-7-51.cust.vodafonedsl.it. [93.146.7.51]) by smtp.gmail.com with ESMTPSA id l10sm16768031wrs.11.2021.06.21.03.06.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Jun 2021 03:06:42 -0700 (PDT) From: Paolo Valerio To: dev@openvswitch.org Date: Mon, 21 Jun 2021 12:06:41 +0200 Message-ID: <162426999980.3650320.10129729985974833736.stgit@fed.void> In-Reply-To: <162426992691.3650320.15060936163617998030.stgit@fed.void> References: <162426992691.3650320.15060936163617998030.stgit@fed.void> User-Agent: StGit/0.23 MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=pvalerio@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: i.maximets@ovn.org Subject: [ovs-dev] [PATCH v7 4/4] dpif-netdev: add all-zero SNAT to the advertised features of ct X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Signed-off-by: Paolo Valerio Acked-by: Aaron Conole --- lib/dpif-netdev.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 05de57ed5..3f04bf6ec 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -8250,6 +8250,16 @@ dpif_netdev_ct_del_limits(struct dpif *dpif OVS_UNUSED, return err; } +static int +dpif_netdev_ct_get_features(struct dpif *dpif OVS_UNUSED, + enum ct_features *features) +{ + if (features != NULL) { + *features = CONNTRACK_F_ZERO_SNAT; + } + return 0; +} + static int dpif_netdev_ct_set_timeout_policy(struct dpif *dpif, const struct ct_dpif_timeout_policy *dpif_tp) @@ -8515,7 +8525,7 @@ const struct dpif_class dpif_netdev_class = { NULL, /* ct_timeout_policy_dump_next */ NULL, /* ct_timeout_policy_dump_done */ dpif_netdev_ct_get_timeout_policy_name, - NULL, /* ct_get_features */ + dpif_netdev_ct_get_features, dpif_netdev_ipf_set_enabled, dpif_netdev_ipf_set_min_frag, dpif_netdev_ipf_set_max_nfrags,