From patchwork Wed Oct 14 16:27:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382255 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.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHrm5fkVz9sVR for ; Thu, 15 Oct 2020 03:27:52 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 17EC887647; Wed, 14 Oct 2020 16:27:51 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kicbt4XRoe78; Wed, 14 Oct 2020 16:27:46 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id E6C3487AF4; Wed, 14 Oct 2020 16:27:44 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id CC82CC1AD5; Wed, 14 Oct 2020 16:27:44 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id A47D5C0051 for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 91E8687A0D for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kmTC4IC-yZAW for ; Wed, 14 Oct 2020 16:27:40 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 790A886C5A for ; Wed, 14 Oct 2020 16:27:40 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcn-0000DW-6a; Wed, 14 Oct 2020 16:27:38 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjci-0001Zd-EJ; Wed, 14 Oct 2020 17:27:34 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:06 +0100 Message-Id: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 1/9] ovn-libs: Add support for parallel processing 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" From: Anton Ivanov This adds a set of functions and macros intended to process hashes in parallel. The principles of operation are documented in the fasthmap.h If these one day go into the OVS tree, the OVS tree versions would be used in preference. Signed-off-by: Anton Ivanov --- lib/automake.mk | 2 + lib/fasthmap.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/fasthmap.h | 206 ++++++++++++++++++++++++++++++++++++ 3 files changed, 477 insertions(+) create mode 100644 lib/fasthmap.c create mode 100644 lib/fasthmap.h diff --git a/lib/automake.mk b/lib/automake.mk index f3e9c8818..976b9181b 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -13,6 +13,8 @@ lib_libovn_la_SOURCES = \ lib/expr.c \ lib/extend-table.h \ lib/extend-table.c \ + lib/fasthmap.h \ + lib/fasthmap.c \ lib/ip-mcast-index.c \ lib/ip-mcast-index.h \ lib/mcast-group-index.c \ diff --git a/lib/fasthmap.c b/lib/fasthmap.c new file mode 100644 index 000000000..bcabbed7a --- /dev/null +++ b/lib/fasthmap.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2020 Red Hat, Inc. + * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2019 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 "fatal-signal.h" +#include "util.h" +#include "openvswitch/vlog.h" +#include "openvswitch/hmap.h" +#include "openvswitch/thread.h" +#include "fasthmap.h" +#include "ovs-atomic.h" +#include "ovs-thread.h" +#include "ovs-numa.h" + +VLOG_DEFINE_THIS_MODULE(fasthmap); + + +static bool worker_pool_setup = false; +static bool workers_must_exit = false; + +static struct ovs_list worker_pools = OVS_LIST_INITIALIZER(&worker_pools); + +static struct ovs_mutex init_mutex = OVS_MUTEX_INITIALIZER; + +static int pool_size; + +static void worker_pool_hook(void *aux OVS_UNUSED) { + int i; + static struct worker_pool *pool; + workers_must_exit = true; /* all workers must honour this flag */ + atomic_thread_fence(memory_order_release); + LIST_FOR_EACH (pool, list_node, &worker_pools) { + for (i = 0; i < pool->size ; i++) { + sem_post(&pool->controls[i].fire); + } + } +} + +static void setup_worker_pools(void) { + int cores, nodes; + + nodes = ovs_numa_get_n_numas(); + if (nodes == OVS_NUMA_UNSPEC || nodes <= 0) { + nodes = 1; + } + cores = ovs_numa_get_n_cores(); + + /* If there is no NUMA config, use 4 cores. + * If there is NUMA config use half the cores on + * one node so that the OS does not start pushing + * threads to other nodes. + */ + if (cores == OVS_CORE_UNSPEC || cores <= 0) { + pool_size = 4; + } else { + pool_size = cores / nodes / 2; + } + fatal_signal_add_hook(worker_pool_hook, NULL, NULL, true); + worker_pool_setup = true; +} + +bool ovn_cease_fire(void) +{ + return workers_must_exit; +} + +struct worker_pool *ovn_add_worker_pool(void *(*start)(void *)){ + + struct worker_pool *new_pool = NULL; + struct worker_control *new_control; + int i; + + ovs_mutex_lock(&init_mutex); + + if (!worker_pool_setup) { + setup_worker_pools(); + } + + new_pool = xmalloc(sizeof(struct worker_pool)); + new_pool->size = pool_size; + sem_init(&new_pool->done, 0, 0); + + ovs_list_push_back(&worker_pools, &new_pool->list_node); + + new_pool->controls = + xmalloc(sizeof(struct worker_control) * new_pool->size); + + for (i = 0; i < new_pool->size; i++) { + new_control = &new_pool->controls[i]; + sem_init(&new_control->fire, 0, 0); + new_control->id = i; + new_control->done = &new_pool->done; + new_control->data = NULL; + ovs_mutex_init(&new_control->mutex); + new_control->finished = ATOMIC_VAR_INIT(false); + } + + for (i = 0; i < pool_size; i++) { + ovs_thread_create("worker pool helper", start, &new_pool->controls[i]); + } + ovs_mutex_unlock(&init_mutex); + return new_pool; +} + + +/* Initializes 'hmap' as an empty hash table with mask N. */ +void +ovn_fast_hmap_init(struct hmap *hmap, ssize_t mask) +{ + size_t i; + + hmap->buckets = xmalloc(sizeof (struct hmap_node *) * (mask + 1)); + hmap->one = NULL; + hmap->mask = mask; + hmap->n = 0; + for (i = 0; i <= hmap->mask; i++) { + hmap->buckets[i] = NULL; + } +} + +/* Initializes 'hmap' as an empty hash table of size X. + * Intended for use in parallel processing so that all + * fragments used to store results in a parallel job + * are the same size. + */ +void +ovn_fast_hmap_size_for(struct hmap *hmap, int size) +{ + size_t mask; + mask = size / 2; + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; +#if SIZE_MAX > UINT32_MAX + mask |= mask >> 32; +#endif + + /* If we need to dynamically allocate buckets we might as well allocate at + * least 4 of them. */ + mask |= (mask & 1) << 1; + + fast_hmap_init(hmap, mask); +} + +/* Run a thread pool which uses a callback function to process results + */ + +void ovn_run_pool_callback( + struct worker_pool *pool, + void *fin_result, + void *result_frags, + void (*helper_func)(struct worker_pool *pool, + void *fin_result, void *result_frags, int index)) +{ + int index, completed; + + atomic_thread_fence(memory_order_release); + + for (index = 0; index < pool->size; index++) { + sem_post(&pool->controls[index].fire); + } + + completed = 0; + + do { + bool test; + sem_wait(&pool->done); + for (index = 0; index < pool->size; index++) { + test = true; + if (atomic_compare_exchange_weak( + &pool->controls[index].finished, + &test, + false)) { + if (helper_func) { + (helper_func)(pool, fin_result, result_frags, index); + } + completed++; + pool->controls[index].data = NULL; + } + } + } while (completed < pool->size); +} + +/* Run a thread pool - basic, does not do results processing. + */ + +void ovn_run_pool(struct worker_pool *pool) +{ + ovn_run_pool_callback(pool, NULL, NULL, NULL); +} + +/* Brute force merge of a hashmap into another hashmap. + * Intended for use in parallel processing. The destination + * hashmap MUST be the same size as the one being merged. + * + * This can be achieved by pre-allocating them to correct size + * and using hmap_insert_fast() instead of hmap_insert() + */ + +void ovn_fast_hmap_merge(struct hmap *dest, struct hmap *inc) +{ + size_t i; + + ovs_assert(inc->mask == dest->mask); + + if (!inc->n) { + /* Request to merge an empty frag, nothing to do */ + return; + } + + for (i = 0; i <= dest->mask; i++) { + struct hmap_node **dest_bucket = &dest->buckets[i]; + struct hmap_node **inc_bucket = &inc->buckets[i]; + if (*inc_bucket != NULL) { + struct hmap_node *last_node = *inc_bucket; + while (last_node->next != NULL) { + last_node = last_node->next; + } + last_node->next = *dest_bucket; + *dest_bucket = *inc_bucket; + *inc_bucket = NULL; + } + } + dest->n += inc->n; + inc->n = 0; +} + +/* Run a thread pool which gathers results in an array + * of hashes. Merge results. + */ + +static void merge_hash_results(struct worker_pool *pool OVS_UNUSED, + void *fin_result, void *result_frags, int index) +{ + struct hmap *result = (struct hmap *)fin_result; + struct hmap *res_frags = (struct hmap *)result_frags; + + fast_hmap_merge(result, &res_frags[index]); + hmap_destroy(&res_frags[index]); +} + + +void ovn_run_pool_hash( + struct worker_pool *pool, + struct hmap *result, + struct hmap *result_frags) +{ + ovn_run_pool_callback(pool, result, result_frags, merge_hash_results); +} + diff --git a/lib/fasthmap.h b/lib/fasthmap.h new file mode 100644 index 000000000..a362b0f5c --- /dev/null +++ b/lib/fasthmap.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2020 Red Hat, 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 HMAP_HAS_PARALLEL_MACROS +#define HMAP_HAS_PARALLEL_MACROS 1 + +/* if the parallel macros are defined by hmap.h or any other ovs define + * we skip over the ovn specific definitions. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include "openvswitch/util.h" +#include "openvswitch/hmap.h" +#include "openvswitch/thread.h" +#include "ovs-atomic.h" + +/* A version of the HMAP_FOR_EACH macro intended for iterating as part + * of parallel processing. + * Each worker thread has a different ThreadID in the range of 0..POOL_SIZE + * and will iterate hash buckets ThreadID, ThreadID + step, + * ThreadID + step * 2, etc. The actual macro accepts + * ThreadID + step * i as the JOBID parameter. + */ + +#define HMAP_FOR_EACH_IN_PARALLEL(NODE, MEMBER, JOBID, HMAP) \ + for (INIT_CONTAINER(NODE, hmap_first_in_bucket_num(HMAP, JOBID), MEMBER); \ + (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) \ + || ((NODE = NULL), false); \ + ASSIGN_CONTAINER(NODE, hmap_next_in_bucket(&(NODE)->MEMBER), MEMBER)) + +/* We do not have a SAFE version of the macro, because the hash size is not + * atomic and hash removal operations would need to be wrapped with + * locks. This will defeat most of the benefits from doing anything in + * parallel. + * If the code block inside FOR_EACH_IN_PARALLEL needs to remove elements, + * each thread should store them in a temporary list result instead, merging + * the lists into a combined result at the end */ + +/* Work "Handle" */ + +struct worker_control { + int id; /* Used as a modulo when iterating over a hash. */ + atomic_bool finished; /* Set to true after achunk of work is complete. */ + sem_t fire; /* Work start semaphore - sem_post starts the worker. */ + sem_t *done; /* Work completion semaphore - sem_post on completion. */ + struct ovs_mutex mutex; /* Guards the data. */ + void *data; /* Pointer to data to be processed. */ + void *workload; /* back-pointer to the worker pool structure. */ +}; + +struct worker_pool { + int size; /* Number of threads in the pool. */ + struct ovs_list list_node; /* List of pools - used in cleanup/exit. */ + struct worker_control *controls; /* "Handles" in this pool. */ + sem_t done; /* Work completion semaphorew. */ +}; + +/* Add a worker pool for thread function start() which expects a pointer to + * a worker_control structure as an argument. */ + +struct worker_pool *ovn_add_worker_pool(void *(*start)(void *)); + +/* Setting this to true will make all processing threads exit */ + +bool ovn_cease_fire(void); + +/* Build a hmap pre-sized for size elements */ + +void ovn_fast_hmap_size_for(struct hmap *hmap, int size); + +/* Build a hmap with a mask equals to size */ + +void ovn_fast_hmap_init(struct hmap *hmap, ssize_t size); + +/* Brute-force merge a hmap into hmap. + * Dest and inc have to have the same mask. The merge is performed + * by extending the element list for bucket N in the dest hmap with the list + * from bucket N in inc. + */ + +void ovn_fast_hmap_merge(struct hmap *dest, struct hmap *inc); + +/* Merge two lists. + * It is possible to achieve the same functionality using ovs_list_splice(). + * This ensures the splicing is exactly for tail of dest to head of inc. + */ + +void ovn_merge_lists(struct ovs_list **dest, struct ovs_list *inc); + +/* Run a pool, without any default processing of results. + */ + +void ovn_run_pool(struct worker_pool *pool); + +/* Run a pool, merge results from hash frags into a final hash result. + * The hash frags must be pre-sized to the same size. + */ + +void ovn_run_pool_hash(struct worker_pool *pool, + struct hmap *result, struct hmap *result_frags); + +/* Run a pool, call a callback function to perform processing of results. + */ + +void ovn_run_pool_callback(struct worker_pool *pool, void *fin_result, + void *result_frags, + void (*helper_func)(struct worker_pool *pool, + void *fin_result, void *result_frags, int index)); + + +/* Returns the first node in 'hmap' in the bucket in which the given 'hash' + * would land, or a null pointer if that bucket is empty. */ + +static inline struct hmap_node * +hmap_first_in_bucket_num(const struct hmap *hmap, size_t num) +{ + return hmap->buckets[num]; +} + +static inline struct hmap_node * +parallel_hmap_next__(const struct hmap *hmap, size_t start, size_t pool_size) +{ + size_t i; + for (i = start; i <= hmap->mask; i+= pool_size) { + struct hmap_node *node = hmap->buckets[i]; + if (node) { + return node; + } + } + return NULL; +} + +/* Returns the first node in 'hmap', as expected by thread with job_id + * for parallel processing in arbitrary order, or a null pointer if + * the slice of 'hmap' for that job_id is empty. */ +static inline struct hmap_node * +parallel_hmap_first(const struct hmap *hmap, size_t job_id, size_t pool_size) +{ + return parallel_hmap_next__(hmap, job_id, pool_size); +} + +/* Returns the next node in the slice of 'hmap' following 'node', + * in arbitrary order, or a * null pointer if 'node' is the last node in + * the 'hmap' slice. + * + */ +static inline struct hmap_node * +parallel_hmap_next(const struct hmap *hmap, + const struct hmap_node *node, ssize_t pool_size) +{ + return (node->next + ? node->next + : parallel_hmap_next__(hmap, + (node->hash & hmap->mask) + pool_size, pool_size)); +} + +/* Use the OVN library functions for stuff which OVS has not defined + * If OVS has defined these, they will still compile using the OVN + * local names, but will be dropped by the linker in favour of the OVS + * supplied functions. + */ + +#define cease_fire() ovn_cease_fire() + +#define add_worker_pool(start) ovn_add_worker_pool(start) + +#define fast_hmap_size_for(hmap, size) ovn_fast_hmap_size_for(hmap, size) + +#define fast_hmap_init(hmap, size) ovn_fast_hmap_init(hmap, size) + +#define fast_hmap_merge(dest, inc) ovn_fast_hmap_merge(dest, inc) + +#define hmap_merge(dest, inc) ovn_hmap_merge(dest, inc) + +#define ovn_run_pool(pool) ovn_run_pool(pool) + +#define run_pool_hash(pool, result, result_frags) \ + ovn_run_pool_hash(pool, result, result_frags) + +#define run_pool_callback(pool, fin_result, result_frags, helper_func) \ + ovn_run_pool_callback(pool, fin_result, result_frags, helper_func) + +#ifdef __cplusplus +} +#endif + +#endif /* lib/fast-hmap.h */ From patchwork Wed Oct 14 16:27:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382253 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.133; helo=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHrj1Dg9z9sVR for ; Thu, 15 Oct 2020 03:27:47 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 4086987DEE; Wed, 14 Oct 2020 16:27:46 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id yA2KExH7aBvI; Wed, 14 Oct 2020 16:27:44 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 419D387DAA; Wed, 14 Oct 2020 16:27:44 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1FD16C1AD5; Wed, 14 Oct 2020 16:27:44 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5D425C0051 for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 58BAC87D92 for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HQkfqawKZX0a for ; Wed, 14 Oct 2020 16:27:40 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by hemlock.osuosl.org (Postfix) with ESMTPS id C3AD987D8C for ; Wed, 14 Oct 2020 16:27:40 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcn-0000DX-Fq; Wed, 14 Oct 2020 16:27:37 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjck-0001Zd-Ks; Wed, 14 Oct 2020 17:27:36 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:07 +0100 Message-Id: <20201014162714.5978-2-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> References: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 2/9] ovn-northd: reorganize processing of lflows 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" From: Anton Ivanov 1. Merge lrouter and lswitch processing. 2. Move lrouter and lswitch lflow generation which uses the same iterator variables into common helpers 3. Set up structures to be used in parallel and sequential mode Signed-off-by: Anton Ivanov --- northd/ovn-northd.c | 191 ++++++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 77 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 366fdd95f..96309a98a 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -8978,24 +8978,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, struct ds actions = DS_EMPTY_INITIALIZER; struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { - build_adm_ctrl_flows_for_lrouter(od, lflows); - } - struct ovn_port *op; - HMAP_FOR_EACH (op, key_node, ports) { - build_adm_ctrl_flows_for_lrouter_port(op, lflows, &match, &actions); - } - - HMAP_FOR_EACH (od, key_node, datapaths) { - build_neigh_learning_flows_for_lrouter( - od, lflows, &match, &actions); - } - - HMAP_FOR_EACH (op, key_node, ports) { - build_neigh_learning_flows_for_lrouter_port( - op, lflows, &match, &actions); - } HMAP_FOR_EACH (od, key_node, datapaths) { if (!od->nbr) { @@ -9956,63 +9939,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, sset_destroy(&nat_entries); } - HMAP_FOR_EACH (op, key_node, ports) { - build_ND_RA_flows_for_lrouter_port(op, lflows, &match, &actions); - } - - /* Logical router ingress table ND_RA_OPTIONS & ND_RA_RESPONSE: RS - * responder, by default goto next. (priority 0). */ - HMAP_FOR_EACH (od, key_node, datapaths) { - build_ND_RA_flows_for_lrouter(od, lflows); - } - - HMAP_FOR_EACH (op, key_node, ports) { - build_ip_routing_flows_for_lrouter_port(op, lflows); - } - - /* Convert the static routes to flows. */ - HMAP_FOR_EACH (od, key_node, datapaths) { - build_static_route_flows_for_lrouter(od, lflows, ports); - } - - HMAP_FOR_EACH (od, key_node, datapaths) { - build_mcast_lookup_flows_for_lrouter(od, lflows, &match, &actions); - } - - HMAP_FOR_EACH (od, key_node, datapaths) { - build_ingress_policy_flows_for_lrouter(od, lflows, ports); - } - - /* XXX destination unreachable */ - - HMAP_FOR_EACH (od, key_node, datapaths) { - build_arp_resolve_flows_for_lrouter(od, lflows); - } - - HMAP_FOR_EACH (op, key_node, ports) { - build_arp_resolve_flows_for_lrouter_port( - op, lflows, ports, &match, &actions); - } - - HMAP_FOR_EACH (od, key_node, datapaths) { - build_check_pkt_len_flows_for_lrouter( - od, lflows, ports, &match, &actions); - } - - HMAP_FOR_EACH (od, key_node, datapaths) { - build_gateway_redirect_flows_for_lrouter( - od, lflows, &match, &actions); - } - - HMAP_FOR_EACH (od, key_node, datapaths) { - build_arp_request_flows_for_lrouter(od, lflows, &match, &actions); - } - - HMAP_FOR_EACH (op, key_node, ports) { - build_egress_delivery_flows_for_lrouter_port( - op, lflows, &match, &actions); - } - ds_destroy(&match); ds_destroy(&actions); } @@ -11421,6 +11347,117 @@ build_ipv6_input_flows_for_lrouter_port( } +struct lswitch_flow_build_info { + struct hmap *datapaths; + struct hmap *ports; + struct hmap *port_groups; + struct hmap *lflows; + struct hmap *mcgroups; + struct hmap *igmp_groups; + struct shash *meter_groups; + struct hmap *lbs; + char *svc_check_match; + struct ds match; + struct ds actions; +}; + +/* Helper function to combine all lflow generation which is iterated by + * datapath. + */ + +static void +build_lswitch_and_lrouter_iterate_by_od( + struct ovn_datapath *od, struct lswitch_flow_build_info *lsi) +{ + + /* Build Logical Router Flows. */ + build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); + build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match, + &lsi->actions); + build_ND_RA_flows_for_lrouter(od, lsi->lflows); + build_static_route_flows_for_lrouter(od, lsi->lflows, lsi->ports); + build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match, + &lsi->actions); + build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->ports); + build_arp_resolve_flows_for_lrouter(od, lsi->lflows); + build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->ports, + &lsi->match, &lsi->actions); + build_gateway_redirect_flows_for_lrouter(od, lsi->lflows, &lsi->match, + &lsi->actions); + build_arp_request_flows_for_lrouter(od, lsi->lflows, &lsi->match, + &lsi->actions); +} + +/* Helper function to combine all lflow generation which is iterated by port. + */ + +static void +build_lswitch_and_lrouter_iterate_by_op( + struct ovn_port *op, + struct lswitch_flow_build_info *lsi) +{ + /* Build Logical Router Flows. */ + + build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, + &lsi->actions); + build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, + &lsi->actions); + build_ip_routing_flows_for_lrouter_port(op, lsi->lflows); + build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, + &lsi->actions); + build_arp_resolve_flows_for_lrouter_port(op, lsi->lflows, lsi->ports, + &lsi->match, &lsi->actions); + build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, + &lsi->actions); +} + +static void +build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + struct hmap *port_groups, struct hmap *lflows, + struct hmap *mcgroups, struct hmap *igmp_groups, + struct shash *meter_groups, + struct hmap *lbs) +{ + + struct ovn_datapath *od; + struct ovn_port *op; + + char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac); + + struct lswitch_flow_build_info lsi = { + .datapaths = datapaths, + .ports = ports, + .port_groups = port_groups, + .lflows = lflows, + .mcgroups = mcgroups, + .igmp_groups = igmp_groups, + .meter_groups = meter_groups, + .lbs = lbs, + .svc_check_match = svc_check_match, + .match = DS_EMPTY_INITIALIZER, + .actions = DS_EMPTY_INITIALIZER, + }; + + /* Combined build - all lflow generation from lswitch and lrouter + * will move here and will be reogranized by iterator type. + */ + HMAP_FOR_EACH (od, key_node, datapaths) { + build_lswitch_and_lrouter_iterate_by_od(od, &lsi); + } + HMAP_FOR_EACH (op, key_node, ports) { + build_lswitch_and_lrouter_iterate_by_op(op, &lsi); + } + free(svc_check_match); + + /* Legacy lswitch build - to be migrated. */ + build_lswitch_flows(datapaths, ports, port_groups, lflows, mcgroups, + igmp_groups, meter_groups, lbs); + + /* Legacy lrouter build - to be migrated. */ + build_lrouter_flows(datapaths, ports, lflows, meter_groups, lbs); +} + + /* Updates the Logical_Flow and Multicast_Group tables in the OVN_SB database, * constructing their contents based on the OVN_NB database. */ static void @@ -11432,9 +11469,9 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths, { struct hmap lflows = HMAP_INITIALIZER(&lflows); - build_lswitch_flows(datapaths, ports, port_groups, &lflows, mcgroups, - igmp_groups, meter_groups, lbs); - build_lrouter_flows(datapaths, ports, &lflows, meter_groups, lbs); + build_lswitch_and_lrouter_flows(datapaths, ports, + port_groups, &lflows, mcgroups, + igmp_groups, meter_groups, lbs); /* Push changes to the Logical_Flow table to database. */ const struct sbrec_logical_flow *sbflow, *next_sbflow; From patchwork Wed Oct 14 16:27:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382252 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.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHrh0qtsz9sVS for ; Thu, 15 Oct 2020 03:27:47 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id CD5B187AED; Wed, 14 Oct 2020 16:27:44 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WZmLWSBqb-5n; Wed, 14 Oct 2020 16:27:43 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 7097287647; Wed, 14 Oct 2020 16:27:43 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 53C34C0052; Wed, 14 Oct 2020 16:27:43 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 66CECC0052 for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 62F0C87D8C for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ITLNep9LJKR7 for ; Wed, 14 Oct 2020 16:27:41 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by hemlock.osuosl.org (Postfix) with ESMTPS id D40DE87D91 for ; Wed, 14 Oct 2020 16:27:40 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcp-0000Dg-AI; Wed, 14 Oct 2020 16:27:39 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjcm-0001Zd-DN; Wed, 14 Oct 2020 17:27:38 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:08 +0100 Message-Id: <20201014162714.5978-3-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> References: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 3/9] ovn-northd: introduce parallel lflow build 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" From: Anton Ivanov 1. Add support for parallel lflow build. 2. Move combined lflow generation to be build in parallel. Signed-off-by: Anton Ivanov --- northd/ovn-northd.c | 192 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 166 insertions(+), 26 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 96309a98a..e8f167d8d 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -48,6 +48,7 @@ #include "unixctl.h" #include "util.h" #include "uuid.h" +#include "fasthmap.h" #include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovn_northd); @@ -4235,7 +4236,7 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, ovn_lflow_init(lflow, od, stage, priority, xstrdup(match), xstrdup(actions), ovn_lflow_hint(stage_hint), where); - hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow)); + hmap_insert_fast(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow)); } /* Adds a row with the specified contents to the Logical_Flow table. */ @@ -11363,6 +11364,8 @@ struct lswitch_flow_build_info { /* Helper function to combine all lflow generation which is iterated by * datapath. + * Invoked by parallel build over a "chunk" of work or by single threaded + * build over a chunk which is initialized to contain "all" work. */ static void @@ -11389,6 +11392,8 @@ build_lswitch_and_lrouter_iterate_by_od( } /* Helper function to combine all lflow generation which is iterated by port. + * Invoked by parallel build over a "chunk" of work or by single threaded + * build over a chunk which is initialized to contain "all" work. */ static void @@ -11411,6 +11416,85 @@ build_lswitch_and_lrouter_iterate_by_op( &lsi->actions); } +struct lflows_thread_pool { + struct worker_pool *pool; +}; + +static void *build_lflows_thread(void *arg) { + struct worker_control *control = (struct worker_control *) arg; + struct lflows_thread_pool *workload; + struct lswitch_flow_build_info *lsi; + + struct ovn_datapath *od; + struct ovn_port *op; + int bnum; + + while (!cease_fire()) { + sem_wait(&control->fire); + workload = (struct lflows_thread_pool *) control->workload; + lsi = (struct lswitch_flow_build_info *) control->data; + if (lsi && workload) { + /* Iterate over bucket ThreadID, ThreadID+size, ... */ + for (bnum = control->id; + bnum <= lsi->datapaths->mask; + bnum += workload->pool->size) + { + HMAP_FOR_EACH_IN_PARALLEL ( + od, key_node, bnum, lsi->datapaths) { + if (cease_fire()) { + return NULL; + } + build_lswitch_and_lrouter_iterate_by_od(od, lsi); + } + } + for (bnum = control->id; + bnum <= lsi->ports->mask; + bnum += workload->pool->size) + { + HMAP_FOR_EACH_IN_PARALLEL ( + op, key_node, bnum, lsi->ports) { + if (cease_fire()) { + return NULL; + } + build_lswitch_and_lrouter_iterate_by_op(op, lsi); + } + } + atomic_store_relaxed(&control->finished, true); + atomic_thread_fence(memory_order_release); + } + sem_post(control->done); + } + return NULL; +} + +static struct lflows_thread_pool *build_lflows_pool = NULL; + +static void init_lflows_thread_pool(void) +{ + int index; + + if (!build_lflows_pool) { + build_lflows_pool = + xmalloc(sizeof(struct lflows_thread_pool)); + build_lflows_pool->pool = + add_worker_pool(build_lflows_thread); + + for (index = 0; index < build_lflows_pool->pool->size; index++) { + build_lflows_pool->pool->controls[index].workload = + build_lflows_pool; + } + } +} + +/* TODO: replace hard cutoffs by configurable via commands. These are + * temporary defines to determine single-thread to multi-thread processing + * cutoff. + * Setting to 1 forces "all parallel" lflow build. + */ + +#define OD_CUTOFF 1 +#define OP_CUTOFF 1 + static void build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports, struct hmap *port_groups, struct hmap *lflows, @@ -11418,35 +11502,84 @@ build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports, struct shash *meter_groups, struct hmap *lbs) { + char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac); - struct ovn_datapath *od; - struct ovn_port *op; + if (hmap_count(datapaths) > OD_CUTOFF || hmap_count(ports) > OP_CUTOFF) { - char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac); + struct hmap *lflow_segs; + struct lswitch_flow_build_info *lsiv; + int index; - struct lswitch_flow_build_info lsi = { - .datapaths = datapaths, - .ports = ports, - .port_groups = port_groups, - .lflows = lflows, - .mcgroups = mcgroups, - .igmp_groups = igmp_groups, - .meter_groups = meter_groups, - .lbs = lbs, - .svc_check_match = svc_check_match, - .match = DS_EMPTY_INITIALIZER, - .actions = DS_EMPTY_INITIALIZER, - }; + init_lflows_thread_pool(); + lsiv = xmalloc( + sizeof(struct lswitch_flow_build_info) * + build_lflows_pool->pool->size); + lflow_segs = xmalloc( + sizeof(struct hmap) * build_lflows_pool->pool->size); - /* Combined build - all lflow generation from lswitch and lrouter - * will move here and will be reogranized by iterator type. - */ - HMAP_FOR_EACH (od, key_node, datapaths) { - build_lswitch_and_lrouter_iterate_by_od(od, &lsi); - } - HMAP_FOR_EACH (op, key_node, ports) { - build_lswitch_and_lrouter_iterate_by_op(op, &lsi); + /* Set up "work chunks" for each thread to work on. */ + + for (index = 0; index < build_lflows_pool->pool->size; index++) { + fast_hmap_init(&lflow_segs[index], lflows->mask); + + lsiv[index].datapaths = datapaths; + lsiv[index].ports = ports; + lsiv[index].port_groups = port_groups; + lsiv[index].lflows = &lflow_segs[index]; + lsiv[index].mcgroups = mcgroups; + lsiv[index].igmp_groups = igmp_groups; + lsiv[index].meter_groups = meter_groups; + lsiv[index].lbs = lbs; + lsiv[index].svc_check_match = svc_check_match; + ds_init(&lsiv[index].match); + ds_init(&lsiv[index].actions); + + build_lflows_pool->pool->controls[index].data = &lsiv[index]; + } + + /* Run thread pool. */ + + run_pool_hash(build_lflows_pool->pool, lflows, lflow_segs); + + for (index = 0; index < build_lflows_pool->pool->size; index++) { + ds_destroy(&lsiv[index].match); + ds_destroy(&lsiv[index].actions); + } + + free(lflow_segs); + free(lsiv); + } else { + struct ovn_datapath *od; + struct ovn_port *op; + + struct lswitch_flow_build_info lsi = { + .datapaths = datapaths, + .ports = ports, + .port_groups = port_groups, + .lflows = lflows, + .mcgroups = mcgroups, + .igmp_groups = igmp_groups, + .meter_groups = meter_groups, + .lbs = lbs, + .svc_check_match = svc_check_match, + .match = DS_EMPTY_INITIALIZER, + .actions = DS_EMPTY_INITIALIZER, + }; + + + /* Converged build - all lflow generation from lswitch and lrouter + * will move here and will be reogranized by iterator type. + */ + HMAP_FOR_EACH (od, key_node, datapaths) { + build_lswitch_and_lrouter_iterate_by_od(od, &lsi); + } + HMAP_FOR_EACH (op, key_node, ports) { + build_lswitch_and_lrouter_iterate_by_op(op, &lsi); + } + ds_destroy(&lsi.match); + ds_destroy(&lsi.actions); } + free(svc_check_match); /* Legacy lswitch build - to be migrated. */ @@ -11457,6 +11590,7 @@ build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports, build_lrouter_flows(datapaths, ports, lflows, meter_groups, lbs); } +static ssize_t max_seen_lflow_size = 128; /* Updates the Logical_Flow and Multicast_Group tables in the OVN_SB database, * constructing their contents based on the OVN_NB database. */ @@ -11467,12 +11601,18 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths, struct shash *meter_groups, struct hmap *lbs) { - struct hmap lflows = HMAP_INITIALIZER(&lflows); + struct hmap lflows; + + fast_hmap_size_for(&lflows, max_seen_lflow_size); build_lswitch_and_lrouter_flows(datapaths, ports, port_groups, &lflows, mcgroups, igmp_groups, meter_groups, lbs); + if (hmap_count(&lflows) > max_seen_lflow_size) { + max_seen_lflow_size = hmap_count(&lflows); + } + /* Push changes to the Logical_Flow table to database. */ const struct sbrec_logical_flow *sbflow, *next_sbflow; SBREC_LOGICAL_FLOW_FOR_EACH_SAFE (sbflow, next_sbflow, ctx->ovnsb_idl) { From patchwork Wed Oct 14 16:27:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382254 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.133; helo=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHrl2qyfz9sVf for ; Thu, 15 Oct 2020 03:27:51 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id D0E7C87DE2; Wed, 14 Oct 2020 16:27:48 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rCojb0RHhrRS; Wed, 14 Oct 2020 16:27:46 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id EA35A87DEA; Wed, 14 Oct 2020 16:27:45 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id D8E3AC1AD4; Wed, 14 Oct 2020 16:27:45 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id E19D2C0051 for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id D126986C5A for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id d9_ZLDnv9zXz for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 582CA87A08 for ; Wed, 14 Oct 2020 16:27:42 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcq-0000Dq-TA; Wed, 14 Oct 2020 16:27:41 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjco-0001Zd-7g; Wed, 14 Oct 2020 17:27:39 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:09 +0100 Message-Id: <20201014162714.5978-4-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> References: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 4/9] ovn-northd: Add commands to set/get parallelisation thresholds 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" From: Anton Ivanov Add commands to control and display single-threaded to multi- threaded cutoff. Signed-off-by: Anton Ivanov --- northd/ovn-northd.c | 47 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index e8f167d8d..cb9e791f3 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -59,6 +59,8 @@ static unixctl_cb_func ovn_northd_resume; static unixctl_cb_func ovn_northd_is_paused; static unixctl_cb_func ovn_northd_status; static unixctl_cb_func cluster_state_reset_cmd; +static unixctl_cb_func get_param_cutoff; +static unixctl_cb_func set_param_cutoff; struct northd_context { struct ovsdb_idl *ovnnb_idl; @@ -11492,8 +11494,8 @@ static void init_lflows_thread_pool(void) * Setting to 1 forces "all parallel" lflow build. */ -#define OD_CUTOFF 1 -#define OP_CUTOFF 1 +static ssize_t lflow_od_cuttoff = 1; +static ssize_t lflow_op_cutoff = 1; static void build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports, @@ -11504,7 +11506,8 @@ build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports, { char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac); - if (hmap_count(datapaths) > OD_CUTOFF || hmap_count(ports) > OP_CUTOFF) { + if (hmap_count(datapaths) > lflow_od_cuttoff || + hmap_count(ports) > lflow_op_cutoff) { struct hmap *lflow_segs; struct lswitch_flow_build_info *lsiv; @@ -13184,6 +13187,14 @@ main(int argc, char *argv[]) unixctl_command_register("is-paused", "", 0, 0, ovn_northd_is_paused, &state); unixctl_command_register("status", "", 0, 0, ovn_northd_status, &state); + unixctl_command_register("set-datapath-cutoff", "", 0, 0, + set_param_cutoff, &lflow_od_cuttoff); + unixctl_command_register("set-port-cutoff", "", 0, 0, + set_param_cutoff, &lflow_op_cutoff); + unixctl_command_register("get-datapath-cutoff", "", 0, 0, + get_param_cutoff, &lflow_od_cuttoff); + unixctl_command_register("get-port-cutoff", "", 0, 0, + get_param_cutoff, &lflow_op_cutoff); bool reset_ovnsb_idl_min_index = false; unixctl_command_register("sb-cluster-state-reset", "", 0, 0, @@ -13609,3 +13620,33 @@ cluster_state_reset_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED, poll_immediate_wake(); unixctl_command_reply(conn, NULL); } + +static void set_param_cutoff +(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], + void *param_) +{ + long new_cutoff; + ssize_t *param = param_; + + if (str_to_long(argv[1], 10, &new_cutoff)) { + if (new_cutoff > 0) { + *param = new_cutoff; + return; + } + } + unixctl_command_reply_error(conn, "unsigned integer required"); +} + +static void get_param_cutoff +(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, + void *param_) +{ + struct ds ds = DS_EMPTY_INITIALIZER; + ssize_t *param = param_; + + ds_put_format(&ds, "%ld\n", *param); + unixctl_command_reply(conn, ds_cstr(&ds)); + ds_destroy(&ds); +} From patchwork Wed Oct 14 16:27:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382259 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.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHsT6lJxz9sTL for ; Thu, 15 Oct 2020 03:28:29 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id C82082E56D; Wed, 14 Oct 2020 16:28:26 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id V8VnvL7joH1u; Wed, 14 Oct 2020 16:28:15 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 8D20F2E511; Wed, 14 Oct 2020 16:27:56 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 81888C1ADA; Wed, 14 Oct 2020 16:27:56 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 16523C0051 for ; Wed, 14 Oct 2020 16:27:55 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 025002E511 for ; Wed, 14 Oct 2020 16:27:55 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id s33yhkLK-xfs for ; Wed, 14 Oct 2020 16:27:50 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by silver.osuosl.org (Postfix) with ESMTPS id D5FF42E2B3 for ; Wed, 14 Oct 2020 16:27:44 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcs-0000Dw-KL; Wed, 14 Oct 2020 16:27:42 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjcp-0001Zd-UN; Wed, 14 Oct 2020 17:27:41 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:10 +0100 Message-Id: <20201014162714.5978-5-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> References: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 5/9] ovn-northd: move pre-acl and acl lswitch processing to a function 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" From: Anton Ivanov Move pre-acl and acl lswitch processing to a function Invoke the pre-acl and acl lswitch processing out of the converged processing od loop. Signed-off-by: Anton Ivanov --- northd/ovn-northd.c | 52 +++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index cb9e791f3..04645da01 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -6829,34 +6829,15 @@ build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op, static void build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, - struct hmap *port_groups, struct hmap *lflows, - struct hmap *mcgroups, struct hmap *igmp_groups, - struct shash *meter_groups, - struct hmap *lbs) + struct hmap *lflows, struct hmap *mcgroups, + struct hmap *igmp_groups, struct hmap *lbs) { /* This flow table structure is documented in ovn-northd(8), so please * update ovn-northd.8.xml if you change anything. */ struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; - - /* Build pre-ACL and ACL tables for both ingress and egress. - * Ingress tables 3 through 10. Egress tables 0 through 7. */ struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs) { - continue; - } - - build_pre_acls(od, lflows); - build_pre_lb(od, lflows, meter_groups, lbs); - build_pre_stateful(od, lflows); - build_acl_hints(od, lflows); - build_acls(od, lflows, port_groups); - build_qos(od, lflows); - build_lb(od, lflows); - build_stateful(od, lflows, lbs); - } /* Build logical flows for the forwarding groups */ HMAP_FOR_EACH (od, key_node, datapaths) { @@ -7533,6 +7514,27 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, ds_destroy(&actions); } +/* Build pre-ACL and ACL tables for both ingress and egress. + * Ingress tables 3 through 10. Egress tables 0 through 7. */ +static void + build_lswitch_lflows_pre_acl_and_acl( + struct ovn_datapath *od, struct hmap *port_groups, + struct hmap *lflows, struct shash *meter_groups, + struct hmap *lbs) +{ + if (od->nbs) { + build_pre_acls(od, lflows); + build_pre_lb(od, lflows, meter_groups, lbs); + build_pre_stateful(od, lflows); + build_acl_hints(od, lflows); + build_acls(od, lflows, port_groups); + build_qos(od, lflows); + build_lb(od, lflows); + build_stateful(od, lflows, lbs); + } +} + + /* Returns a string of the IP address of the router port 'op' that * overlaps with 'ip_s". If one is not found, returns NULL. * @@ -11374,6 +11376,10 @@ static void build_lswitch_and_lrouter_iterate_by_od( struct ovn_datapath *od, struct lswitch_flow_build_info *lsi) { + /* Build Logical Switch Flows. */ + + build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups, lsi->lflows, + lsi->meter_groups, lsi->lbs); /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); @@ -11586,8 +11592,8 @@ build_lswitch_and_lrouter_flows(struct hmap *datapaths, struct hmap *ports, free(svc_check_match); /* Legacy lswitch build - to be migrated. */ - build_lswitch_flows(datapaths, ports, port_groups, lflows, mcgroups, - igmp_groups, meter_groups, lbs); + build_lswitch_flows(datapaths, ports, lflows, mcgroups, + igmp_groups, lbs); /* Legacy lrouter build - to be migrated. */ build_lrouter_flows(datapaths, ports, lflows, meter_groups, lbs); From patchwork Wed Oct 14 16:27:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382258 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=whitealder.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHsR6XDVz9sTL for ; Thu, 15 Oct 2020 03:28:27 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 79287880F0; Wed, 14 Oct 2020 16:28:26 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id yrBBjfe8smW7; Wed, 14 Oct 2020 16:28:20 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id D7F61880B7; Wed, 14 Oct 2020 16:28:03 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id CBECBC0051; Wed, 14 Oct 2020 16:28:03 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4CF5FC1AD6 for ; Wed, 14 Oct 2020 16:28:02 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 226222E534 for ; Wed, 14 Oct 2020 16:28:02 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qnItd2DogsVr for ; Wed, 14 Oct 2020 16:27:54 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by silver.osuosl.org (Postfix) with ESMTPS id DFAFB2E2BE for ; Wed, 14 Oct 2020 16:27:45 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcu-0000E2-Ed; Wed, 14 Oct 2020 16:27:44 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjcr-0001Zd-Ko; Wed, 14 Oct 2020 17:27:43 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:11 +0100 Message-Id: <20201014162714.5978-6-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> References: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 6/9] ovn-northd: migrate build_fwd_group_lflows to build_converged 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" From: Anton Ivanov 1. Move the condition from the old HMAP_FOR_EACH loop into the build_fwd_group_lflows() function. 2. Move build_fwd_group_lflows() into the converged build helper function Signed-off-by: Anton Ivanov --- northd/ovn-northd.c | 112 ++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 04645da01..4d2caf0c2 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -6186,64 +6186,69 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows, struct hmap *lbs) ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;"); } +/* Build logical flows for the forwarding groups */ static void build_fwd_group_lflows(struct ovn_datapath *od, struct hmap *lflows) { - struct ds match = DS_EMPTY_INITIALIZER; - struct ds actions = DS_EMPTY_INITIALIZER; - for (int i = 0; i < od->nbs->n_forwarding_groups; ++i) { - const struct nbrec_forwarding_group *fwd_group = NULL; - fwd_group = od->nbs->forwarding_groups[i]; - if (!fwd_group->n_child_port) { - continue; - } + if (!(!od->nbs || !od->nbs->n_forwarding_groups)) { + struct ds match = DS_EMPTY_INITIALIZER; + struct ds actions = DS_EMPTY_INITIALIZER; - /* ARP responder for the forwarding group's virtual IP */ - ds_put_format(&match, "arp.tpa == %s && arp.op == 1", - fwd_group->vip); - ds_put_format(&actions, - "eth.dst = eth.src; " - "eth.src = %s; " - "arp.op = 2; /* ARP reply */ " - "arp.tha = arp.sha; " - "arp.sha = %s; " - "arp.tpa = arp.spa; " - "arp.spa = %s; " - "outport = inport; " - "flags.loopback = 1; " - "output;", - fwd_group->vmac, fwd_group->vmac, fwd_group->vip); - - ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 50, - ds_cstr(&match), ds_cstr(&actions), - &fwd_group->header_); + for (int i = 0; i < od->nbs->n_forwarding_groups; ++i) { + const struct nbrec_forwarding_group *fwd_group = NULL; + fwd_group = od->nbs->forwarding_groups[i]; + if (!fwd_group->n_child_port) { + continue; + } - /* L2 lookup for the forwarding group's virtual MAC */ - ds_clear(&match); - ds_put_format(&match, "eth.dst == %s", fwd_group->vmac); + /* ARP responder for the forwarding group's virtual IP */ + ds_put_format(&match, "arp.tpa == %s && arp.op == 1", + fwd_group->vip); + ds_put_format(&actions, + "eth.dst = eth.src; " + "eth.src = %s; " + "arp.op = 2; /* ARP reply */ " + "arp.tha = arp.sha; " + "arp.sha = %s; " + "arp.tpa = arp.spa; " + "arp.spa = %s; " + "outport = inport; " + "flags.loopback = 1; " + "output;", + fwd_group->vmac, fwd_group->vmac, fwd_group->vip); + + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(&match), ds_cstr(&actions), + &fwd_group->header_); - /* Create a comma separated string of child ports */ - struct ds group_ports = DS_EMPTY_INITIALIZER; - if (fwd_group->liveness) { - ds_put_cstr(&group_ports, "liveness=\"true\","); - } - ds_put_cstr(&group_ports, "childports="); - for (i = 0; i < (fwd_group->n_child_port - 1); ++i) { - ds_put_format(&group_ports, "\"%s\",", fwd_group->child_port[i]); + /* L2 lookup for the forwarding group's virtual MAC */ + ds_clear(&match); + ds_put_format(&match, "eth.dst == %s", fwd_group->vmac); + + /* Create a comma separated string of child ports */ + struct ds group_ports = DS_EMPTY_INITIALIZER; + if (fwd_group->liveness) { + ds_put_cstr(&group_ports, "liveness=\"true\","); + } + ds_put_cstr(&group_ports, "childports="); + for (i = 0; i < (fwd_group->n_child_port - 1); ++i) { + ds_put_format( + &group_ports, "\"%s\",", fwd_group->child_port[i]); + } + ds_put_format(&group_ports, "\"%s\"", + fwd_group->child_port[fwd_group->n_child_port - 1]); + + ds_clear(&actions); + ds_put_format(&actions, "fwd_group(%s);", ds_cstr(&group_ports)); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, 50, + ds_cstr(&match), ds_cstr(&actions), + &fwd_group->header_); } - ds_put_format(&group_ports, "\"%s\"", - fwd_group->child_port[fwd_group->n_child_port - 1]); - ds_clear(&actions); - ds_put_format(&actions, "fwd_group(%s);", ds_cstr(&group_ports)); - ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, 50, - ds_cstr(&match), ds_cstr(&actions), - &fwd_group->header_); + ds_destroy(&match); + ds_destroy(&actions); } - - ds_destroy(&match); - ds_destroy(&actions); } static void @@ -6839,15 +6844,6 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, struct ds actions = DS_EMPTY_INITIALIZER; struct ovn_datapath *od; - /* Build logical flows for the forwarding groups */ - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs || !od->nbs->n_forwarding_groups) { - continue; - } - - build_fwd_group_lflows(od, lflows); - } - /* Logical switch ingress table 0: Admission control framework (priority * 100). */ HMAP_FOR_EACH (od, key_node, datapaths) { @@ -11381,6 +11377,8 @@ build_lswitch_and_lrouter_iterate_by_od( build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups, lsi->lflows, lsi->meter_groups, lsi->lbs); + build_fwd_group_lflows(od, lsi->lflows); + /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match, From patchwork Wed Oct 14 16:27:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382257 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.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHsP3rTDz9sTL for ; Thu, 15 Oct 2020 03:28:25 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id C6A042E568; Wed, 14 Oct 2020 16:28:23 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id xVfh7J1GLkHs; Wed, 14 Oct 2020 16:28:11 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id CA2912E507; Wed, 14 Oct 2020 16:27:53 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id AF0A7C0891; Wed, 14 Oct 2020 16:27:53 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 14A3BC0052 for ; Wed, 14 Oct 2020 16:27:53 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 0270487B4E for ; Wed, 14 Oct 2020 16:27:53 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id XoleXHzbiQ0O for ; Wed, 14 Oct 2020 16:27:51 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 7AB4A87AD8 for ; Wed, 14 Oct 2020 16:27:47 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcw-0000E8-32; Wed, 14 Oct 2020 16:27:46 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjct-0001Zd-Cz; Wed, 14 Oct 2020 17:27:45 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:12 +0100 Message-Id: <20201014162714.5978-7-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> References: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 7/9] ovn-northd: Move lswitch admission control to a helper function 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" From: Anton Ivanov 1. Move the admission control lflows to a helper function 2. Add the helper function to the converged build per-od loop. Signed-off-by: Anton Ivanov --- northd/ovn-northd.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 4d2caf0c2..cbd18d9aa 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -6844,25 +6844,6 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, struct ds actions = DS_EMPTY_INITIALIZER; struct ovn_datapath *od; - /* Logical switch ingress table 0: Admission control framework (priority - * 100). */ - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs) { - continue; - } - - /* Logical VLANs not supported. */ - ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_L2, 100, "vlan.present", - "drop;"); - - /* Broadcast/multicast source address is invalid. */ - ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_L2, 100, "eth.src[40]", - "drop;"); - - /* Port security flows have priority 50 (see below) and will continue - * to the next table if packet source is acceptable. */ - } - build_lswitch_input_port_sec(ports, datapaths, lflows); /* Ingress table 13: ARP/ND responder, skip requests coming from localnet @@ -7530,6 +7511,27 @@ static void } } +/* Logical switch ingress table 0: Admission control framework (priority + * 100). */ +static void + build_lswitch_lflows_admission_control( + struct ovn_datapath *od, struct hmap *lflows) +{ + if (od->nbs) { + + /* Logical VLANs not supported. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_L2, 100, "vlan.present", + "drop;"); + + /* Broadcast/multicast source address is invalid. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_L2, 100, "eth.src[40]", + "drop;"); + + /* Port security flows have priority 50 (see below) and will continue + * to the next table if packet source is acceptable. */ + } +} + /* Returns a string of the IP address of the router port 'op' that * overlaps with 'ip_s". If one is not found, returns NULL. @@ -11378,6 +11380,7 @@ build_lswitch_and_lrouter_iterate_by_od( lsi->meter_groups, lsi->lbs); build_fwd_group_lflows(od, lsi->lflows); + build_lswitch_lflows_admission_control(od, lsi->lflows); /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); From patchwork Wed Oct 14 16:27:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382260 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.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHtM0bdkz9sTL for ; Thu, 15 Oct 2020 03:29:15 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 72B962E52A; Wed, 14 Oct 2020 16:29:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EVcD4ulHzI2F; Wed, 14 Oct 2020 16:29:01 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id A10A22E542; Wed, 14 Oct 2020 16:28:05 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6DC75C1AD5; Wed, 14 Oct 2020 16:28:05 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 094EAC0052 for ; Wed, 14 Oct 2020 16:28:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id E88C98809E for ; Wed, 14 Oct 2020 16:28:02 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 39nqsMT05pG1 for ; Wed, 14 Oct 2020 16:27:58 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by whitealder.osuosl.org (Postfix) with ESMTPS id ADF2F880B6 for ; Wed, 14 Oct 2020 16:27:49 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcx-0000EE-RK; Wed, 14 Oct 2020 16:27:48 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjcv-0001Zd-3h; Wed, 14 Oct 2020 17:27:46 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:13 +0100 Message-Id: <20201014162714.5978-8-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> References: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 8/9] ovn-northd: migrate input port security flows to converged build 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" From: Anton Ivanov 1. Split build_lswitch_input_port_sec into per-datapath and per-port iterators 2. Reuse common scratchpad in the per-port build 3. Migrate the two new functions to the converged build loops Signed-off-by: Anton Ivanov --- northd/ovn-northd.c | 102 +++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index cbd18d9aa..bda83e106 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -4841,70 +4841,64 @@ has_stateful_acl(struct ovn_datapath *od) return false; } +/* Logical switch ingress table 0: Ingress port security - L2 + * (priority 50). + * Ingress table 1: Ingress port security - IP (priority 90 and 80) + * Ingress table 2: Ingress port security - ND (priority 90 and 80) + */ static void -build_lswitch_input_port_sec(struct hmap *ports, struct hmap *datapaths, - struct hmap *lflows) +build_lswitch_input_port_sec_op( + struct ovn_port *op, struct hmap *lflows, + struct ds *actions, struct ds *match) { - /* Logical switch ingress table 0: Ingress port security - L2 - * (priority 50). - * Ingress table 1: Ingress port security - IP (priority 90 and 80) - * Ingress table 2: Ingress port security - ND (priority 90 and 80) - */ - struct ds actions = DS_EMPTY_INITIALIZER; - struct ds match = DS_EMPTY_INITIALIZER; - struct ovn_port *op; - HMAP_FOR_EACH (op, key_node, ports) { - if (!op->nbsp) { - continue; - } + if (!op->nbsp) { + return; + } - if (!lsp_is_enabled(op->nbsp)) { - /* Drop packets from disabled logical ports (since logical flow - * tables are default-drop). */ - continue; - } + if (!lsp_is_enabled(op->nbsp)) { + /* Drop packets from disabled logical ports (since logical flow + * tables are default-drop). */ + return; + } - if (lsp_is_external(op->nbsp)) { - continue; - } + if (lsp_is_external(op->nbsp)) { + return; + } - ds_clear(&match); - ds_clear(&actions); - ds_put_format(&match, "inport == %s", op->json_key); - build_port_security_l2("eth.src", op->ps_addrs, op->n_ps_addrs, - &match); + ds_clear(match); + ds_clear(actions); + ds_put_format(match, "inport == %s", op->json_key); + build_port_security_l2("eth.src", op->ps_addrs, op->n_ps_addrs, + match); - const char *queue_id = smap_get(&op->sb->options, "qdisc_queue_id"); - if (queue_id) { - ds_put_format(&actions, "set_queue(%s); ", queue_id); - } - ds_put_cstr(&actions, "next;"); - ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50, - ds_cstr(&match), ds_cstr(&actions), - &op->nbsp->header_); + const char *queue_id = smap_get(&op->sb->options, "qdisc_queue_id"); + if (queue_id) { + ds_put_format(actions, "set_queue(%s); ", queue_id); + } + ds_put_cstr(actions, "next;"); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50, + ds_cstr(match), ds_cstr(actions), + &op->nbsp->header_); - if (op->nbsp->n_port_security) { - build_port_security_ip(P_IN, op, lflows, &op->nbsp->header_); - build_port_security_nd(op, lflows, &op->nbsp->header_); - } + if (op->nbsp->n_port_security) { + build_port_security_ip(P_IN, op, lflows, &op->nbsp->header_); + build_port_security_nd(op, lflows, &op->nbsp->header_); } +} - /* Ingress table 1 and 2: Port security - IP and ND, by default - * goto next. (priority 0) - */ - struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs) { - continue; - } +/* Ingress table 1 and 2: Port security - IP and ND, by default + * goto next. (priority 0) + */ +static void +build_lswitch_input_port_sec_od( + struct ovn_datapath *od, struct hmap *lflows) +{ + if (od->nbs) { ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_ND, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_IP, 0, "1", "next;"); } - - ds_destroy(&match); - ds_destroy(&actions); } static void @@ -6844,8 +6838,6 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, struct ds actions = DS_EMPTY_INITIALIZER; struct ovn_datapath *od; - build_lswitch_input_port_sec(ports, datapaths, lflows); - /* Ingress table 13: ARP/ND responder, skip requests coming from localnet * and vtep ports. (priority 100); see ovn-northd.8.xml for the * rationale. */ @@ -11381,6 +11373,7 @@ build_lswitch_and_lrouter_iterate_by_od( build_fwd_group_lflows(od, lsi->lflows); build_lswitch_lflows_admission_control(od, lsi->lflows); + build_lswitch_input_port_sec_od(od, lsi->lflows); /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); @@ -11410,8 +11403,11 @@ build_lswitch_and_lrouter_iterate_by_op( struct ovn_port *op, struct lswitch_flow_build_info *lsi) { - /* Build Logical Router Flows. */ + /* Build Logical Switch Flows. */ + build_lswitch_input_port_sec_op(op, lsi->lflows, &lsi->actions, + &lsi->match); + /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions); build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, From patchwork Wed Oct 14 16:27:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Ivanov X-Patchwork-Id: 1382256 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.133; helo=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=cambridgegreys.com Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CBHsK2wBsz9sVR for ; Thu, 15 Oct 2020 03:28:21 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 98AAC87E2C; Wed, 14 Oct 2020 16:28:19 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id W-gisHnCDxRB; Wed, 14 Oct 2020 16:28:14 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id DB4F687E1E; Wed, 14 Oct 2020 16:28:07 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id AE854C0891; Wed, 14 Oct 2020 16:28:07 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1C00CC1AD6 for ; Wed, 14 Oct 2020 16:28:06 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 0B3C98810B for ; Wed, 14 Oct 2020 16:28:06 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vUUa+fOHbe0j for ; Wed, 14 Oct 2020 16:27:59 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from www.kot-begemot.co.uk (ivanoab7.miniserver.com [37.128.132.42]) by whitealder.osuosl.org (Postfix) with ESMTPS id 9FD6B880B1 for ; Wed, 14 Oct 2020 16:27:51 +0000 (UTC) Received: from tun252.jain.kot-begemot.co.uk ([192.168.18.6] helo=jain.kot-begemot.co.uk) by www.kot-begemot.co.uk with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kSjcz-0000EK-UO; Wed, 14 Oct 2020 16:27:50 +0000 Received: from jain.kot-begemot.co.uk ([192.168.3.3]) by jain.kot-begemot.co.uk with esmtp (Exim 4.92) (envelope-from ) id 1kSjcw-0001Zd-R6; Wed, 14 Oct 2020 17:27:48 +0100 From: anton.ivanov@cambridgegreys.com To: dev@openvswitch.org Date: Wed, 14 Oct 2020 17:27:14 +0100 Message-Id: <20201014162714.5978-9-anton.ivanov@cambridgegreys.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> References: <20201014162714.5978-1-anton.ivanov@cambridgegreys.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett Cc: i.maximets@ovn.org, Anton Ivanov Subject: [ovs-dev] [PATCH ovn v5 9/9] ovn-northd: migrate lswitch arp responder to converged build 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" From: Anton Ivanov Move the processing for arp responder, arp responder known ips and arp responder skip to next to helper functions. Move the invocation of the helper functions to the converged build. Signed-off-by: Anton Ivanov --- northd/ovn-northd.c | 396 +++++++++++++++++++++++--------------------- 1 file changed, 205 insertions(+), 191 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index bda83e106..9530dd55e 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -6837,198 +6837,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; struct ovn_datapath *od; - - /* Ingress table 13: ARP/ND responder, skip requests coming from localnet - * and vtep ports. (priority 100); see ovn-northd.8.xml for the - * rationale. */ struct ovn_port *op; - HMAP_FOR_EACH (op, key_node, ports) { - if (!op->nbsp) { - continue; - } - - if ((!strcmp(op->nbsp->type, "localnet")) || - (!strcmp(op->nbsp->type, "vtep"))) { - ds_clear(&match); - ds_put_format(&match, "inport == %s", op->json_key); - ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, - 100, ds_cstr(&match), "next;", - &op->nbsp->header_); - } - } - - /* Ingress table 13: ARP/ND responder, reply for known IPs. - * (priority 50). */ - HMAP_FOR_EACH (op, key_node, ports) { - if (!op->nbsp) { - continue; - } - - if (!strcmp(op->nbsp->type, "virtual")) { - /* Handle - * - GARPs for virtual ip which belongs to a logical port - * of type 'virtual' and bind that port. - * - * - ARP reply from the virtual ip which belongs to a logical - * port of type 'virtual' and bind that port. - * */ - ovs_be32 ip; - const char *virtual_ip = smap_get(&op->nbsp->options, - "virtual-ip"); - const char *virtual_parents = smap_get(&op->nbsp->options, - "virtual-parents"); - if (!virtual_ip || !virtual_parents || - !ip_parse(virtual_ip, &ip)) { - continue; - } - - char *tokstr = xstrdup(virtual_parents); - char *save_ptr = NULL; - char *vparent; - for (vparent = strtok_r(tokstr, ",", &save_ptr); vparent != NULL; - vparent = strtok_r(NULL, ",", &save_ptr)) { - struct ovn_port *vp = ovn_port_find(ports, vparent); - if (!vp || vp->od != op->od) { - /* vparent name should be valid and it should belong - * to the same logical switch. */ - continue; - } - - ds_clear(&match); - ds_put_format(&match, "inport == \"%s\" && " - "((arp.op == 1 && arp.spa == %s && " - "arp.tpa == %s) || (arp.op == 2 && " - "arp.spa == %s))", - vparent, virtual_ip, virtual_ip, - virtual_ip); - ds_clear(&actions); - ds_put_format(&actions, - "bind_vport(%s, inport); " - "next;", - op->json_key); - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(&match), ds_cstr(&actions), - &vp->nbsp->header_); - } - - free(tokstr); - } else { - /* - * Add ARP/ND reply flows if either the - * - port is up and it doesn't have 'unknown' address defined or - * - port type is router or - * - port type is localport - */ - if (check_lsp_is_up && - !lsp_is_up(op->nbsp) && strcmp(op->nbsp->type, "router") && - strcmp(op->nbsp->type, "localport")) { - continue; - } - - if (lsp_is_external(op->nbsp) || op->has_unknown) { - continue; - } - - for (size_t i = 0; i < op->n_lsp_addrs; i++) { - for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) { - ds_clear(&match); - ds_put_format(&match, "arp.tpa == %s && arp.op == 1", - op->lsp_addrs[i].ipv4_addrs[j].addr_s); - ds_clear(&actions); - ds_put_format(&actions, - "eth.dst = eth.src; " - "eth.src = %s; " - "arp.op = 2; /* ARP reply */ " - "arp.tha = arp.sha; " - "arp.sha = %s; " - "arp.tpa = arp.spa; " - "arp.spa = %s; " - "outport = inport; " - "flags.loopback = 1; " - "output;", - op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s, - op->lsp_addrs[i].ipv4_addrs[j].addr_s); - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 50, - ds_cstr(&match), - ds_cstr(&actions), - &op->nbsp->header_); - - /* Do not reply to an ARP request from the port that owns - * the address (otherwise a DHCP client that ARPs to check - * for a duplicate address will fail). Instead, forward - * it the usual way. - * - * (Another alternative would be to simply drop the packet. - * If everything is working as it is configured, then this - * would produce equivalent results, since no one should - * reply to the request. But ARPing for one's own IP - * address is intended to detect situations where the - * network is not working as configured, so dropping the - * request would frustrate that intent.) */ - ds_put_format(&match, " && inport == %s", op->json_key); - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(&match), "next;", - &op->nbsp->header_); - } - - /* For ND solicitations, we need to listen for both the - * unicast IPv6 address and its all-nodes multicast address, - * but always respond with the unicast IPv6 address. */ - for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { - ds_clear(&match); - ds_put_format(&match, - "nd_ns && ip6.dst == {%s, %s} && nd.target == %s", - op->lsp_addrs[i].ipv6_addrs[j].addr_s, - op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s, - op->lsp_addrs[i].ipv6_addrs[j].addr_s); - - ds_clear(&actions); - ds_put_format(&actions, - "%s { " - "eth.src = %s; " - "ip6.src = %s; " - "nd.target = %s; " - "nd.tll = %s; " - "outport = inport; " - "flags.loopback = 1; " - "output; " - "};", - !strcmp(op->nbsp->type, "router") ? - "nd_na_router" : "nd_na", - op->lsp_addrs[i].ea_s, - op->lsp_addrs[i].ipv6_addrs[j].addr_s, - op->lsp_addrs[i].ipv6_addrs[j].addr_s, - op->lsp_addrs[i].ea_s); - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 50, - ds_cstr(&match), - ds_cstr(&actions), - &op->nbsp->header_); - - /* Do not reply to a solicitation from the port that owns - * the address (otherwise DAD detection will fail). */ - ds_put_format(&match, " && inport == %s", op->json_key); - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 100, - ds_cstr(&match), "next;", - &op->nbsp->header_); - } - } - } - } - - /* Ingress table 13: ARP/ND responder, by default goto next. - * (priority 0)*/ - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs) { - continue; - } - - ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;"); - } /* Ingress table 13: ARP/ND responder for service monitor source ip. * (priority 110)*/ @@ -7524,6 +7333,205 @@ static void } } +/* Ingress table 13: ARP/ND responder, skip requests coming from localnet + * and vtep ports. (priority 100); see ovn-northd.8.xml for the + * rationale. */ + +static void + build_lswitch_arp_nd_responder( + struct ovn_port *op, struct hmap *lflows, + struct ds *match) +{ + if (op->nbsp) { + if ((!strcmp(op->nbsp->type, "localnet")) || + (!strcmp(op->nbsp->type, "vtep"))) { + ds_clear(match); + ds_put_format(match, "inport == %s", op->json_key); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, + 100, ds_cstr(match), "next;", + &op->nbsp->header_); + } + } +} + +/* Ingress table 13: ARP/ND responder, reply for known IPs. + * (priority 50). */ +static void + build_lswitch_arp_nd_responder_known( + struct ovn_port *op, struct hmap *lflows, + struct hmap *ports, + struct ds *match, struct ds *actions) +{ + if (!op->nbsp) { + return; + } + if (!strcmp(op->nbsp->type, "virtual")) { + /* Handle + * - GARPs for virtual ip which belongs to a logical port + * of type 'virtual' and bind that port. + * + * - ARP reply from the virtual ip which belongs to a logical + * port of type 'virtual' and bind that port. + * */ + ovs_be32 ip; + const char *virtual_ip = smap_get(&op->nbsp->options, + "virtual-ip"); + const char *virtual_parents = smap_get(&op->nbsp->options, + "virtual-parents"); + if (!virtual_ip || !virtual_parents || + !ip_parse(virtual_ip, &ip)) { + return; + } + + char *tokstr = xstrdup(virtual_parents); + char *save_ptr = NULL; + char *vparent; + for (vparent = strtok_r(tokstr, ",", &save_ptr); vparent != NULL; + vparent = strtok_r(NULL, ",", &save_ptr)) { + struct ovn_port *vp = ovn_port_find(ports, vparent); + if (!vp || vp->od != op->od) { + /* vparent name should be valid and it should belong + * to the same logical switch. */ + continue; + } + + ds_clear(match); + ds_put_format(match, "inport == \"%s\" && " + "((arp.op == 1 && arp.spa == %s && " + "arp.tpa == %s) || (arp.op == 2 && " + "arp.spa == %s))", + vparent, virtual_ip, virtual_ip, + virtual_ip); + ds_clear(actions); + ds_put_format(actions, + "bind_vport(%s, inport); " + "next;", + op->json_key); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 100, + ds_cstr(match), ds_cstr(actions), + &vp->nbsp->header_); + } + + free(tokstr); + } else { + /* + * Add ARP/ND reply flows if either the + * - port is up and it doesn't have 'unknown' address defined or + * - port type is router or + * - port type is localport + */ + if (check_lsp_is_up && + !lsp_is_up(op->nbsp) && strcmp(op->nbsp->type, "router") && + strcmp(op->nbsp->type, "localport")) { + return; + } + + if (lsp_is_external(op->nbsp) || op->has_unknown) { + return; + } + + for (size_t i = 0; i < op->n_lsp_addrs; i++) { + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) { + ds_clear(match); + ds_put_format(match, "arp.tpa == %s && arp.op == 1", + op->lsp_addrs[i].ipv4_addrs[j].addr_s); + ds_clear(actions); + ds_put_format(actions, + "eth.dst = eth.src; " + "eth.src = %s; " + "arp.op = 2; /* ARP reply */ " + "arp.tha = arp.sha; " + "arp.sha = %s; " + "arp.tpa = arp.spa; " + "arp.spa = %s; " + "outport = inport; " + "flags.loopback = 1; " + "output;", + op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s, + op->lsp_addrs[i].ipv4_addrs[j].addr_s); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(match), + ds_cstr(actions), + &op->nbsp->header_); + + /* Do not reply to an ARP request from the port that owns + * the address (otherwise a DHCP client that ARPs to check + * for a duplicate address will fail). Instead, forward + * it the usual way. + * + * (Another alternative would be to simply drop the packet. + * If everything is working as it is configured, then this + * would produce equivalent results, since no one should + * reply to the request. But ARPing for one's own IP + * address is intended to detect situations where the + * network is not working as configured, so dropping the + * request would frustrate that intent.) */ + ds_put_format(match, " && inport == %s", op->json_key); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 100, + ds_cstr(match), "next;", + &op->nbsp->header_); + } + + /* For ND solicitations, we need to listen for both the + * unicast IPv6 address and its all-nodes multicast address, + * but always respond with the unicast IPv6 address. */ + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { + ds_clear(match); + ds_put_format(match, + "nd_ns && ip6.dst == {%s, %s} && nd.target == %s", + op->lsp_addrs[i].ipv6_addrs[j].addr_s, + op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s, + op->lsp_addrs[i].ipv6_addrs[j].addr_s); + + ds_clear(actions); + ds_put_format(actions, + "%s { " + "eth.src = %s; " + "ip6.src = %s; " + "nd.target = %s; " + "nd.tll = %s; " + "outport = inport; " + "flags.loopback = 1; " + "output; " + "};", + !strcmp(op->nbsp->type, "router") ? + "nd_na_router" : "nd_na", + op->lsp_addrs[i].ea_s, + op->lsp_addrs[i].ipv6_addrs[j].addr_s, + op->lsp_addrs[i].ipv6_addrs[j].addr_s, + op->lsp_addrs[i].ea_s); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(match), + ds_cstr(actions), + &op->nbsp->header_); + + /* Do not reply to a solicitation from the port that owns + * the address (otherwise DAD detection will fail). */ + ds_put_format(match, " && inport == %s", op->json_key); + ovn_lflow_add_with_hint(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 100, + ds_cstr(match), "next;", + &op->nbsp->header_); + } + } + } +} + +/* Ingress table 13: ARP/ND responder, by default goto next. + * (priority 0)*/ +static void + build_lswitch_arp_nd_responder_next( + struct ovn_datapath *od, struct hmap *lflows) +{ + if (od->nbs) { + ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;"); + } +} + /* Returns a string of the IP address of the router port 'op' that * overlaps with 'ip_s". If one is not found, returns NULL. @@ -11374,6 +11382,7 @@ build_lswitch_and_lrouter_iterate_by_od( build_fwd_group_lflows(od, lsi->lflows); build_lswitch_lflows_admission_control(od, lsi->lflows); build_lswitch_input_port_sec_od(od, lsi->lflows); + build_lswitch_arp_nd_responder_next(od, lsi->lflows); /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); @@ -11406,6 +11415,11 @@ build_lswitch_and_lrouter_iterate_by_op( /* Build Logical Switch Flows. */ build_lswitch_input_port_sec_op(op, lsi->lflows, &lsi->actions, &lsi->match); + build_lswitch_input_port_sec_op(op, lsi->lflows, &lsi->actions, + &lsi->match); + build_lswitch_arp_nd_responder(op, lsi->lflows, &lsi->match); + build_lswitch_arp_nd_responder_known(op, lsi->lflows, lsi->ports, + &lsi->match, &lsi->actions); /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,