From patchwork Fri Feb 5 06:59:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1436451 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=) 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 4DX5rQ2CtGz9sWg for ; Fri, 5 Feb 2021 17:59:33 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id AF335872EC; Fri, 5 Feb 2021 06:59:29 +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 9ScYh9DCiupy; Fri, 5 Feb 2021 06:59:26 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 59297872BA; Fri, 5 Feb 2021 06:59:26 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3C5EFC08A1; Fri, 5 Feb 2021 06:59:26 +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 73D9BC0174 for ; Fri, 5 Feb 2021 06:59:25 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 57DC6203E9 for ; Fri, 5 Feb 2021 06:59:25 +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 g6vv65nbkL-b for ; Fri, 5 Feb 2021 06:59:22 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by silver.osuosl.org (Postfix) with ESMTPS id 050D520397 for ; Fri, 5 Feb 2021 06:59:21 +0000 (UTC) Received: from nusiddiq.home.org.com (unknown [115.99.223.251]) (Authenticated sender: numans@ovn.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 6615320000A; Fri, 5 Feb 2021 06:59:16 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Fri, 5 Feb 2021 12:29:12 +0530 Message-Id: <20210205065912.39866-1-numans@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210205065622.39226-1-numans@ovn.org> References: <20210205065622.39226-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 1/6] controller: Split mac learning code to a separate file. 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: Numan Siddique This patch moves the 'struct put_mac_binding' from controller/pinctrl.c to controller/mac-learn.c as a 'struct mac_binding' and adds the relevant functions to access it. Signed-off-by: Numan Siddique --- controller/automake.mk | 5 +- controller/mac-learn.c | 101 ++++++++++++++++++++++++++++++++++++++++ controller/mac-learn.h | 46 +++++++++++++++++++ controller/pinctrl.c | 102 ++++++++++++----------------------------- 4 files changed, 181 insertions(+), 73 deletions(-) create mode 100644 controller/mac-learn.c create mode 100644 controller/mac-learn.h diff --git a/controller/automake.mk b/controller/automake.mk index 480578eda3..9b8debd2ff 100644 --- a/controller/automake.mk +++ b/controller/automake.mk @@ -27,7 +27,10 @@ controller_ovn_controller_SOURCES = \ controller/ovn-controller.c \ controller/ovn-controller.h \ controller/physical.c \ - controller/physical.h + controller/physical.h \ + controller/mac-learn.c \ + controller/mac-learn.h + controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la man_MANS += controller/ovn-controller.8 EXTRA_DIST += controller/ovn-controller.8.xml diff --git a/controller/mac-learn.c b/controller/mac-learn.c new file mode 100644 index 0000000000..36a6d6e589 --- /dev/null +++ b/controller/mac-learn.c @@ -0,0 +1,101 @@ +/* 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. + */ + +#include + +#include "mac-learn.h" + +/* OpenvSwitch lib includes. */ +#include "openvswitch/vlog.h" +#include "lib/smap.h" + +VLOG_DEFINE_THIS_MODULE(mac_learn); + +#define MAX_MAC_BINDINGS 1000 + +static size_t mac_binding_hash(uint32_t dp_key, uint32_t port_key, + struct in6_addr *); +static struct mac_binding *mac_binding_find(struct hmap *mac_bindings, + uint32_t dp_key, + uint32_t port_key, + struct in6_addr *ip, size_t hash); + +void +ovn_mac_bindings_init(struct hmap *mac_bindings) +{ + hmap_init(mac_bindings); +} + +void +ovn_mac_bindings_flush(struct hmap *mac_bindings) +{ + struct mac_binding *mb; + HMAP_FOR_EACH_POP (mb, hmap_node, mac_bindings) { + free(mb); + } +} + +void +ovn_mac_bindings_destroy(struct hmap *mac_bindings) +{ + ovn_mac_bindings_flush(mac_bindings); + hmap_destroy(mac_bindings); +} + +struct mac_binding * +ovn_mac_binding_add(struct hmap *mac_bindings, uint32_t dp_key, + uint32_t port_key, struct in6_addr *ip, + struct eth_addr mac) +{ + uint32_t hash = mac_binding_hash(dp_key, port_key, ip); + + struct mac_binding *mb = + mac_binding_find(mac_bindings, dp_key, port_key, ip, hash); + if (!mb) { + if (hmap_count(mac_bindings) >= MAX_MAC_BINDINGS) { + return NULL; + } + + mb = xmalloc(sizeof *mb); + mb->dp_key = dp_key; + mb->port_key = port_key; + mb->ip = *ip; + hmap_insert(mac_bindings, &mb->hmap_node, hash); + } + mb->mac = mac; + + return mb; +} + +static size_t +mac_binding_hash(uint32_t dp_key, uint32_t port_key, struct in6_addr *ip) +{ + return hash_bytes(ip, sizeof *ip, hash_2words(dp_key, port_key)); +} + +static struct mac_binding * +mac_binding_find(struct hmap *mac_bindings, uint32_t dp_key, + uint32_t port_key, struct in6_addr *ip, size_t hash) +{ + struct mac_binding *mb; + HMAP_FOR_EACH_WITH_HASH (mb, hmap_node, hash, mac_bindings) { + if (mb->dp_key == dp_key && mb->port_key == port_key && + IN6_ARE_ADDR_EQUAL(&mb->ip, ip)) { + return mb; + } + } + + return NULL; +} diff --git a/controller/mac-learn.h b/controller/mac-learn.h new file mode 100644 index 0000000000..3a8520c360 --- /dev/null +++ b/controller/mac-learn.h @@ -0,0 +1,46 @@ +/* + * 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 OVN_MAC_LEARN_H +#define OVN_MAC_LEARN_H 1 + +#include +#include +#include "openvswitch/hmap.h" + +struct mac_binding { + struct hmap_node hmap_node; /* In a hmap. */ + + /* Key. */ + uint32_t dp_key; + uint32_t port_key; /* Port from where this mac_binding is learnt. */ + struct in6_addr ip; + + /* Value. */ + struct eth_addr mac; +}; + +void ovn_mac_bindings_init(struct hmap *mac_bindings); +void ovn_mac_bindings_flush(struct hmap *mac_bindings); +void ovn_mac_bindings_destroy(struct hmap *mac_bindings); + +struct mac_binding *ovn_mac_binding_add(struct hmap *mac_bindings, + uint32_t dp_key, uint32_t port_key, + struct in6_addr *ip, + struct eth_addr mac); + + +#endif /* OVN_MAC_LEARN_H */ \ No newline at end of file diff --git a/controller/pinctrl.c b/controller/pinctrl.c index dcf6b4af5c..723d2a6522 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -26,6 +26,7 @@ #include "flow.h" #include "ha-chassis.h" #include "lport.h" +#include "mac-learn.h" #include "nx-match.h" #include "latch.h" #include "lib/packets.h" @@ -193,7 +194,6 @@ static void run_put_mac_bindings( struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip) OVS_REQUIRES(pinctrl_mutex); static void wait_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn); -static void flush_put_mac_bindings(void); static void send_mac_binding_buffered_pkts(struct rconn *swconn) OVS_REQUIRES(pinctrl_mutex); @@ -3893,47 +3893,20 @@ pinctrl_destroy(void) * available. */ /* Buffered "put_mac_binding" operation. */ -struct put_mac_binding { - struct hmap_node hmap_node; /* In 'put_mac_bindings'. */ - /* Key. */ - uint32_t dp_key; - uint32_t port_key; - struct in6_addr ip_key; - - /* Value. */ - struct eth_addr mac; -}; - -/* Contains "struct put_mac_binding"s. */ +/* Contains "struct mac_binding"s. */ static struct hmap put_mac_bindings; static void init_put_mac_bindings(void) { - hmap_init(&put_mac_bindings); + ovn_mac_bindings_init(&put_mac_bindings); } static void destroy_put_mac_bindings(void) { - flush_put_mac_bindings(); - hmap_destroy(&put_mac_bindings); -} - -static struct put_mac_binding * -pinctrl_find_put_mac_binding(uint32_t dp_key, uint32_t port_key, - const struct in6_addr *ip_key, uint32_t hash) -{ - struct put_mac_binding *pa; - HMAP_FOR_EACH_WITH_HASH (pa, hmap_node, hash, &put_mac_bindings) { - if (pa->dp_key == dp_key - && pa->port_key == port_key - && IN6_ARE_ADDR_EQUAL(&pa->ip_key, ip_key)) { - return pa; - } - } - return NULL; + ovn_mac_bindings_destroy(&put_mac_bindings); } /* Called with in the pinctrl_handler thread context. */ @@ -3953,23 +3926,16 @@ pinctrl_handle_put_mac_binding(const struct flow *md, ovs_be128 ip6 = hton128(flow_get_xxreg(md, 0)); memcpy(&ip_key, &ip6, sizeof ip_key); } - uint32_t hash = hash_bytes(&ip_key, sizeof ip_key, - hash_2words(dp_key, port_key)); - struct put_mac_binding *pmb - = pinctrl_find_put_mac_binding(dp_key, port_key, &ip_key, hash); - if (!pmb) { + + struct mac_binding *mb = ovn_mac_binding_add(&put_mac_bindings, dp_key, + port_key, &ip_key, + headers->dl_src); + if (!mb) { if (hmap_count(&put_mac_bindings) >= 1000) { COVERAGE_INC(pinctrl_drop_put_mac_binding); return; } - - pmb = xmalloc(sizeof *pmb); - hmap_insert(&put_mac_bindings, &pmb->hmap_node, hash); - pmb->dp_key = dp_key; - pmb->port_key = port_key; - pmb->ip_key = ip_key; } - pmb->mac = headers->dl_src; /* We can send the buffered packet once the main ovn-controller * thread calls pinctrl_run() and it writes the mac_bindings stored @@ -4012,12 +3978,12 @@ mac_binding_lookup(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, /* Update or add an IP-MAC binding for 'logical_port'. * Caller should make sure that 'ovnsb_idl_txn' is valid. */ static void -mac_binding_add(struct ovsdb_idl_txn *ovnsb_idl_txn, - struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, - const char *logical_port, - const struct sbrec_datapath_binding *dp, - struct eth_addr ea, const char *ip, - bool update_only) +mac_binding_add_to_sb(struct ovsdb_idl_txn *ovnsb_idl_txn, + struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, + const char *logical_port, + const struct sbrec_datapath_binding *dp, + struct eth_addr ea, const char *ip, + bool update_only) { /* Convert ethernet argument to string form for database. */ char mac_string[ETH_ADDR_STRLEN + 1]; @@ -4073,9 +4039,9 @@ send_garp_locally(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ds ip_s = DS_EMPTY_INITIALIZER; ip_format_masked(ip, OVS_BE32_MAX, &ip_s); - mac_binding_add(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, - remote->logical_port, remote->datapath, - ea, ds_cstr(&ip_s), update_only); + mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, + remote->logical_port, remote->datapath, + ea, ds_cstr(&ip_s), update_only); ds_destroy(&ip_s); } } @@ -4085,30 +4051,30 @@ run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_datapath_binding_by_key, struct ovsdb_idl_index *sbrec_port_binding_by_key, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, - const struct put_mac_binding *pmb) + const struct mac_binding *mb) { /* Convert logical datapath and logical port key into lport. */ const struct sbrec_port_binding *pb = lport_lookup_by_key( sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, - pmb->dp_key, pmb->port_key); + mb->dp_key, mb->port_key); if (!pb) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "unknown logical port with datapath %"PRIu32" " - "and port %"PRIu32, pmb->dp_key, pmb->port_key); + "and port %"PRIu32, mb->dp_key, mb->port_key); return; } /* Convert ethernet argument to string form for database. */ char mac_string[ETH_ADDR_STRLEN + 1]; snprintf(mac_string, sizeof mac_string, - ETH_ADDR_FMT, ETH_ADDR_ARGS(pmb->mac)); + ETH_ADDR_FMT, ETH_ADDR_ARGS(mb->mac)); struct ds ip_s = DS_EMPTY_INITIALIZER; - ipv6_format_mapped(&pmb->ip_key, &ip_s); - mac_binding_add(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, - pb->logical_port, pb->datapath, pmb->mac, ds_cstr(&ip_s), - false); + ipv6_format_mapped(&mb->ip, &ip_s); + mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip, + pb->logical_port, pb->datapath, mb->mac, + ds_cstr(&ip_s), false); ds_destroy(&ip_s); } @@ -4125,14 +4091,14 @@ run_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn, return; } - const struct put_mac_binding *pmb; - HMAP_FOR_EACH (pmb, hmap_node, &put_mac_bindings) { + const struct mac_binding *mb; + HMAP_FOR_EACH (mb, hmap_node, &put_mac_bindings) { run_put_mac_binding(ovnsb_idl_txn, sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, sbrec_mac_binding_by_lport_ip, - pmb); + mb); } - flush_put_mac_bindings(); + ovn_mac_bindings_flush(&put_mac_bindings); } static void @@ -4188,14 +4154,6 @@ wait_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn) } } -static void -flush_put_mac_bindings(void) -{ - struct put_mac_binding *pmb; - HMAP_FOR_EACH_POP (pmb, hmap_node, &put_mac_bindings) { - free(pmb); - } -} /* * Send gratuitous/reverse ARP for vif on localnet. From patchwork Fri Feb 5 06:59:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1436456 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=) 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 4DX5rm2sQWz9sWw for ; Fri, 5 Feb 2021 17:59:52 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 035AD86A33; Fri, 5 Feb 2021 06:59: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 CbnDv-5VTI4R; Fri, 5 Feb 2021 06:59:48 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 3143D8680B; Fri, 5 Feb 2021 06:59:48 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 14BA2C08A1; Fri, 5 Feb 2021 06:59:48 +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 625E5C0174 for ; Fri, 5 Feb 2021 06:59:47 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 4FF28872BD for ; Fri, 5 Feb 2021 06:59:47 +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 Umw6Mh7jTeZs for ; Fri, 5 Feb 2021 06:59:45 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by hemlock.osuosl.org (Postfix) with ESMTPS id 587AF872BA for ; Fri, 5 Feb 2021 06:59:45 +0000 (UTC) Received: from nusiddiq.home.org.com (unknown [115.99.223.251]) (Authenticated sender: numans@ovn.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 816F624000B; Fri, 5 Feb 2021 06:59:42 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Fri, 5 Feb 2021 12:29:38 +0530 Message-Id: <20210205065938.40002-1-numans@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210205065622.39226-1-numans@ovn.org> References: <20210205065622.39226-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 2/6] MAC learning: Add a new FDB table in southbound db. 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: Numan Siddique This patch - Adds a new table 'FDB' in Southbound database. - Adds a new pinctrl_handler action - ACTION_OPCODE_PUT_FDB which learns the port-to-mac bindings and stores it in the 'FDB' table. This handler will be used later. - Upcoming patch adds necessary OVN actions to learn the port-to-mac bindings. Unlike MAC_Binding Southbound table, FDB table stores the datapath tunnel key and port key. This makes it easier for ovn-controller to program the OF rules and it doesn't need to do any logical port lookup in the Port_Binding table. Signed-off-by: Numan Siddique --- controller/mac-learn.c | 79 ++++++++++++++++++++++++ controller/mac-learn.h | 20 ++++++ controller/ovn-controller.c | 5 ++ controller/pinctrl.c | 118 ++++++++++++++++++++++++++++++++++++ controller/pinctrl.h | 1 + include/ovn/actions.h | 4 ++ ovn-sb.ovsschema | 17 +++++- ovn-sb.xml | 24 ++++++++ 8 files changed, 266 insertions(+), 2 deletions(-) diff --git a/controller/mac-learn.c b/controller/mac-learn.c index 36a6d6e589..27634dca8b 100644 --- a/controller/mac-learn.c +++ b/controller/mac-learn.c @@ -19,11 +19,13 @@ /* OpenvSwitch lib includes. */ #include "openvswitch/vlog.h" +#include "lib/packets.h" #include "lib/smap.h" VLOG_DEFINE_THIS_MODULE(mac_learn); #define MAX_MAC_BINDINGS 1000 +#define MAX_FDB_ENTRIES 1000 static size_t mac_binding_hash(uint32_t dp_key, uint32_t port_key, struct in6_addr *); @@ -31,7 +33,12 @@ static struct mac_binding *mac_binding_find(struct hmap *mac_bindings, uint32_t dp_key, uint32_t port_key, struct in6_addr *ip, size_t hash); +static size_t fdb_entry_hash(uint32_t dp_key, struct eth_addr *); +static struct fdb_entry *fdb_entry_find(struct hmap *fdbs, uint32_t dp_key, + struct eth_addr *mac, size_t hash); + +/* mac_binding functions. */ void ovn_mac_bindings_init(struct hmap *mac_bindings) { @@ -79,6 +86,55 @@ ovn_mac_binding_add(struct hmap *mac_bindings, uint32_t dp_key, return mb; } +/* fdb functions. */ +void +ovn_fdb_init(struct hmap *fdbs) +{ + hmap_init(fdbs); +} + +void +ovn_fdbs_flush(struct hmap *fdbs) +{ + struct fdb_entry *fdb_e; + HMAP_FOR_EACH_POP (fdb_e, hmap_node, fdbs) { + free(fdb_e); + } +} + +void +ovn_fdbs_destroy(struct hmap *fdbs) +{ + ovn_fdbs_flush(fdbs); + hmap_destroy(fdbs); +} + +struct fdb_entry * +ovn_fdb_add(struct hmap *fdbs, uint32_t dp_key, struct eth_addr mac, + uint32_t port_key) +{ + uint32_t hash = fdb_entry_hash(dp_key, &mac); + + struct fdb_entry *fdb_e = + fdb_entry_find(fdbs, dp_key, &mac, hash); + if (!fdb_e) { + if (hmap_count(fdbs) >= MAX_FDB_ENTRIES) { + return NULL; + } + + fdb_e = xzalloc(sizeof *fdb_e); + fdb_e->dp_key = dp_key; + fdb_e->mac = mac; + hmap_insert(fdbs, &fdb_e->hmap_node, hash); + } + fdb_e->port_key = port_key; + + return fdb_e; + +} + +/* mac_binding related static functions. */ + static size_t mac_binding_hash(uint32_t dp_key, uint32_t port_key, struct in6_addr *ip) { @@ -99,3 +155,26 @@ mac_binding_find(struct hmap *mac_bindings, uint32_t dp_key, return NULL; } + +/* fdb related static functions. */ + +static size_t +fdb_entry_hash(uint32_t dp_key, struct eth_addr *mac) +{ + uint64_t mac64 = eth_addr_to_uint64(*mac); + return hash_2words(dp_key, hash_uint64(mac64)); +} + +static struct fdb_entry * +fdb_entry_find(struct hmap *fdbs, uint32_t dp_key, + struct eth_addr *mac, size_t hash) +{ + struct fdb_entry *fdb_e; + HMAP_FOR_EACH_WITH_HASH (fdb_e, hmap_node, hash, fdbs) { + if (fdb_e->dp_key == dp_key && eth_addr_equals(fdb_e->mac, *mac)) { + return fdb_e; + } + } + + return NULL; +} diff --git a/controller/mac-learn.h b/controller/mac-learn.h index 3a8520c360..7a7897e4db 100644 --- a/controller/mac-learn.h +++ b/controller/mac-learn.h @@ -43,4 +43,24 @@ struct mac_binding *ovn_mac_binding_add(struct hmap *mac_bindings, struct eth_addr mac); + +struct fdb_entry { + struct hmap_node hmap_node; /* In a hmap. */ + + /* Key. */ + uint32_t dp_key; + struct eth_addr mac; + + /* value. */ + uint32_t port_key; +}; + +void ovn_fdb_init(struct hmap *fdbs); +void ovn_fdbs_flush(struct hmap *fdbs); +void ovn_fdbs_destroy(struct hmap *fdbs); + +struct fdb_entry *ovn_fdb_add(struct hmap *fdbs, + uint32_t dp_key, struct eth_addr mac, + uint32_t port_key); + #endif /* OVN_MAC_LEARN_H */ \ No newline at end of file diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index ef3e0e95ea..42858d60fa 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -2462,6 +2462,10 @@ main(int argc, char *argv[]) = ip_mcast_index_create(ovnsb_idl_loop.idl); struct ovsdb_idl_index *sbrec_igmp_group = igmp_group_index_create(ovnsb_idl_loop.idl); + struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac + = ovsdb_idl_index_create2(ovnsb_idl_loop.idl, + &sbrec_fdb_col_mac, + &sbrec_fdb_col_dp_key); ovsdb_idl_track_add_all(ovnsb_idl_loop.idl); ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, @@ -2864,6 +2868,7 @@ main(int argc, char *argv[]) sbrec_mac_binding_by_lport_ip, sbrec_igmp_group, sbrec_ip_multicast, + sbrec_fdb_by_dp_key_mac, sbrec_dns_table_get(ovnsb_idl_loop.idl), sbrec_controller_event_table_get( ovnsb_idl_loop.idl), diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 723d2a6522..116ab65334 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -340,6 +340,22 @@ static void bfd_monitor_run(struct ovsdb_idl_txn *ovnsb_idl_txn, const struct sbrec_chassis *chassis, const struct sset *active_tunnels) OVS_REQUIRES(pinctrl_mutex); +static void init_fdb_entries(void); +static void destroy_fdb_entries(void); +static const struct sbrec_fdb *fdb_lookup( + struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, + uint32_t dp_key, const char *mac); +static void run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn, + struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, + const struct fdb_entry *fdb_e) + OVS_REQUIRES(pinctrl_mutex); +static void run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn, + struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac) + OVS_REQUIRES(pinctrl_mutex); +static void wait_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn); +static void pinctrl_handle_put_fdb(const struct flow *md, + const struct flow *headers) + OVS_REQUIRES(pinctrl_mutex); COVERAGE_DEFINE(pinctrl_drop_put_mac_binding); COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map); @@ -506,6 +522,7 @@ pinctrl_init(void) init_put_vport_bindings(); init_svc_monitors(); bfd_monitor_init(); + init_fdb_entries(); pinctrl.br_int_name = NULL; pinctrl_handler_seq = seq_create(); pinctrl_main_seq = seq_create(); @@ -3020,6 +3037,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg) ovs_mutex_unlock(&pinctrl_mutex); break; + case ACTION_OPCODE_PUT_FDB: + ovs_mutex_lock(&pinctrl_mutex); + pinctrl_handle_put_fdb(&pin.flow_metadata.flow, &headers); + ovs_mutex_unlock(&pinctrl_mutex); + break; + case ACTION_OPCODE_PUT_DHCPV6_OPTS: pinctrl_handle_put_dhcpv6_opts(swconn, &packet, &pin, &userdata, &continuation); @@ -3297,6 +3320,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, struct ovsdb_idl_index *sbrec_igmp_groups, struct ovsdb_idl_index *sbrec_ip_multicast_opts, + struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, const struct sbrec_dns_table *dns_table, const struct sbrec_controller_event_table *ce_table, const struct sbrec_service_monitor_table *svc_mon_table, @@ -3333,6 +3357,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, chassis); bfd_monitor_run(ovnsb_idl_txn, bfd_table, sbrec_port_binding_by_name, chassis, active_tunnels); + run_put_fdbs(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac); ovs_mutex_unlock(&pinctrl_mutex); } @@ -3856,6 +3881,7 @@ pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn) wait_put_vport_bindings(ovnsb_idl_txn); int64_t new_seq = seq_read(pinctrl_main_seq); seq_wait(pinctrl_main_seq, new_seq); + wait_put_fdbs(ovnsb_idl_txn); } /* Called by ovn-controller. */ @@ -3877,6 +3903,7 @@ pinctrl_destroy(void) ip_mcast_snoop_destroy(); destroy_svc_monitors(); bfd_monitor_destroy(); + destroy_fdb_entries(); seq_destroy(pinctrl_main_seq); seq_destroy(pinctrl_handler_seq); } @@ -7530,3 +7557,94 @@ pinctrl_handle_svc_check(struct rconn *swconn, const struct flow *ip_flow, svc_mon->next_send_time = time_msec() + svc_mon->interval; } } + +static struct hmap put_fdbs; + +/* MAC learning (fdb) related functions. Runs within the main + * ovn-controller thread context. */ + +static void +init_fdb_entries(void) +{ + ovn_fdb_init(&put_fdbs); +} + +static void +destroy_fdb_entries(void) +{ + ovn_fdbs_destroy(&put_fdbs); +} + +static const struct sbrec_fdb * +fdb_lookup(struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, uint32_t dp_key, + const char *mac) +{ + struct sbrec_fdb *fdb = sbrec_fdb_index_init_row(sbrec_fdb_by_dp_key_mac); + sbrec_fdb_index_set_dp_key(fdb, dp_key); + sbrec_fdb_index_set_mac(fdb, mac); + + const struct sbrec_fdb *retval + = sbrec_fdb_index_find(sbrec_fdb_by_dp_key_mac, fdb); + + sbrec_fdb_index_destroy_row(fdb); + + return retval; +} + +static void +run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn, + struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, + const struct fdb_entry *fdb_e) +{ + /* Convert ethernet argument to string form for database. */ + char mac_string[ETH_ADDR_STRLEN + 1]; + snprintf(mac_string, sizeof mac_string, + ETH_ADDR_FMT, ETH_ADDR_ARGS(fdb_e->mac)); + + /* Update or add an FDB entry. */ + const struct sbrec_fdb *sb_fdb = + fdb_lookup(sbrec_fdb_by_dp_key_mac, fdb_e->dp_key, mac_string); + if (!sb_fdb) { + sb_fdb = sbrec_fdb_insert(ovnsb_idl_txn); + sbrec_fdb_set_dp_key(sb_fdb, fdb_e->dp_key); + sbrec_fdb_set_mac(sb_fdb, mac_string); + } + sbrec_fdb_set_port_key(sb_fdb, fdb_e->port_key); +} + +static void +run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn, + struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac) + OVS_REQUIRES(pinctrl_mutex) +{ + if (!ovnsb_idl_txn) { + return; + } + + const struct fdb_entry *fdb_e; + HMAP_FOR_EACH (fdb_e, hmap_node, &put_fdbs) { + run_put_fdb(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac, fdb_e); + } + ovn_fdbs_flush(&put_fdbs); +} + + +static void +wait_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn) +{ + if (ovnsb_idl_txn && !hmap_is_empty(&put_fdbs)) { + poll_immediate_wake(); + } +} + +/* Called with in the pinctrl_handler thread context. */ +static void +pinctrl_handle_put_fdb(const struct flow *md, const struct flow *headers) + OVS_REQUIRES(pinctrl_mutex) +{ + uint32_t dp_key = ntohll(md->metadata); + uint32_t port_key = md->regs[MFF_LOG_INPORT - MFF_REG0]; + + ovn_fdb_add(&put_fdbs, dp_key, headers->dl_src, port_key); + notify_pinctrl_main(); +} diff --git a/controller/pinctrl.h b/controller/pinctrl.h index 8555d983db..cc0a51984a 100644 --- a/controller/pinctrl.h +++ b/controller/pinctrl.h @@ -42,6 +42,7 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, struct ovsdb_idl_index *sbrec_igmp_groups, struct ovsdb_idl_index *sbrec_ip_multicast_opts, + struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, const struct sbrec_dns_table *, const struct sbrec_controller_event_table *, const struct sbrec_service_monitor_table *, diff --git a/include/ovn/actions.h b/include/ovn/actions.h index be87e61352..a2d28c6a3f 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -641,6 +641,10 @@ enum action_opcode { * The actions, in OpenFlow 1.3 format, follow the action_header. */ ACTION_OPCODE_SCTP_ABORT, + + /* put_fdb(inport, eth.src). + */ + ACTION_OPCODE_PUT_FDB, }; /* Header. */ diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index 0d20f08266..246e3908a0 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "20.15.0", - "cksum": "539683023 25965", + "version": "20.16.0", + "cksum": "1219580357 26536", "tables": { "SB_Global": { "columns": { @@ -513,6 +513,19 @@ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, "indexes": [["logical_port", "dst_ip", "src_port", "disc"]], + "isRoot": true}, + "FDB": { + "columns": { + "mac": {"type": "string"}, + "dp_key": { + "type": {"key": {"type": "integer", + "minInteger": 1, + "maxInteger": 16777215}}}, + "port_key": { + "type": {"key": {"type": "integer", + "minInteger": 1, + "maxInteger": 16777215}}}}, + "indexes": [["mac", "dp_key"]], "isRoot": true} } } diff --git a/ovn-sb.xml b/ovn-sb.xml index 2f251bd5c2..b8912b33c8 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -4330,4 +4330,28 @@ tcp.flags = RST; + + +

+ This table is primarily used to learn the MACs observed on a VIF + which belongs to a Logical_Switch_Port record in + OVN_Northbound whose port security is disabled + and 'unknown' address set. If port security is disabled on a + Logical_Switch_Port record, OVN should allow traffic + with any source mac from the VIF. This table will be used to deliver + a packet to the VIF, If a packet's eth.dst is learnt. +

+ + + The learnt mac address. + + + + The key of the datapath on which this FDB was learnt. + + + + The key of the port binding on which this FDB was learnt. + +
From patchwork Fri Feb 5 06:59:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1436459 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=) 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 4DX5s55m5rz9sWg for ; Fri, 5 Feb 2021 18:00:09 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 5EC69872F6; Fri, 5 Feb 2021 07:00:08 +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 1qKs1-fS6vYt; Fri, 5 Feb 2021 07:00:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 6697C872EF; Fri, 5 Feb 2021 07:00:05 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3A815C1834; Fri, 5 Feb 2021 07:00:05 +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 81FC0C0174 for ; Fri, 5 Feb 2021 07:00:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 7057F8672E for ; Fri, 5 Feb 2021 07:00:03 +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 W-xpcukdcSL9 for ; Fri, 5 Feb 2021 07:00:00 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 9486786432 for ; Fri, 5 Feb 2021 06:59:59 +0000 (UTC) X-Originating-IP: 115.99.223.251 Received: from nusiddiq.home.org.com (unknown [115.99.223.251]) (Authenticated sender: numans@ovn.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 9AFDD60002; Fri, 5 Feb 2021 06:59:54 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Fri, 5 Feb 2021 12:29:50 +0530 Message-Id: <20210205065950.40117-1-numans@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210205065622.39226-1-numans@ovn.org> References: <20210205065622.39226-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 3/6] MAC learning: Add new actions - put_fdb, get_fdb and lookup_fdb. 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: Numan Siddique This patch adds these OVN actions to learn port-to-mac bindings on the logical ports whose port security is disabled and are configured to accept unknown destination packets. put_fdb(inport, mac) will add an entry in the Southbound 'FDB' table. get_fdb(mac) will get the port key on which the mac is learnt. lookup_fdb(inport, mac) will check if the port-to-mac entry is already present or not. This is added to limit using the action - put_fdb() only if required. An upcoming patch in the series will add the necessary logical flows which makes use of these actions. Signed-off-by: Numan Siddique --- controller/lflow.c | 2 + controller/lflow.h | 2 + include/ovn/actions.h | 29 ++++++ include/ovn/logical-fields.h | 4 + lib/actions.c | 176 +++++++++++++++++++++++++++++++++++ ovn-sb.xml | 62 ++++++++++++ tests/ovn.at | 58 ++++++++++++ tests/test-ovn.c | 2 + utilities/ovn-trace.c | 138 ++++++++++++++++++++++++++- 9 files changed, 472 insertions(+), 1 deletion(-) diff --git a/controller/lflow.c b/controller/lflow.c index 946c1e04b7..baf6932d51 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -701,6 +701,8 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .lb_hairpin_ptable = OFTABLE_CHK_LB_HAIRPIN, .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY, .ct_snat_vip_ptable = OFTABLE_CT_SNAT_FOR_VIP, + .fdb_ptable = OFTABLE_GET_FDB, + .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, }; ovnacts_encode(ovnacts->data, ovnacts->size, &ep, &ofpacts); diff --git a/controller/lflow.h b/controller/lflow.h index ba79cc374f..d790d518d8 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -71,6 +71,8 @@ struct uuid; #define OFTABLE_CHK_LB_HAIRPIN 68 #define OFTABLE_CHK_LB_HAIRPIN_REPLY 69 #define OFTABLE_CT_SNAT_FOR_VIP 70 +#define OFTABLE_GET_FDB 71 +#define OFTABLE_LOOKUP_FDB 72 /* The number of tables for the ingress and egress pipelines. */ #define LOG_PIPELINE_LEN 24 diff --git a/include/ovn/actions.h b/include/ovn/actions.h index a2d28c6a3f..0402131777 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -107,6 +107,9 @@ struct ovn_extend_table; OVNACT(CT_SNAT_TO_VIP, ovnact_null) \ OVNACT(BFD_MSG, ovnact_null) \ OVNACT(SCTP_ABORT, ovnact_nest) \ + OVNACT(PUT_FDB, ovnact_put_fdb) \ + OVNACT(GET_FDB, ovnact_get_fdb) \ + OVNACT(LOOKUP_FDB, ovnact_lookup_fdb) \ /* enum ovnact_type, with a member OVNACT_ for each action. */ enum OVS_PACKED_ENUM ovnact_type { @@ -415,6 +418,28 @@ struct ovnact_fwd_group { uint8_t ltable; /* Logical table ID of next table. */ }; +/* OVNACT_PUT_FDB. */ +struct ovnact_put_fdb { + struct ovnact ovnact; + struct expr_field port; /* Logical port name. */ + struct expr_field mac; /* 48-bit Ethernet address. */ +}; + +/* OVNACT_GET_FDB. */ +struct ovnact_get_fdb { + struct ovnact ovnact; + struct expr_field mac; /* 48-bit Ethernet address. */ + struct expr_field dst; /* 32-bit destination field. */ +}; + +/* OVNACT_LOOKUP_FDB. */ +struct ovnact_lookup_fdb { + struct ovnact ovnact; + struct expr_field mac; /* 48-bit Ethernet address. */ + struct expr_field port; /* Logical port name. */ + struct expr_field dst; /* 1-bit destination field. */ +}; + /* Internal use by the helpers below. */ void ovnact_init(struct ovnact *, enum ovnact_type, size_t len); void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len); @@ -766,6 +791,10 @@ struct ovnact_encode_params { * 'chk_lb_hairpin_reply' to resubmit. */ uint8_t ct_snat_vip_ptable; /* OpenFlow table for * 'ct_snat_to_vip' to resubmit. */ + uint8_t fdb_ptable; /* OpenFlow table for + * 'get_fdb' to resubmit. */ + uint8_t fdb_lookup_ptable; /* OpenFlow table for + * 'lookup_fdb' to resubmit. */ }; void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h index aee4748562..9d8d07fab2 100644 --- a/include/ovn/logical-fields.h +++ b/include/ovn/logical-fields.h @@ -59,6 +59,7 @@ enum mff_log_flags_bits { MLF_NESTED_CONTAINER_BIT = 5, MLF_LOOKUP_MAC_BIT = 6, MLF_LOOKUP_LB_HAIRPIN_BIT = 7, + MLF_LOOKUP_FDB_BIT = 8, }; /* MFF_LOG_FLAGS_REG flag assignments */ @@ -92,6 +93,9 @@ enum mff_log_flags { MLF_LOOKUP_MAC = (1 << MLF_LOOKUP_MAC_BIT), MLF_LOOKUP_LB_HAIRPIN = (1 << MLF_LOOKUP_LB_HAIRPIN_BIT), + + /* Indicate that the lookup in the fdb table was successful. */ + MLF_LOOKUP_FDB = (1 << MLF_LOOKUP_FDB_BIT), }; /* OVN logical fields diff --git a/lib/actions.c b/lib/actions.c index 56b8fab629..b3433f49ea 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -3743,6 +3743,172 @@ encode_CT_SNAT_TO_VIP(const struct ovnact_null *null OVS_UNUSED, emit_resubmit(ofpacts, ep->ct_snat_vip_ptable); } +static void +format_PUT_FDB(const struct ovnact_put_fdb *put_fdb, struct ds *s) +{ + ds_put_cstr(s, "put_fdb("); + expr_field_format(&put_fdb->port, s); + ds_put_cstr(s, ", "); + expr_field_format(&put_fdb->mac, s); + ds_put_cstr(s, ");"); +} + +static void +encode_PUT_FDB(const struct ovnact_put_fdb *put_fdb, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + const struct arg args[] = { + { expr_resolve_field(&put_fdb->port), MFF_LOG_INPORT }, + { expr_resolve_field(&put_fdb->mac), MFF_ETH_SRC } + }; + encode_setup_args(args, ARRAY_SIZE(args), ofpacts); + encode_controller_op(ACTION_OPCODE_PUT_FDB, ofpacts); + encode_restore_args(args, ARRAY_SIZE(args), ofpacts); +} + +static void +parse_put_fdb(struct action_context *ctx, struct ovnact_put_fdb *put_fdb) +{ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + action_parse_field(ctx, 0, false, &put_fdb->port); + lexer_force_match(ctx->lexer, LEX_T_COMMA); + action_parse_field(ctx, 48, false, &put_fdb->mac); + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +ovnact_put_fdb_free(struct ovnact_put_fdb *put_fdb OVS_UNUSED) +{ +} + +static void +format_GET_FDB(const struct ovnact_get_fdb *get_fdb, struct ds *s) +{ + expr_field_format(&get_fdb->dst, s); + ds_put_cstr(s, " = get_fdb("); + expr_field_format(&get_fdb->mac, s); + ds_put_cstr(s, ");"); +} + +static void +encode_GET_FDB(const struct ovnact_get_fdb *get_fdb, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + struct mf_subfield dst = expr_resolve_field(&get_fdb->dst); + ovs_assert(dst.field); + + const struct arg args[] = { + { expr_resolve_field(&get_fdb->mac), MFF_ETH_DST }, + }; + encode_setup_args(args, ARRAY_SIZE(args), ofpacts); + put_load(0, MFF_LOG_OUTPORT, 0, 32, ofpacts); + emit_resubmit(ofpacts, ep->fdb_ptable); + encode_restore_args(args, ARRAY_SIZE(args), ofpacts); + + if (dst.field->id != MFF_LOG_OUTPORT) { + struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts); + orm->dst = dst; + orm->src.field = mf_from_id(MFF_LOG_OUTPORT); + orm->src.ofs = 0; + orm->src.n_bits = 32; + } +} + +static void +parse_get_fdb(struct action_context *ctx, + struct expr_field *dst, + struct ovnact_get_fdb *get_fdb) +{ + lexer_get(ctx->lexer); /* Skip get_bfd. */ + lexer_get(ctx->lexer); /* Skip '('. */ + + /* Validate that the destination is a 32-bit, modifiable field if it + is not a string field (i.e 'inport' or 'outport'). */ + if (dst->n_bits) { + char *error = expr_type_check(dst, 32, true, ctx->scope); + if (error) { + lexer_error(ctx->lexer, "%s", error); + free(error); + return; + } + } + get_fdb->dst = *dst; + + action_parse_field(ctx, 48, false, &get_fdb->mac); + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +ovnact_get_fdb_free(struct ovnact_get_fdb *get_fdb OVS_UNUSED) +{ +} + +static void +format_LOOKUP_FDB(const struct ovnact_lookup_fdb *lookup_fdb, struct ds *s) +{ + expr_field_format(&lookup_fdb->dst, s); + ds_put_cstr(s, " = lookup_fdb("); + expr_field_format(&lookup_fdb->port, s); + ds_put_cstr(s, ", "); + expr_field_format(&lookup_fdb->mac, s); + ds_put_cstr(s, ");"); +} + +static void +encode_LOOKUP_FDB(const struct ovnact_lookup_fdb *lookup_fdb, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + const struct arg args[] = { + { expr_resolve_field(&lookup_fdb->port), MFF_LOG_INPORT }, + { expr_resolve_field(&lookup_fdb->mac), MFF_ETH_SRC }, + }; + encode_setup_args(args, ARRAY_SIZE(args), ofpacts); + + struct mf_subfield dst = expr_resolve_field(&lookup_fdb->dst); + ovs_assert(dst.field); + + put_load(0, MFF_LOG_FLAGS, MLF_LOOKUP_FDB_BIT, 1, ofpacts); + emit_resubmit(ofpacts, ep->fdb_lookup_ptable); + encode_restore_args(args, ARRAY_SIZE(args), ofpacts); + + struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts); + orm->dst = dst; + orm->src.field = mf_from_id(MFF_LOG_FLAGS); + orm->src.ofs = MLF_LOOKUP_FDB_BIT; + orm->src.n_bits = 1; +} + +static void +parse_lookup_fdb(struct action_context *ctx, + struct expr_field *dst, + struct ovnact_lookup_fdb *lookup_fdb) +{ + lexer_get(ctx->lexer); /* Skip lookup_bfd. */ + lexer_get(ctx->lexer); /* Skip '('. */ + + /* Validate that the destination is a 1-bit, modifiable field. */ + char *error = expr_type_check(dst, 1, true, ctx->scope); + if (error) { + lexer_error(ctx->lexer, "%s", error); + free(error); + return; + } + lookup_fdb->dst = *dst; + + action_parse_field(ctx, 0, false, &lookup_fdb->port); + lexer_force_match(ctx->lexer, LEX_T_COMMA); + action_parse_field(ctx, 48, false, &lookup_fdb->mac); + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +ovnact_lookup_fdb_free(struct ovnact_lookup_fdb *get_fdb OVS_UNUSED) +{ +} + /* Parses an assignment or exchange or put_dhcp_opts action. */ static void parse_set_action(struct action_context *ctx) @@ -3803,6 +3969,14 @@ parse_set_action(struct action_context *ctx) && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { parse_chk_lb_hairpin_reply( ctx, &lhs, ovnact_put_CHK_LB_HAIRPIN_REPLY(ctx->ovnacts)); + } else if (!strcmp(ctx->lexer->token.s, "get_fdb") + && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { + parse_get_fdb( + ctx, &lhs, ovnact_put_GET_FDB(ctx->ovnacts)); + } else if (!strcmp(ctx->lexer->token.s, "lookup_fdb") + && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { + parse_lookup_fdb( + ctx, &lhs, ovnact_put_LOOKUP_FDB(ctx->ovnacts)); } else { parse_assignment_action(ctx, false, &lhs); } @@ -3895,6 +4069,8 @@ parse_action(struct action_context *ctx) parse_REJECT(ctx); } else if (lexer_match_id(ctx->lexer, "ct_snat_to_vip")) { ovnact_put_CT_SNAT_TO_VIP(ctx->ovnacts); + } else if (lexer_match_id(ctx->lexer, "put_fdb")) { + parse_put_fdb(ctx, ovnact_put_PUT_FDB(ctx->ovnacts)); } else { lexer_syntax_error(ctx->lexer, "expecting action"); } diff --git a/ovn-sb.xml b/ovn-sb.xml index b8912b33c8..35000ed681 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -1526,6 +1526,68 @@

+
P = get_fdb(A);
+ +
+

+ Parameters:48-bit MAC address field A. +

+ +

+ Looks up A in fdb table. If an entry is found, stores + the logical port key to the out parameter P. +

+ +

Example: outport = get_fdb(eth.src);

+
+ +
+ put_fdb(P, A); +
+ +
+

+ Parameters: logical port string field P, 48-bit + MAC address field A. +

+ +

+ Adds or updates the entry for Ethernet address A in + fdb table, setting its logical port key to P. +

+ +

Example: put_fdb(inport, arp.spa);

+
+ +
+ R = lookup_fdb(P, A); +
+ +
+

+ Parameters: 48-bit MAC address field M, + logical port string field P. +

+ +

+ Result: stored to a 1-bit subfield R. +

+ +

+ Looks up A in fdb table. If an entry is found + and the the logical port key is P, P, + stores 1 in the 1-bit subfield + R, else 0. +

+ +

+ Example: + + reg0[0] = lookup_fdb(inport, eth.src); + +

+
+
nd_ns { action; ... };

diff --git a/tests/ovn.at b/tests/ovn.at index 80c9fe138a..8dbd3bf932 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1822,6 +1822,64 @@ ct_snat_to_vip(foo); handle_bfd_msg(); encodes as controller(userdata=00.00.00.17.00.00.00.00) +# put_fdb +put_fdb(inport, arp.sha); + encodes as push:NXM_OF_ETH_SRC[],push:NXM_NX_ARP_SHA[],pop:NXM_OF_ETH_SRC[],controller(userdata=00.00.00.19.00.00.00.00),pop:NXM_OF_ETH_SRC[] + has prereqs eth.type == 0x806 + +put_fdb(inport, eth.src); + encodes as controller(userdata=00.00.00.19.00.00.00.00) + +put_fdb(inport, ip4.src); + Cannot use 32-bit field ip4.src[0..31] where 48-bit field is required. + +# get_fdb +outport = get_fdb(eth.dst); + encodes as set_field:0->reg15,resubmit(,71) + +outport = get_fdb(eth.src); + encodes as push:NXM_OF_ETH_DST[],push:NXM_OF_ETH_SRC[],pop:NXM_OF_ETH_DST[],set_field:0->reg15,resubmit(,71),pop:NXM_OF_ETH_DST[] + +inport = get_fdb(arp.sha); + encodes as push:NXM_OF_ETH_DST[],push:NXM_NX_ARP_SHA[],pop:NXM_OF_ETH_DST[],set_field:0->reg15,resubmit(,71),pop:NXM_OF_ETH_DST[],move:NXM_NX_REG15[]->NXM_NX_REG14[] + has prereqs eth.type == 0x806 + +reg0 = get_fdb(arp.tha); + encodes as push:NXM_OF_ETH_DST[],push:NXM_NX_ARP_THA[],pop:NXM_OF_ETH_DST[],set_field:0->reg15,resubmit(,71),pop:NXM_OF_ETH_DST[],move:NXM_NX_REG15[]->NXM_NX_XXREG0[96..127] + has prereqs eth.type == 0x806 + +reg0[1..3] = get_fdb(eth.src); + Cannot use 3-bit field reg0[1..3] where 32-bit field is required. + +reg15 = get_fdb(eth.dst); + Syntax error at `reg15' expecting field name. + +outport = get_fdb(ip4.dst); + Cannot use 32-bit field ip4.dst[0..31] where 48-bit field is required. + +# lookup_fdb +reg0[0] = lookup_fdb(inport, eth.src); + encodes as set_field:0/0x100->reg10,resubmit(,72),move:NXM_NX_REG10[8]->NXM_NX_XXREG0[96] + +reg1[4] = lookup_fdb(outport, eth.dst); + encodes as push:NXM_NX_REG14[],push:NXM_OF_ETH_SRC[],push:NXM_OF_ETH_DST[],push:NXM_NX_REG15[],pop:NXM_NX_REG14[],pop:NXM_OF_ETH_SRC[],set_field:0/0x100->reg10,resubmit(,72),pop:NXM_OF_ETH_SRC[],pop:NXM_NX_REG14[],move:NXM_NX_REG10[8]->NXM_NX_XXREG0[68] + +reg0[0] = lookup_fdb(outport, arp.sha); + encodes as push:NXM_NX_REG14[],push:NXM_OF_ETH_SRC[],push:NXM_NX_ARP_SHA[],push:NXM_NX_REG15[],pop:NXM_NX_REG14[],pop:NXM_OF_ETH_SRC[],set_field:0/0x100->reg10,resubmit(,72),pop:NXM_OF_ETH_SRC[],pop:NXM_NX_REG14[],move:NXM_NX_REG10[8]->NXM_NX_XXREG0[96] + has prereqs eth.type == 0x806 + +reg0 = lookup_fdb(outport, arp.sha); + Cannot use 32-bit field reg0[0..31] where 1-bit field is required. + +outport = lookup_fdb(outport, arp.sha); + Cannot use string field outport where numeric field is required. + +reg1[1] = lookup_fdb(outport, ip4.src); + Cannot use 32-bit field ip4.src[0..31] where 48-bit field is required. + +reg1[1] = lookup_fdb(ip4.src, eth.src); + Cannot use numeric field ip4.src where string field is required. + # Miscellaneous negative tests. ; Syntax error at `;'. diff --git a/tests/test-ovn.c b/tests/test-ovn.c index 9bd13a037f..202a96c5dd 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -1348,6 +1348,8 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) .lb_hairpin_ptable = OFTABLE_CHK_LB_HAIRPIN, .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY, .ct_snat_vip_ptable = OFTABLE_CT_SNAT_FOR_VIP, + .fdb_ptable = OFTABLE_GET_FDB, + .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, }; struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 0); diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index c0a0edc0a3..fead759b49 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -405,6 +405,7 @@ struct ovntrace_datapath { size_t n_flows, allocated_flows; struct hmap mac_bindings; /* Contains "struct ovntrace_mac_binding"s. */ + struct hmap fdbs; /* Contains "struct ovntrace_fdb"s. */ bool has_local_l3gateway; }; @@ -453,12 +454,24 @@ struct ovntrace_mac_binding { struct eth_addr mac; }; +struct ovntrace_fdb { + struct hmap_node node; + uint16_t port_key; + struct eth_addr mac; +}; + static inline uint32_t hash_mac_binding(uint16_t port_key, const struct in6_addr *ip) { return hash_bytes(ip, sizeof *ip, port_key); } +static inline uint32_t +hash_fdb(const struct eth_addr *mac) +{ + return hash_bytes(mac, sizeof *mac, 0); +} + /* Every ovntrace_datapath, by southbound Datapath_Binding record UUID. */ static struct hmap datapaths; @@ -518,6 +531,18 @@ ovntrace_datapath_find_by_name(const char *name) return match; } +static struct ovntrace_datapath * +ovntrace_datapath_find_by_key(uint32_t tunnel_key) +{ + struct ovntrace_datapath *dp; + HMAP_FOR_EACH (dp, sb_uuid_node, &datapaths) { + if (dp->tunnel_key == tunnel_key) { + return dp; + } + } + return NULL; +} + static const struct ovntrace_port * ovntrace_port_find_by_key(const struct ovntrace_datapath *dp, uint16_t tunnel_key) @@ -598,6 +623,20 @@ ovntrace_mac_binding_find_mac_ip(const struct ovntrace_datapath *dp, return NULL; } +static const struct ovntrace_fdb * +ovntrace_fdb_find(const struct ovntrace_datapath *dp, + const struct eth_addr *mac) +{ + const struct ovntrace_fdb *fdb; + HMAP_FOR_EACH_WITH_HASH (fdb, node, hash_fdb(mac), + &dp->fdbs) { + if (eth_addr_equals(fdb->mac, *mac)) { + return fdb; + } + } + return NULL; +} + /* If 's' ends with a UUID, returns a copy of it with the UUID truncated to * just the first 6 characters; otherwise, returns a copy of 's'. */ static char * @@ -638,7 +677,7 @@ read_datapaths(void) ovs_list_init(&dp->mcgroups); hmap_init(&dp->mac_bindings); - + hmap_init(&dp->fdbs); hmap_insert(&datapaths, &dp->sb_uuid_node, uuid_hash(&dp->sb_uuid)); } } @@ -1053,6 +1092,30 @@ read_mac_bindings(void) } } +static void +read_fdbs(void) +{ + const struct sbrec_fdb *fdb; + SBREC_FDB_FOR_EACH (fdb, ovnsb_idl) { + struct eth_addr mac; + if (!eth_addr_from_string(fdb->mac, &mac)) { + VLOG_WARN("%s: bad Ethernet address", fdb->mac); + continue; + } + + struct ovntrace_datapath *dp = + ovntrace_datapath_find_by_key(fdb->dp_key); + if (!dp) { + continue; + } + + struct ovntrace_fdb *fdb_t = xmalloc(sizeof *fdb_t); + fdb_t->mac = mac; + fdb_t->port_key = fdb->port_key; + hmap_insert(&dp->fdbs, &fdb_t->node, hash_fdb(&mac)); + } +} + static void read_db(void) { @@ -1064,6 +1127,7 @@ read_db(void) read_gen_opts(); read_flows(); read_mac_bindings(); + read_fdbs(); } static const struct ovntrace_port * @@ -2029,6 +2093,66 @@ execute_lookup_mac_bind_ip(const struct ovnact_lookup_mac_bind_ip *bind, mf_write_subfield_flow(&dst, &sv, uflow); } +static void +execute_lookup_fdb(const struct ovnact_lookup_fdb *lookup_fdb, + const struct ovntrace_datapath *dp, + struct flow *uflow, + struct ovs_list *super) +{ + /* Get logical port number.*/ + struct mf_subfield port_sf = expr_resolve_field(&lookup_fdb->port); + ovs_assert(port_sf.n_bits == 32); + uint32_t port_key = mf_get_subfield(&port_sf, uflow); + + /* Get MAC. */ + struct mf_subfield mac_sf = expr_resolve_field(&lookup_fdb->mac); + ovs_assert(mac_sf.n_bits == 48); + union mf_subvalue mac_sv; + mf_read_subfield(&mac_sf, uflow, &mac_sv); + + const struct ovntrace_fdb *fdb_t + = ovntrace_fdb_find(dp, &mac_sv.mac); + + struct mf_subfield dst = expr_resolve_field(&lookup_fdb->dst); + uint8_t val = 0; + + if (fdb_t && fdb_t->port_key == port_key) { + val = 1; + ovntrace_node_append(super, OVNTRACE_NODE_ACTION, + "/* MAC lookup for "ETH_ADDR_FMT" found in " + "FDB. */", ETH_ADDR_ARGS(uflow->dl_dst)); + } else { + ovntrace_node_append(super, OVNTRACE_NODE_ACTION, + "/* lookup mac failed in mac learning table. */"); + } + union mf_subvalue sv = { .u8_val = val }; + mf_write_subfield_flow(&dst, &sv, uflow); +} + +static void +execute_get_fdb(const struct ovnact_get_fdb *get_fdb, + const struct ovntrace_datapath *dp, + struct flow *uflow) +{ + /* Get MAC. */ + struct mf_subfield mac_sf = expr_resolve_field(&get_fdb->mac); + ovs_assert(mac_sf.n_bits == 48); + union mf_subvalue mac_sv; + mf_read_subfield(&mac_sf, uflow, &mac_sv); + + const struct ovntrace_fdb *fdb_t + = ovntrace_fdb_find(dp, &mac_sv.mac); + + struct mf_subfield dst = expr_resolve_field(&get_fdb->dst); + uint32_t val = 0; + if (fdb_t) { + val = fdb_t->port_key; + } + + union mf_subvalue sv = { .be32_int = htonl(val) }; + mf_write_subfield_flow(&dst, &sv, uflow); +} + static void execute_put_opts(const struct ovnact_put_opts *po, const char *name, struct flow *uflow, @@ -2638,6 +2762,18 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, break; case OVNACT_BFD_MSG: break; + + case OVNACT_PUT_FDB: + /* Nothing to do for tracing. */ + break; + + case OVNACT_GET_FDB: + execute_get_fdb(ovnact_get_GET_FDB(a), dp, uflow); + break; + + case OVNACT_LOOKUP_FDB: + execute_lookup_fdb(ovnact_get_LOOKUP_FDB(a), dp, uflow, super); + break; } } ds_destroy(&s); From patchwork Fri Feb 5 07:00:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1436460 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=) 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 4DX5sV6h48z9sWg for ; Fri, 5 Feb 2021 18:00:30 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 240D12E109; Fri, 5 Feb 2021 07:00:28 +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 XBDJdMtOSC5d; Fri, 5 Feb 2021 07:00:17 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 5AC2F20397; Fri, 5 Feb 2021 07:00:17 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3BD07C08A1; Fri, 5 Feb 2021 07:00:17 +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 336B3C08A1 for ; Fri, 5 Feb 2021 07:00:15 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 1F04A86F90 for ; Fri, 5 Feb 2021 07:00:15 +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 D8Ga0yW7rV34 for ; Fri, 5 Feb 2021 07:00:13 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by whitealder.osuosl.org (Postfix) with ESMTPS id AFC9886EB0 for ; Fri, 5 Feb 2021 07:00:12 +0000 (UTC) X-Originating-IP: 115.99.223.251 Received: from nusiddiq.home.org.com (unknown [115.99.223.251]) (Authenticated sender: numans@ovn.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id EF131E000E; Fri, 5 Feb 2021 07:00:07 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Fri, 5 Feb 2021 12:30:04 +0530 Message-Id: <20210205070004.40218-1-numans@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210205065622.39226-1-numans@ovn.org> References: <20210205065622.39226-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 4/6] controller: MAC learning: Add OF rules for the FDB entries. 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: Numan Siddique This patch adds the OF rules in table 71 and 72 to support 'get_fdb' and 'lookup_fdb' actions. Signed-off-by: Numan Siddique --- controller/lflow.c | 103 ++++++++++++++++++++++++++++++++++++ controller/lflow.h | 2 + controller/ovn-controller.c | 27 +++++++++- 3 files changed, 131 insertions(+), 1 deletion(-) diff --git a/controller/lflow.c b/controller/lflow.c index baf6932d51..6c74fe9c85 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -1080,6 +1080,18 @@ put_load(const uint8_t *data, size_t len, bitwise_one(ofpact_set_field_mask(sf), sf->field->n_bytes, ofs, n_bits); } +static void +put_load64(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, + struct ofpbuf *ofpacts) +{ + struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts, + mf_from_id(dst), NULL, + NULL); + ovs_be64 n_value = htonll(value); + bitwise_copy(&n_value, 8, 0, sf->value, sf->field->n_bytes, ofs, n_bits); + bitwise_one(ofpact_set_field_mask(sf), sf->field->n_bytes, ofs, n_bits); +} + static void consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name, const struct hmap *local_datapaths, @@ -1419,6 +1431,61 @@ lflow_handle_changed_neighbors( } } +static void +consider_fdb_flows(const struct sbrec_fdb *fdb, + const struct hmap *local_datapaths, + struct ovn_desired_flow_table *flow_table) +{ + if (!get_local_datapath(local_datapaths, fdb->dp_key)) { + return; + } + + struct eth_addr mac; + if (!eth_addr_from_string(fdb->mac, &mac)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad 'mac' %s", fdb->mac); + return; + } + + struct match match = MATCH_CATCHALL_INITIALIZER; + match_set_metadata(&match, htonll(fdb->dp_key)); + match_set_dl_dst(&match, mac); + + uint64_t stub[1024 / 8]; + struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub); + put_load64(fdb->port_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); + ofctrl_add_flow(flow_table, OFTABLE_GET_FDB, 100, + fdb->header_.uuid.parts[0], &match, &ofpacts, + &fdb->header_.uuid); + ofpbuf_clear(&ofpacts); + + uint8_t value = 1; + put_load(&value, sizeof value, MFF_LOG_FLAGS, + MLF_LOOKUP_FDB_BIT, 1, &ofpacts); + + struct match lookup_match = MATCH_CATCHALL_INITIALIZER; + match_set_metadata(&lookup_match, htonll(fdb->dp_key)); + match_set_dl_src(&lookup_match, mac); + match_set_reg(&lookup_match, MFF_LOG_INPORT - MFF_REG0, fdb->port_key); + ofctrl_add_flow(flow_table, OFTABLE_LOOKUP_FDB, 100, + fdb->header_.uuid.parts[0], &lookup_match, &ofpacts, + &fdb->header_.uuid); + ofpbuf_uninit(&ofpacts); +} + +/* Adds an OpenFlow flow to flow tables for each MAC binding in the OVN + * southbound database. */ +static void +add_fdb_flows(const struct sbrec_fdb_table *fdb_table, + const struct hmap *local_datapaths, + struct ovn_desired_flow_table *flow_table) +{ + const struct sbrec_fdb *fdb; + SBREC_FDB_TABLE_FOR_EACH (fdb, fdb_table) { + consider_fdb_flows(fdb, local_datapaths, flow_table); + } +} + /* Translates logical flows in the Logical_Flow table in the OVN_SB database * into OpenFlow flows. See ovn-architecture(7) for more information. */ @@ -1446,6 +1513,8 @@ lflow_run(struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out) l_ctx_out->flow_table); add_lb_hairpin_flows(l_ctx_in->lb_table, l_ctx_in->local_datapaths, l_ctx_out->flow_table); + add_fdb_flows(l_ctx_in->fdb_table, l_ctx_in->local_datapaths, + l_ctx_out->flow_table); } void @@ -1597,3 +1666,37 @@ lflow_handle_changed_lbs(struct lflow_ctx_in *l_ctx_in, return true; } + +bool +lflow_handle_changed_fdbs(struct lflow_ctx_in *l_ctx_in, + struct lflow_ctx_out *l_ctx_out) +{ + const struct sbrec_fdb *fdb; + + SBREC_FDB_TABLE_FOR_EACH_TRACKED (fdb, l_ctx_in->fdb_table) { + if (sbrec_fdb_is_deleted(fdb)) { + VLOG_DBG("Remove fdb flows for deleted fdb "UUID_FMT, + UUID_ARGS(&fdb->header_.uuid)); + ofctrl_remove_flows(l_ctx_out->flow_table, &fdb->header_.uuid); + } + } + + SBREC_FDB_TABLE_FOR_EACH_TRACKED (fdb, l_ctx_in->fdb_table) { + if (sbrec_fdb_is_deleted(fdb)) { + continue; + } + + if (!sbrec_fdb_is_new(fdb)) { + VLOG_DBG("Remove fdb flows for updated fdb "UUID_FMT, + UUID_ARGS(&fdb->header_.uuid)); + ofctrl_remove_flows(l_ctx_out->flow_table, &fdb->header_.uuid); + } + + VLOG_DBG("Add fdb flows for fdb "UUID_FMT, + UUID_ARGS(&fdb->header_.uuid)); + consider_fdb_flows(fdb, l_ctx_in->local_datapaths, + l_ctx_out->flow_table); + } + + return true; +} diff --git a/controller/lflow.h b/controller/lflow.h index d790d518d8..9f8bed4938 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -138,6 +138,7 @@ struct lflow_ctx_in { const struct sbrec_logical_flow_table *logical_flow_table; const struct sbrec_logical_dp_group_table *logical_dp_group_table; const struct sbrec_multicast_group_table *mc_group_table; + const struct sbrec_fdb_table *fdb_table; const struct sbrec_chassis *chassis; const struct sbrec_load_balancer_table *lb_table; const struct hmap *local_datapaths; @@ -169,6 +170,7 @@ void lflow_handle_changed_neighbors( const struct hmap *local_datapaths, struct ovn_desired_flow_table *); bool lflow_handle_changed_lbs(struct lflow_ctx_in *, struct lflow_ctx_out *); +bool lflow_handle_changed_fdbs(struct lflow_ctx_in *, struct lflow_ctx_out *); void lflow_destroy(void); void lflow_cache_init(struct hmap *); diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 42858d60fa..32f3f69324 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -923,7 +923,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) SB_NODE(dhcp_options, "dhcp_options") \ SB_NODE(dhcpv6_options, "dhcpv6_options") \ SB_NODE(dns, "dns") \ - SB_NODE(load_balancer, "load_balancer") + SB_NODE(load_balancer, "load_balancer") \ + SB_NODE(fdb, "fdb") enum sb_engine_node { #define SB_NODE(NAME, NAME_STR) SB_##NAME, @@ -1854,6 +1855,10 @@ static void init_lflow_ctx(struct engine_node *node, (struct sbrec_load_balancer_table *)EN_OVSDB_GET( engine_get_input("SB_load_balancer", node)); + struct sbrec_fdb_table *fdb_table = + (struct sbrec_fdb_table *)EN_OVSDB_GET( + engine_get_input("SB_fdb", node)); + struct ovsrec_open_vswitch_table *ovs_table = (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET( engine_get_input("OVS_open_vswitch", node)); @@ -1891,6 +1896,7 @@ static void init_lflow_ctx(struct engine_node *node, l_ctx_in->logical_flow_table = logical_flow_table; l_ctx_in->logical_dp_group_table = logical_dp_group_table; l_ctx_in->mc_group_table = multicast_group_table; + l_ctx_in->fdb_table = fdb_table, l_ctx_in->chassis = chassis; l_ctx_in->lb_table = lb_table; l_ctx_in->local_datapaths = &rt_data->local_datapaths; @@ -2331,6 +2337,23 @@ flow_output_sb_load_balancer_handler(struct engine_node *node, void *data) return handled; } +static bool +flow_output_sb_fdb_handler(struct engine_node *node, void *data) +{ + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + + struct ed_type_flow_output *fo = data; + struct lflow_ctx_in l_ctx_in; + struct lflow_ctx_out l_ctx_out; + init_lflow_ctx(node, rt_data, fo, &l_ctx_in, &l_ctx_out); + + bool handled = lflow_handle_changed_fdbs(&l_ctx_in, &l_ctx_out); + + engine_set_node_state(node, EN_UPDATED); + return handled; +} + struct ovn_controller_exit_args { bool *exiting; bool *restart; @@ -2592,6 +2615,8 @@ main(int argc, char *argv[]) engine_add_input(&en_flow_output, &en_sb_dns, NULL); engine_add_input(&en_flow_output, &en_sb_load_balancer, flow_output_sb_load_balancer_handler); + engine_add_input(&en_flow_output, &en_sb_fdb, + flow_output_sb_fdb_handler); engine_add_input(&en_ct_zones, &en_ovs_open_vswitch, NULL); engine_add_input(&en_ct_zones, &en_ovs_bridge, NULL); From patchwork Fri Feb 5 07:00:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1436468 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=) 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 4DX5tk6qbxz9sWg for ; Fri, 5 Feb 2021 18:01:34 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 5D4B22E139; Fri, 5 Feb 2021 07:01:33 +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 I65Da+55GqeL; Fri, 5 Feb 2021 07:00:46 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 5D320203E9; Fri, 5 Feb 2021 07:00:35 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4FD26C08A1; Fri, 5 Feb 2021 07:00:35 +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 C571FC0174 for ; Fri, 5 Feb 2021 07:00:33 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id B6CDF872BA for ; Fri, 5 Feb 2021 07:00:33 +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 hg2zETUAXhlE for ; Fri, 5 Feb 2021 07:00:29 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by hemlock.osuosl.org (Postfix) with ESMTPS id D3471872EE for ; Fri, 5 Feb 2021 07:00:28 +0000 (UTC) X-Originating-IP: 115.99.223.251 Received: from nusiddiq.home.org.com (unknown [115.99.223.251]) (Authenticated sender: numans@ovn.org) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id EAA276000A; Fri, 5 Feb 2021 07:00:25 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Fri, 5 Feb 2021 12:30:22 +0530 Message-Id: <20210205070022.40327-1-numans@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210205065622.39226-1-numans@ovn.org> References: <20210205065622.39226-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 5/6] northd: MAC learning: Add logical flows for fdb. 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: Numan Siddique This patch adds the logical flows to do mac learning for the logical ports whose port security is disabled with 'unknown' addresses set. Until now, OVN delivers the unknown destination packets to all the logical ports with 'unknown' addresses set. With this mac learning feature, such flooding of packets is avoided once OVN has learnt the port-to-mac bindings. Note that we don't learn macs seen on the localnet logical ports. Signed-off-by: Numan Siddique --- controller/lflow.c | 5 + controller/lflow.h | 9 +- lib/ovn-util.h | 3 + northd/ovn-northd.8.xml | 162 +++++++++++-- northd/ovn-northd.c | 96 ++++++-- ovn-sb.ovsschema | 6 +- tests/ovn-northd.at | 32 +-- tests/ovn.at | 517 ++++++++++++++++++++++++++++++++++++---- utilities/ovn-trace.c | 7 +- 9 files changed, 722 insertions(+), 115 deletions(-) diff --git a/controller/lflow.c b/controller/lflow.c index 6c74fe9c85..544b47b41b 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -88,6 +88,11 @@ static void lflow_resource_destroy_lflow(struct lflow_resource_ref *, static bool lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp) { + if (!strcmp(port_name, "none")) { + *portp = 0; + return true; + } + const struct lookup_port_aux *aux = aux_; const struct sbrec_port_binding *pb diff --git a/controller/lflow.h b/controller/lflow.h index 9f8bed4938..2eb2cb1121 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -60,9 +60,9 @@ struct uuid; * you make any changes. */ #define OFTABLE_PHY_TO_LOG 0 #define OFTABLE_LOG_INGRESS_PIPELINE 8 /* First of LOG_PIPELINE_LEN tables. */ -#define OFTABLE_REMOTE_OUTPUT 32 -#define OFTABLE_LOCAL_OUTPUT 33 -#define OFTABLE_CHECK_LOOPBACK 34 +#define OFTABLE_REMOTE_OUTPUT 37 +#define OFTABLE_LOCAL_OUTPUT 38 +#define OFTABLE_CHECK_LOOPBACK 39 #define OFTABLE_LOG_EGRESS_PIPELINE 40 /* First of LOG_PIPELINE_LEN tables. */ #define OFTABLE_SAVE_INPORT 64 #define OFTABLE_LOG_TO_PHY 65 @@ -74,9 +74,6 @@ struct uuid; #define OFTABLE_GET_FDB 71 #define OFTABLE_LOOKUP_FDB 72 -/* The number of tables for the ingress and egress pipelines. */ -#define LOG_PIPELINE_LEN 24 - enum ref_type { REF_TYPE_ADDRSET, REF_TYPE_PORTGROUP, diff --git a/lib/ovn-util.h b/lib/ovn-util.h index 0823461183..df4b0bc989 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -261,4 +261,7 @@ BUILD_ASSERT_DECL(SCTP_INIT_CHUNK_LEN == sizeof(struct sctp_init_chunk)); /* See RFC 4960 Sections 3.3.7 and 8.5.1 for information on this flag. */ #define SCTP_ABORT_CHUNK_FLAG_T (1 << 0) +/* The number of tables for the ingress and egress pipelines. */ +#define LOG_PIPELINE_LEN 29 + #endif diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index 70065a36d9..0251a89dc0 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -307,7 +307,73 @@ -

Ingress Table 3: from-lport Pre-ACLs

+

Ingress Table 3: Lookup MAC address learning table

+ +

+ This table looks up the MAC learning table of the logical switch + datapath to check if the port-mac pair is present + or not. MAC is learnt only for logical switch VIF ports whose + port security is disabled and 'unknown' address set. +

+ +
    +
  • +

    + For each such logical port p whose port security + is disabled and 'unknown' address set following flow + is added. +

    + +
      +
    • + Priority 100 flow with the match + inport == p and action + reg0[11] = lookup_fdb(inport, eth.src); next; +
    • +
    +
  • + +
  • + One priority-0 fallback flow that matches all packets and advances to + the next table. +
  • +
+ +

Ingress Table 4: Learn MAC of 'unknown' ports.

+ +

+ This table learns the MAC addresses seen on the logical ports + whose port security is disabled and 'unknown' address set + if the lookup_fdb action returned false in the + previous table. +

+ +
    +
  • +

    + For each such logical port p whose port security + is disabled and 'unknown' address set following flow + is added. +

    + +
      +
    • + Priority 100 flow with the match + inport == p && reg0[11] == 0 and + action put_fdb(inport, eth.src); next; which stores + the port-mac in the mac learning table of the + logical switch datapath and advances the packet to the next table. +
    • +
    +
  • + +
  • + One priority-0 fallback flow that matches all packets and advances to + the next table. +
  • +
+ +

Ingress Table 5: from-lport Pre-ACLs

This table prepares flows for possible stateful ACL processing in @@ -332,7 +398,7 @@ db="OVN_Northbound"/> table.

-

Ingress Table 4: Pre-LB

+

Ingress Table 6: Pre-LB

This table prepares flows for possible stateful load balancing processing @@ -399,7 +465,7 @@ logical router datapath to logical switch datapath.

-

Ingress Table 5: Pre-stateful

+

Ingress Table 7: Pre-stateful

This table prepares flows for all possible stateful processing @@ -410,7 +476,7 @@ ct_next; action.

-

Ingress Table 6: from-lport ACL hints

+

Ingress Table 8: from-lport ACL hints

This table consists of logical flows that set hints @@ -489,7 +555,7 @@ -

Ingress table 7: from-lport ACLs

+

Ingress table 9: from-lport ACLs

Logical flows in this table closely reproduce those in the @@ -598,7 +664,7 @@ -

Ingress Table 8: from-lport QoS Marking

+

Ingress Table 10: from-lport QoS Marking

Logical flows in this table closely reproduce those in the @@ -620,7 +686,7 @@ -

Ingress Table 9: from-lport QoS Meter

+

Ingress Table 11: from-lport QoS Meter

Logical flows in this table closely reproduce those in the @@ -642,7 +708,7 @@ -

Ingress Table 10: LB

+

Ingress Table 12: LB

It contains a priority-0 flow that simply moves traffic to the next @@ -668,7 +734,7 @@ connection.)

-

Ingress Table 11: Stateful

+

Ingress Table 13: Stateful

  • @@ -726,7 +792,7 @@
-

Ingress Table 12: Pre-Hairpin

+

Ingress Table 14: Pre-Hairpin

  • If the logical switch has load balancer(s) configured, then a @@ -751,7 +817,7 @@
-

Ingress Table 13: Nat-Hairpin

+

Ingress Table 15: Nat-Hairpin

  • If the logical switch has load balancer(s) configured, then a @@ -777,7 +843,7 @@
-

Ingress Table 14: Hairpin

+

Ingress Table 16: Hairpin

  • A priority-1 flow that hairpins traffic matched by non-default @@ -790,7 +856,7 @@
-

Ingress Table 15: ARP/ND responder

+

Ingress Table 17: ARP/ND responder

This table implements ARP/ND responder in a logical switch for known @@ -1080,7 +1146,7 @@ output; -

Ingress Table 16: DHCP option processing

+

Ingress Table 18: DHCP option processing

This table adds the DHCPv4 options to a DHCPv4 packet from the @@ -1141,7 +1207,7 @@ next; -

Ingress Table 17: DHCP responses

+

Ingress Table 19: DHCP responses

This table implements DHCP responder for the DHCP replies generated by @@ -1222,7 +1288,7 @@ output; -

Ingress Table 18 DNS Lookup

+

Ingress Table 20 DNS Lookup

This table looks up and resolves the DNS names to the corresponding @@ -1251,7 +1317,7 @@ reg0[4] = dns_lookup(); next; -

Ingress Table 19 DNS Responses

+

Ingress Table 21 DNS Responses

This table implements DNS responder for the DNS replies generated by @@ -1286,7 +1352,7 @@ output; -

Ingress table 20 External ports

+

Ingress table 22 External ports

Traffic from the external logical ports enter the ingress @@ -1329,7 +1395,7 @@ output; -

Ingress Table 21 Destination Lookup

+

Ingress Table 23 Destination Lookup

This table implements switching behavior. It contains these logical @@ -1492,12 +1558,58 @@ output;

  • - One priority-0 fallback flow that matches all packets and outputs them - to the MC_UNKNOWN multicast group, which - ovn-northd populates with all enabled logical ports that - accept unknown destination packets. As a small optimization, if no - logical ports accept unknown destination packets, - ovn-northd omits this multicast group and logical flow. + One priority-0 fallback flow that matches all packets with the + action outport = get_fdb(eth.dst); next;. The action + get_fdb gets the port for the eth.dst + in the MAC learning table of the logical switch datapath. If there + is no entry for eth.dst in the MAC learning table, + then it stores none in the outport. +
  • + + +

    Ingress Table 23 Destination unknown

    + +

    + This table handles the packets whose destination was not found or + and looked up in the MAC learning table of the logical switch + datapath. It contains the following flows. +

    + +
      +
    • +

      + If the logical switch has logical ports with 'unknown' addresses set, + then the below logical flow is added +

      + +
        +
      • + Priority 50 flow with the match outport == none then + outputs them to the MC_UNKNOWN multicast group, which + ovn-northd populates with all enabled logical ports + that accept unknown destination packets. As a small optimization, + if no logical ports accept unknown destination packets, + ovn-northd omits this multicast group and logical + flow. +
      • +
      + +

      + If the logical switch has no logical ports with 'unknown' address + set, then the below logical flow is added +

      + +
        +
      • + Priority 50 flow with the match outport == none + and drops the packets. +
      • +
      +
    • + +
    • + One priority-0 fallback flow that outputs the packet to the egress + stage with the outport learnt from get_fdb action.
    diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 12a24a694f..23c26de36f 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -138,25 +138,28 @@ enum ovn_stage { PIPELINE_STAGE(SWITCH, IN, PORT_SEC_L2, 0, "ls_in_port_sec_l2") \ PIPELINE_STAGE(SWITCH, IN, PORT_SEC_IP, 1, "ls_in_port_sec_ip") \ PIPELINE_STAGE(SWITCH, IN, PORT_SEC_ND, 2, "ls_in_port_sec_nd") \ - PIPELINE_STAGE(SWITCH, IN, PRE_ACL, 3, "ls_in_pre_acl") \ - PIPELINE_STAGE(SWITCH, IN, PRE_LB, 4, "ls_in_pre_lb") \ - PIPELINE_STAGE(SWITCH, IN, PRE_STATEFUL, 5, "ls_in_pre_stateful") \ - PIPELINE_STAGE(SWITCH, IN, ACL_HINT, 6, "ls_in_acl_hint") \ - PIPELINE_STAGE(SWITCH, IN, ACL, 7, "ls_in_acl") \ - PIPELINE_STAGE(SWITCH, IN, QOS_MARK, 8, "ls_in_qos_mark") \ - PIPELINE_STAGE(SWITCH, IN, QOS_METER, 9, "ls_in_qos_meter") \ - PIPELINE_STAGE(SWITCH, IN, LB, 10, "ls_in_lb") \ - PIPELINE_STAGE(SWITCH, IN, STATEFUL, 11, "ls_in_stateful") \ - PIPELINE_STAGE(SWITCH, IN, PRE_HAIRPIN, 12, "ls_in_pre_hairpin") \ - PIPELINE_STAGE(SWITCH, IN, NAT_HAIRPIN, 13, "ls_in_nat_hairpin") \ - PIPELINE_STAGE(SWITCH, IN, HAIRPIN, 14, "ls_in_hairpin") \ - PIPELINE_STAGE(SWITCH, IN, ARP_ND_RSP, 15, "ls_in_arp_rsp") \ - PIPELINE_STAGE(SWITCH, IN, DHCP_OPTIONS, 16, "ls_in_dhcp_options") \ - PIPELINE_STAGE(SWITCH, IN, DHCP_RESPONSE, 17, "ls_in_dhcp_response") \ - PIPELINE_STAGE(SWITCH, IN, DNS_LOOKUP, 18, "ls_in_dns_lookup") \ - PIPELINE_STAGE(SWITCH, IN, DNS_RESPONSE, 19, "ls_in_dns_response") \ - PIPELINE_STAGE(SWITCH, IN, EXTERNAL_PORT, 20, "ls_in_external_port") \ - PIPELINE_STAGE(SWITCH, IN, L2_LKUP, 21, "ls_in_l2_lkup") \ + PIPELINE_STAGE(SWITCH, IN, LOOKUP_FDB , 3, "ls_in_lookup_fdb") \ + PIPELINE_STAGE(SWITCH, IN, PUT_FDB, 4, "ls_in_put_fdb") \ + PIPELINE_STAGE(SWITCH, IN, PRE_ACL, 5, "ls_in_pre_acl") \ + PIPELINE_STAGE(SWITCH, IN, PRE_LB, 6, "ls_in_pre_lb") \ + PIPELINE_STAGE(SWITCH, IN, PRE_STATEFUL, 7, "ls_in_pre_stateful") \ + PIPELINE_STAGE(SWITCH, IN, ACL_HINT, 8, "ls_in_acl_hint") \ + PIPELINE_STAGE(SWITCH, IN, ACL, 9, "ls_in_acl") \ + PIPELINE_STAGE(SWITCH, IN, QOS_MARK, 10, "ls_in_qos_mark") \ + PIPELINE_STAGE(SWITCH, IN, QOS_METER, 11, "ls_in_qos_meter") \ + PIPELINE_STAGE(SWITCH, IN, LB, 12, "ls_in_lb") \ + PIPELINE_STAGE(SWITCH, IN, STATEFUL, 13, "ls_in_stateful") \ + PIPELINE_STAGE(SWITCH, IN, PRE_HAIRPIN, 14, "ls_in_pre_hairpin") \ + PIPELINE_STAGE(SWITCH, IN, NAT_HAIRPIN, 15, "ls_in_nat_hairpin") \ + PIPELINE_STAGE(SWITCH, IN, HAIRPIN, 16, "ls_in_hairpin") \ + PIPELINE_STAGE(SWITCH, IN, ARP_ND_RSP, 17, "ls_in_arp_rsp") \ + PIPELINE_STAGE(SWITCH, IN, DHCP_OPTIONS, 18, "ls_in_dhcp_options") \ + PIPELINE_STAGE(SWITCH, IN, DHCP_RESPONSE, 19, "ls_in_dhcp_response") \ + PIPELINE_STAGE(SWITCH, IN, DNS_LOOKUP, 20, "ls_in_dns_lookup") \ + PIPELINE_STAGE(SWITCH, IN, DNS_RESPONSE, 21, "ls_in_dns_response") \ + PIPELINE_STAGE(SWITCH, IN, EXTERNAL_PORT, 22, "ls_in_external_port") \ + PIPELINE_STAGE(SWITCH, IN, L2_LKUP, 23, "ls_in_l2_lkup") \ + PIPELINE_STAGE(SWITCH, IN, L2_UNKNOWN, 24, "ls_in_l2_unknown") \ \ /* Logical switch egress stages. */ \ PIPELINE_STAGE(SWITCH, OUT, PRE_LB, 0, "ls_out_pre_lb") \ @@ -223,6 +226,7 @@ enum ovn_stage { #define REGBIT_ACL_HINT_ALLOW "reg0[8]" #define REGBIT_ACL_HINT_DROP "reg0[9]" #define REGBIT_ACL_HINT_BLOCK "reg0[10]" +#define REGBIT_LKUP_FDB "reg0[11]" /* Register definitions for switches and routers. */ @@ -4717,6 +4721,42 @@ build_lswitch_input_port_sec_od( } } +static void +build_lswitch_learn_fdb_op( + struct ovn_port *op, struct hmap *lflows, + struct ds *actions, struct ds *match) +{ + if (op->nbsp && !op->n_ps_addrs && !strcmp(op->nbsp->type, "") && + op->has_unknown) { + ds_clear(match); + ds_clear(actions); + ds_put_format(match, "inport == %s", op->json_key); + ds_put_format(actions, REGBIT_LKUP_FDB + " = lookup_fdb(inport, eth.src); next;"); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_LOOKUP_FDB, 100, + ds_cstr(match), ds_cstr(actions), + &op->nbsp->header_); + + ds_put_cstr(match, " && "REGBIT_LKUP_FDB" == 0"); + ds_clear(actions); + ds_put_cstr(actions, "put_fdb(inport, eth.src); next;"); + ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_PUT_FDB, 100, + ds_cstr(match), ds_cstr(actions), + &op->nbsp->header_); + } +} + +static void +build_lswitch_learn_fdb_od( + struct ovn_datapath *od, struct hmap *lflows) +{ + + if (od->nbs) { + ovn_lflow_add(lflows, od, S_SWITCH_IN_LOOKUP_FDB, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_PUT_FDB, 0, "1", "next;"); + } +} + /* Egress table 8: Egress port security - IP (priorities 90 and 80) * if port security enabled. * @@ -6572,16 +6612,25 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *lflows) struct ds actions = DS_EMPTY_INITIALIZER; struct ovn_datapath *od; - /* Ingress table 19: Destination lookup for unknown MACs (priority 0). */ + /* Ingress table 24: Destination lookup for unknown MACs (priority 0). */ HMAP_FOR_EACH (od, key_node, datapaths) { if (!od->nbs) { continue; } + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1", + "outport = get_fdb(eth.dst); next;"); + if (od->has_unknown) { - ovn_lflow_add_unique(lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1", - "outport = \""MC_UNKNOWN"\"; output;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50, + "outport == \"none\"", + "outport = \""MC_UNKNOWN"\"; output;"); + } else { + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50, + "outport == \"none\"", "drop;"); } + ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 0, "1", + "output;"); } ds_destroy(&match); @@ -11421,6 +11470,7 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *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_learn_fdb_od(od, lsi->lflows); build_lswitch_arp_nd_responder_default(od, lsi->lflows); build_lswitch_dns_lookup_and_response(od, lsi->lflows); build_lswitch_dhcp_and_dns_defaults(od, lsi->lflows); @@ -11460,6 +11510,8 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op, /* Build Logical Switch Flows. */ build_lswitch_input_port_sec_op(op, lsi->lflows, &lsi->actions, &lsi->match); + build_lswitch_learn_fdb_op(op, lsi->lflows, &lsi->actions, + &lsi->match); build_lswitch_arp_nd_responder_skip_local(op, lsi->lflows, &lsi->match); build_lswitch_arp_nd_responder_known_ips(op, lsi->lflows, diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index 246e3908a0..b5d3338f46 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "20.16.0", - "cksum": "1219580357 26536", + "version": "20.16.1", + "cksum": "4243908307 26536", "tables": { "SB_Global": { "columns": { @@ -103,7 +103,7 @@ "egress"]]}}}, "table_id": {"type": {"key": {"type": "integer", "minInteger": 0, - "maxInteger": 23}}}, + "maxInteger": 32}}}, "priority": {"type": {"key": {"type": "integer", "minInteger": 0, "maxInteger": 65535}}}, diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 7240e22baf..1b4160cfa0 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -1753,10 +1753,10 @@ AT_CAPTURE_FILE([sw1flows]) AT_CHECK( [grep -E 'ls_(in|out)_acl' sw0flows sw1flows | grep pg0 | sort], [0], [dnl -sw0flows: table=5 (ls_out_acl ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw0flows: table=7 (ls_in_acl ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };) -sw1flows: table=5 (ls_out_acl ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw1flows: table=7 (ls_in_acl ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };) +sw0flows: table=5 (ls_out_acl ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw0flows: table=9 (ls_in_acl ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };) +sw1flows: table=5 (ls_out_acl ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw1flows: table=9 (ls_in_acl ), priority=2002 , match=(inport == @pg0 && ip4 && tcp && tcp.dst == 80), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=egress,table=6); };) ]) AS_BOX([2]) @@ -1769,10 +1769,10 @@ ovn-sbctl dump-flows sw1 > sw1flows2 AT_CAPTURE_FILE([sw1flows2]) AT_CHECK([grep "ls_out_acl" sw0flows2 sw1flows2 | grep pg0 | sort], [0], [dnl -sw0flows2: table=5 (ls_out_acl ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw0flows2: table=5 (ls_out_acl ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw1flows2: table=5 (ls_out_acl ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw1flows2: table=5 (ls_out_acl ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) +sw0flows2: table=5 (ls_out_acl ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw0flows2: table=5 (ls_out_acl ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw1flows2: table=5 (ls_out_acl ), priority=2002 , match=(outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw1flows2: table=5 (ls_out_acl ), priority=2003 , match=(outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) ]) AS_BOX([3]) @@ -1787,16 +1787,16 @@ AT_CAPTURE_FILE([sw1flows3]) AT_CHECK([grep "ls_out_acl" sw0flows3 sw1flows3 | grep pg0 | sort], [0], [dnl sw0flows3: table=5 (ls_out_acl ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;) sw0flows3: table=5 (ls_out_acl ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;) -sw0flows3: table=5 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw0flows3: table=5 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw0flows3: table=5 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw0flows3: table=5 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) +sw0flows3: table=5 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw0flows3: table=5 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw0flows3: table=5 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw0flows3: table=5 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) sw1flows3: table=5 (ls_out_acl ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;) sw1flows3: table=5 (ls_out_acl ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;) -sw1flows3: table=5 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw1flows3: table=5 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw1flows3: table=5 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) -sw1flows3: table=5 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=21); };) +sw1flows3: table=5 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw1flows3: table=5 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw1flows3: table=5 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) +sw1flows3: table=5 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=23); };) ]) AT_CLEANUP diff --git a/tests/ovn.at b/tests/ovn.at index 8dbd3bf932..eee77a5dc4 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -8247,18 +8247,18 @@ as hv1 AT_CHECK([ovs-vsctl add-port br-int localvif1 -- set Interface localvif1 external_ids:iface-id=localvif1]) # On hv1, check that there are no flows outputting bcast to tunnel -OVS_WAIT_UNTIL([test `ovs-ofctl dump-flows br-int table=32 | ofctl_strip | grep output | wc -l` -eq 0]) +OVS_WAIT_UNTIL([test `ovs-ofctl dump-flows br-int table=37 | ofctl_strip | grep output | wc -l` -eq 0]) # On hv2, check that no flow outputs bcast to tunnel to hv1. as hv2 -OVS_WAIT_UNTIL([test `ovs-ofctl dump-flows br-int table=32 | ofctl_strip | grep output | wc -l` -eq 0]) +OVS_WAIT_UNTIL([test `ovs-ofctl dump-flows br-int table=37 | ofctl_strip | grep output | wc -l` -eq 0]) # Now bind vif2 on hv2. AT_CHECK([ovs-vsctl add-port br-int localvif2 -- set Interface localvif2 external_ids:iface-id=localvif2]) # At this point, the broadcast flow on vif2 should be deleted. -# because, there is now a localnet vif bound (table=32 programming logic) -OVS_WAIT_UNTIL([test `ovs-ofctl dump-flows br-int table=32 | ofctl_strip | grep output | wc -l` -eq 0]) +# because, there is now a localnet vif bound (table=37 programming logic) +OVS_WAIT_UNTIL([test `ovs-ofctl dump-flows br-int table=37 | ofctl_strip | grep output | wc -l` -eq 0]) # Verify that the local net patch port exists on hv2. OVS_WAIT_UNTIL([test `ovs-vsctl show | grep "Port patch-br-int-to-ln_port" | wc -l` -eq 1]) @@ -10388,12 +10388,12 @@ AT_CAPTURE_FILE([hv2flows]) AT_CHECK( [# Check that redirect mapping is programmed only on hv2 - grep table=33 hv1flows | grep =0x3,metadata=0x1 | wc -l - grep table=33 hv2flows | grep =0x3,metadata=0x1 | grep load:0x2- | wc -l + grep table=38 hv1flows | grep =0x3,metadata=0x1 | wc -l + grep table=38 hv2flows | grep =0x3,metadata=0x1 | grep load:0x2- | wc -l # Check that hv1 sends chassisredirect port traffic to hv2 - grep table=32 hv1flows | grep =0x3,metadata=0x1 | grep output | wc -l - grep table=32 hv2flows | grep =0x3,metadata=0x1 | wc -l + grep table=37 hv1flows | grep =0x3,metadata=0x1 | grep output | wc -l + grep table=37 hv2flows | grep =0x3,metadata=0x1 | wc -l # Check that arp reply on distributed gateway port is only programmed on hv2 grep arp hv1flows | grep load:0x2- | grep =0x2,metadata=0x1 | wc -l @@ -10943,8 +10943,8 @@ as hv3 reset_pcap_file hv3-vif1 hv3/vif1 as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet sleep 2 -# On hv1, table 32 check that no packet goes via the tunnel port -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=32 \ +# On hv1, table 37 check that no packet goes via the tunnel port +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=37 \ | grep "NXM_NX_TUN_ID" | grep -v n_packets=0 | wc -l], [0], [[0 ]]) @@ -11634,20 +11634,20 @@ echo $hv2_gw1_ofport echo $hv2_gw2_ofport echo "--- hv1 ---" -as hv1 ovs-ofctl dump-flows br-int table=32 +as hv1 ovs-ofctl dump-flows br-int table=37 echo "--- hv2 ---" -as hv2 ovs-ofctl dump-flows br-int table=32 +as hv2 ovs-ofctl dump-flows br-int table=37 gw1_chassis=$(fetch_column Chassis _uuid name=gw1) gw2_chassis=$(fetch_column Chassis _uuid name=gw2) -OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=32 | \ +OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \ grep active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport \ | wc -l], [0], [1 ]) -OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=32 | \ +OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \ grep active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport \ | wc -l], [0], [1 ]) @@ -11688,12 +11688,12 @@ wait_for_ports_up check ovn-nbctl --wait=hv sync # we make sure that the hypervisors noticed, and inverted the slave ports -OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=32 | \ +OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \ grep active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport \ | wc -l], [0], [1 ]) -OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=32 | \ +OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \ grep active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport \ | wc -l], [0], [1 ]) @@ -11846,12 +11846,12 @@ ovn-nbctl set Logical_Router_Port outside ha_chassis_group=$hagrp1_uuid wait_row_count HA_Chassis_Group 1 wait_row_count HA_Chassis 2 -OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=32 | \ +OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \ grep active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport \ | wc -l], [0], [1 ]) -OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=32 | \ +OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \ grep active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport \ | wc -l], [0], [1 ]) @@ -11903,12 +11903,12 @@ wait_column "$exp_ref_ch_list" HA_Chassis_Group ref_chassis # Increase the priority of gw2 ovn-nbctl --wait=sb ha-chassis-group-add-chassis hagrp1 gw2 40 -OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=32 | \ +OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \ grep active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport \ | wc -l], [0], [1 ]) -OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=32 | \ +OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \ grep active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport \ | wc -l], [0], [1 ]) @@ -15352,7 +15352,7 @@ wait_for_ports_up ls1-lp_ext1 # There should be a flow in hv2 to drop traffic from ls1-lp_ext1 destined # to router mac. AT_CHECK([as hv2 ovs-ofctl dump-flows br-int \ -table=28,dl_src=f0:00:00:00:00:03,dl_dst=a0:10:00:00:00:01 | \ +table=30,dl_src=f0:00:00:00:00:03,dl_dst=a0:10:00:00:00:01 | \ grep -c "actions=drop"], [0], [1 ]) @@ -15950,6 +15950,7 @@ ovn-nbctl lsp-add sw1 rp-sw1 -- set Logical_Switch_Port rp-sw1 \ ovn-nbctl lsp-add sw0 sw0-p0 \ -- lsp-set-addresses sw0-p0 "f0:00:00:01:02:03 192.168.1.2 2001::2" + ovn-nbctl lsp-add sw0 sw0-p1 \ -- lsp-set-addresses sw0-p1 "f0:00:00:11:02:03 192.168.1.3 2001::3" @@ -16015,7 +16016,7 @@ policy=$(fetch_column nb:Logical_Router_Policy _uuid priority=2000) check ovn-nbctl set logical_router_policy $policy options:pkt_mark=100 as hv2 # add a flow in egress pipeline to check pkt marking -ovs-ofctl --protocols=OpenFlow13 add-flow br-int "table=32,priority=200,ip,nw_src=172.16.1.2,pkt_mark=0x64 actions=resubmit(,33)" +ovs-ofctl --protocols=OpenFlow13 add-flow br-int "table=37,priority=200,ip,nw_src=172.16.1.2,pkt_mark=0x64 actions=resubmit(,38)" dst_ip=$(ip_to_hex 172 16 2 10) fip_ip=$(ip_to_hex 172 16 1 2) @@ -16027,7 +16028,7 @@ echo $(get_arp_req f00000010204 $fip_ip $gw_router_ip) >> expected send_arp_reply 2 1 $gw_router_mac f00000010204 $gw_router_ip $fip_ip echo "${gw_router_mac}f0000001020408004500001c00004000fe0121b4${fip_ip}${dst_ip}${data}" >> expected -AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=32 | grep pkt_mark=0x64 | grep -q n_packets=1],[0]) +AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=37 | grep pkt_mark=0x64 | grep -q n_packets=1],[0]) OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) @@ -19016,7 +19017,7 @@ m4_define([DVR_N_S_PING], OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv4/vif-north-tx.pcap], [vif-north.expected]) # Confirm that packets did not go out via tunnel port. - AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep table=33 | grep NXM_NX_TUN_METADATA0 | grep n_packets=0 | wc -l], [0], [[0 + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep table=38 | grep NXM_NX_TUN_METADATA0 | grep n_packets=0 | wc -l], [0], [[0 ]]) # Confirm that packet went out via localnet port @@ -19146,7 +19147,8 @@ list mac_binding], [0], [lr0-sw0 50:54:00:00:00:03 ]) -AT_CHECK([test 1 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | wc -l`]) +AT_CHECK([test 1 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | \ +grep table_id=10 | wc -l`]) AT_CHECK([test 1 = `as hv1 ovs-ofctl dump-flows br-int table=10 | grep arp | \ grep controller | grep -v n_packets=0 | wc -l`]) @@ -19163,7 +19165,8 @@ OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int table=67 | grep n_p # The packet should not be sent to ovn-controller. The packet # count should be 1 only. -AT_CHECK([test 1 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | wc -l`]) +AT_CHECK([test 1 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | \ +grep table_id=10 | wc -l`]) AT_CHECK([test 1 = `as hv1 ovs-ofctl dump-flows br-int table=10 | grep arp | \ grep controller | grep -v n_packets=0 | wc -l`]) @@ -19176,7 +19179,8 @@ send_garp 1 1 $eth_src $eth_dst $spa $tpa # The garp packet should be sent to ovn-controller and the mac_binding entry # should be updated. -OVS_WAIT_UNTIL([test 2 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | wc -l`]) +OVS_WAIT_UNTIL([test 2 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | \ +grep table_id=10 | wc -l`]) check_row_count MAC_Binding 1 @@ -19201,7 +19205,8 @@ send_garp 1 1 $eth_src $eth_dst $spa $tpa # The garp packet should be sent to ovn-controller and the mac_binding entry # should be updated. -OVS_WAIT_UNTIL([test 3 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | wc -l`]) +OVS_WAIT_UNTIL([test 3 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | \ +grep table_id=10 | wc -l`]) OVS_WAIT_UNTIL( [test 1 = `as hv1 ovs-ofctl dump-flows br-int table=67 | grep dl_src=50:54:00:00:00:33 \ @@ -19222,7 +19227,8 @@ OVS_WAIT_UNTIL( | grep n_packets=1 | wc -l`] ) -AT_CHECK([test 3 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | wc -l`]) +AT_CHECK([test 3 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | \ +grep table_id=10 | wc -l`]) # Now send ARP reply packet with IP - 10.0.0.40 and mac 505400000023 eth_src=505400000023 @@ -19239,7 +19245,8 @@ send_arp_reply 1 1 $eth_src $eth_dst $spa $tpa # The garp packet should be sent to ovn-controller and the mac_binding entry # should be updated. -OVS_WAIT_UNTIL([test 4 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | wc -l`]) +OVS_WAIT_UNTIL([test 4 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | \ +grep table_id=10 | wc -l`]) # Wait for an entry in table=67 for the learnt mac_binding entry. @@ -19255,7 +19262,8 @@ OVS_WAIT_UNTIL( | grep n_packets=1 | wc -l`] ) -AT_CHECK([test 4 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | wc -l`]) +AT_CHECK([test 4 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | \ +grep table_id=10 | wc -l`]) send_arp_reply 1 1 $eth_src $eth_dst $spa $tpa OVS_WAIT_UNTIL( @@ -19263,7 +19271,8 @@ OVS_WAIT_UNTIL( | grep n_packets=2 | wc -l`] ) -AT_CHECK([test 4 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | wc -l`]) +AT_CHECK([test 4 = `cat hv1/ovn-controller.log | grep NXT_PACKET_IN2 | \ +grep table_id=10 | wc -l`]) OVN_CLEANUP([hv1], [hv2]) AT_CLEANUP @@ -21882,22 +21891,22 @@ AT_CHECK([test ! -z $p1_zoneid]) p2_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p2 | sed 's/"//g') AT_CHECK([test ! -z $p2_zoneid]) -AT_CHECK([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw0_dpkey},\ +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\ reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 1]) -AT_CHECK([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw0_dpkey},\ +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\ reg15=0x${p1_dpkey} | grep "load:0x${p1_zoneid}->NXM_NX_REG13" | wc -l) -eq 1]) -AT_CHECK([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw1_dpkey},\ +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw1_dpkey},\ reg15=0x${p2_dpkey} | grep REG13 | wc -l) -eq 1]) -AT_CHECK([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw1_dpkey},\ +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw1_dpkey},\ reg15=0x${p2_dpkey} | grep "load:0x${p2_zoneid}->NXM_NX_REG13" | wc -l) -eq 1]) ovs-vsctl set interface hv1-vif1 external_ids:iface-id=foo OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw0-p1) = xdown]) -AT_CHECK([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw0_dpkey},\ +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\ reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 0]) p1_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p1 | sed 's/"//g') @@ -21909,16 +21918,16 @@ OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw0-p1) = xup]) p1_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p1 | sed 's/"//g') AT_CHECK([test ! -z $p1_zoneid]) -AT_CHECK([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw0_dpkey},\ +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\ reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 1]) -AT_CHECK([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw0_dpkey},\ +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\ reg15=0x${p1_dpkey} | grep "load:0x${p1_zoneid}->NXM_NX_REG13" | wc -l) -eq 1]) ovs-vsctl del-port hv1-vif2 OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw0-p2) = xdown]) -AT_CHECK([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw0_dpkey},\ +AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\ reg15=0x${p2_dpkey} | grep REG13 | wc -l) -eq 0]) p2_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p2 | sed 's/"//g') @@ -21926,7 +21935,7 @@ AT_CHECK([test -z $p2_zoneid]) ovn-nbctl lsp-del sw0-p1 -OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int table=33,metadata=${sw0_dpkey},\ +OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\ reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 0]) p1_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p1 | sed 's/"//g') @@ -22510,7 +22519,8 @@ ovn-nbctl lsp-add s1 lsp-s1-r1 -- set Logical_Switch_Port lsp-s1-r1 type=router # Create logical port p1 in s1 ovn-nbctl lsp-add s1 p1 \ --- lsp-set-addresses p1 "f0:00:00:00:01:02 10.0.1.2" +-- lsp-set-addresses p1 "f0:00:00:00:01:02 10.0.1.2" \ +-- lsp-set-port-security p1 "f0:00:00:00:01:02 10.0.1.2" # Create two hypervisor and create OVS ports corresponding to logical ports. net_add n1 @@ -24003,3 +24013,426 @@ wait_column "true" nb:Logical_Switch_Port up name=lsp1 OVN_CLEANUP([hv1]) AT_CLEANUP + +AT_SETUP([ovn -- OVN FDB (MAC learning) - 2 HVs, 2 LS, 1 LR ]) +ovn_start + +# Create the first logical switch with one port +check ovn-nbctl ls-add sw0 +check ovn-nbctl lsp-add sw0 sw0-p1 +check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3" unknown + +check ovn-nbctl lsp-add sw0 sw0-p2 +check ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4" +# Port security is set for sw0-p2 +check ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4" + +# sw0-p1 and sw0-p3 have unknown address and no port security. +# FDB should be enabled for these lports. +check ovn-nbctl lsp-add sw0 sw0-p3 +check ovn-nbctl lsp-set-addresses sw0-p3 unknown + +# Create the second logical switch with one port +check ovn-nbctl ls-add sw1 +check ovn-nbctl lsp-add sw1 sw1-p1 +check ovn-nbctl lsp-set-addresses sw1-p1 "40:54:00:00:00:03 11.0.0.3" unknown + +check ovn-nbctl lsp-add sw1 sw1-p2 +check ovn-nbctl lsp-set-addresses sw1-p2 "40:54:00:00:00:04 11.0.0.4" +check ovn-nbctl lsp-set-port-security sw1-p2 "40:54:00:00:00:04 11.0.0.4" + +# Create a logical router and attach both logical switches +check ovn-nbctl lr-add lr0 +check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 +check ovn-nbctl lsp-add sw0 sw0-lr0 +check ovn-nbctl lsp-set-type sw0-lr0 router +check ovn-nbctl lsp-set-addresses sw0-lr0 router +check ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 + +check ovn-nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 11.0.0.1/24 +check ovn-nbctl lsp-add sw1 sw1-lr0 +check ovn-nbctl lsp-set-type sw1-lr0 router +check ovn-nbctl lsp-set-addresses sw1-lr0 router +check ovn-nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 +ovn-nbctl --wait=hv sync + +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=sw0-p1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 +ovs-vsctl -- add-port br-int hv1-vif2 -- \ + set interface hv1-vif2 external-ids:iface-id=sw1-p2 \ + options:tx_pcap=hv1/vif2-tx.pcap \ + options:rxq_pcap=hv1/vif2-rx.pcap \ + ofport-request=2 +ovs-vsctl -- add-port br-int hv1-vif3 -- \ + set interface hv1-vif3 external-ids:iface-id=sw0-p3 \ + options:tx_pcap=hv1/vif3-tx.pcap \ + options:rxq_pcap=hv1/vif3-rx.pcap \ + ofport-request=3 + +sim_add hv2 +as hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=sw0-p2 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 +ovs-vsctl -- add-port br-int hv2-vif2 -- \ + set interface hv2-vif2 external-ids:iface-id=sw1-p1 \ + options:tx_pcap=hv2/vif2-tx.pcap \ + options:rxq_pcap=hv2/vif2-rx.pcap \ + ofport-request=2 + +OVN_POPULATE_ARP + +ip_to_hex() { + printf "%02x%02x%02x%02x" "$@" +} + +send_icmp_packet() { + local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ipv4_dst=$6 ip_chksum=$7 data=$8 + shift 8 + + local ip_ttl=ff + local ip_len=001c + local packet=${eth_dst}${eth_src}08004500${ip_len}00004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}${data} + echo $packet > expected + as hv$hv ovs-appctl netdev-dummy/receive hv$hv-vif$inport $packet +} + +reset_pcap_file() { + local iface=$1 + local pcap_file=$2 + ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \ +options:rxq_pcap=dummy-rx.pcap + rm -f ${pcap_file}*.pcap + ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \ +options:rxq_pcap=${pcap_file}-rx.pcap +} + +trim_zeros() { + sed 's/\(00\)\{1,\}$//' +} + +AS_BOX([Wait for all ports to be up]) +wait_for_ports_up + +# Check that there is put_fdb() flow added by ovn-northd for sw0-p1 +ovn-sbctl dump-flows sw0 > sw0flows +AT_CAPTURE_FILE([sw0flows]) + +AT_CHECK([grep "ls_in_lookup_fdb" sw0flows | sort], [0], [dnl + table=3 (ls_in_lookup_fdb ), priority=0 , dnl +match=(1), action=(next;) + table=3 (ls_in_lookup_fdb ), priority=100 , dnl +match=(inport == "sw0-p1"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) + table=3 (ls_in_lookup_fdb ), priority=100 , dnl +match=(inport == "sw0-p3"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) +]) + +AT_CHECK([grep "ls_in_put_fdb" sw0flows | sort], [0], [dnl + table=4 (ls_in_put_fdb ), priority=0 , dnl +match=(1), action=(next;) + table=4 (ls_in_put_fdb ), priority=100 , dnl +match=(inport == "sw0-p1" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) + table=4 (ls_in_put_fdb ), priority=100 , dnl +match=(inport == "sw0-p3" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) +]) + +# Send a packet from sw0-p1 with a different mac not present +# in it's addresses. +AS_BOX([Send a pkt from sw0-p1 with a different mac address]) + +# Use the src mac 50:54:00:00:00:13 instead of 50:54:00:00:00:03 +src_mac=505400000013 +src_ip=$(ip_to_hex 10 0 0 13) + +# send the packet to sw0-p2 +dst_mac=505400000004 +dst_ip=$(ip_to_hex 10 0 0 4) + +data=0800bee4391a0001 +send_icmp_packet 1 1 $src_mac $dst_mac $src_ip $dst_ip 0000 $data +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +# There should be one row in fdb +AS_BOX([Check that the FDB entry is created]) +wait_row_count FDB 1 + +sw0_dpkey=$(fetch_column datapath_binding tunnel_key external_ids:name=sw0) +sw0p1_dpkey=$(fetch_column port_binding tunnel_key logical_port=sw0-p1) +sw0p3_dpkey=$(fetch_column port_binding tunnel_key logical_port=sw0-p3) + +check_column '50:54:00:00:00:13' fdb mac +check_column $sw0_dpkey fdb dp_key +check_column $sw0p1_dpkey fdb port_key + +# Make sure that OVS tables 71 and 72 are populated on both hv1 and hv2. +AS_BOX([Check that ovn-controller programs the flows for FDB]) +as hv1 ovs-ofctl dump-flows br-int table=71 > hv1_offlows_table71.txt +as hv2 ovs-ofctl dump-flows br-int table=71 > hv2_offlows_table71.txt + +AT_CAPTURE_FILE([hv1_offlows_table71.txt]) +AT_CAPTURE_FILE([hv2_offlows_table71.txt]) +AT_CHECK([cat hv1_offlows_table71.txt | grep -v NXST | cut -d ' ' -f8- | sort], [0], [dnl +priority=100,metadata=0x1,dl_dst=50:54:00:00:00:13 actions=load:0x1->NXM_NX_REG15[[]] +]) + +AT_CHECK([cat hv2_offlows_table71.txt | grep -v NXST | cut -d ' ' -f8- | sort], [0], [dnl +priority=100,metadata=0x1,dl_dst=50:54:00:00:00:13 actions=load:0x1->NXM_NX_REG15[[]] +]) + +as hv1 ovs-ofctl dump-flows br-int table=72 > hv1_offlows_table72.txt +as hv2 ovs-ofctl dump-flows br-int table=72 > hv2_offlows_table72.txt + +AT_CAPTURE_FILE([hv1_offlows_table72.txt]) +AT_CAPTURE_FILE([hv2_offlows_table72.txt]) +AT_CHECK([cat hv1_offlows_table72.txt | grep -v NXST | cut -d ' ' -f8- | sort], [0], [dnl +priority=100,reg14=0x1,metadata=0x1,dl_src=50:54:00:00:00:13 actions=load:0x1->NXM_NX_REG10[[8]] +]) + +AT_CHECK([cat hv2_offlows_table72.txt | grep -v NXST | cut -d ' ' -f8- | sort], [0], [dnl +priority=100,reg14=0x1,metadata=0x1,dl_src=50:54:00:00:00:13 actions=load:0x1->NXM_NX_REG10[[8]] +]) + +# Use the src mac 50:54:00:00:00:14 instead of 50:54:00:00:00:03 +src_mac=505400000014 +src_ip=$(ip_to_hex 10 0 0 14) + +as hv2 reset_pcap_file hv2-vif1 hv2/vif1 + +send_icmp_packet 1 1 $src_mac $dst_mac $src_ip $dst_ip 0000 $data +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +# There should be two rows in fdb +wait_row_count FDB 2 + +check_column "50:54:00:00:00:13 50:54:00:00:00:14" fdb mac +check_column "$sw0_dpkey $sw0_dpkey" fdb dp_key +check_column "$sw0p1_dpkey $sw0p1_dpkey" fdb port_key + +# Make sure that OVS tables 71 and 72 are populated on both hv1 and hv2. +as hv1 ovs-ofctl dump-flows br-int table=71 > hv1_offlows_table71.txt +as hv2 ovs-ofctl dump-flows br-int table=71 > hv2_offlows_table71.txt + +AT_CAPTURE_FILE([hv1_offlows_table71.txt]) +AT_CAPTURE_FILE([hv2_offlows_table71.txt]) +AT_CHECK([cat hv1_offlows_table71.txt | grep -v NXST | cut -d ' ' -f8- | sort], [0], [dnl +priority=100,metadata=0x1,dl_dst=50:54:00:00:00:13 actions=load:0x1->NXM_NX_REG15[[]] +priority=100,metadata=0x1,dl_dst=50:54:00:00:00:14 actions=load:0x1->NXM_NX_REG15[[]] +]) + +AT_CHECK([cat hv2_offlows_table71.txt | grep -v NXST | cut -d ' ' -f8- | sort], [0], [dnl +priority=100,metadata=0x1,dl_dst=50:54:00:00:00:13 actions=load:0x1->NXM_NX_REG15[[]] +priority=100,metadata=0x1,dl_dst=50:54:00:00:00:14 actions=load:0x1->NXM_NX_REG15[[]] +]) + +as hv1 ovs-ofctl dump-flows br-int table=72 > hv1_offlows_table72.txt +as hv2 ovs-ofctl dump-flows br-int table=72 > hv2_offlows_table72.txt + +AT_CAPTURE_FILE([hv1_offlows_table72.txt]) +AT_CAPTURE_FILE([hv2_offlows_table72.txt]) +AT_CHECK([cat hv1_offlows_table72.txt | grep -v NXST | cut -d ' ' -f8- | sort], [0], [dnl +priority=100,reg14=0x1,metadata=0x1,dl_src=50:54:00:00:00:13 actions=load:0x1->NXM_NX_REG10[[8]] +priority=100,reg14=0x1,metadata=0x1,dl_src=50:54:00:00:00:14 actions=load:0x1->NXM_NX_REG10[[8]] +]) + +AT_CHECK([cat hv2_offlows_table72.txt | grep -v NXST | cut -d ' ' -f8- | sort], [0], [dnl +priority=100,reg14=0x1,metadata=0x1,dl_src=50:54:00:00:00:13 actions=load:0x1->NXM_NX_REG10[[8]] +priority=100,reg14=0x1,metadata=0x1,dl_src=50:54:00:00:00:14 actions=load:0x1->NXM_NX_REG10[[8]] +]) + +as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +as hv2 reset_pcap_file hv2-vif1 hv2/vif1 + +# Send the packet from sw0-p2 to sw0-p1 with the dst mac 50:54:00:00:00:13 +src_mac=505400000004 +src_ip=$(ip_to_hex 10 0 0 4) + +dst_mac=505400000013 +dst_ip=$(ip_to_hex 10 0 0 13) + +send_icmp_packet 1 2 $src_mac $dst_mac $src_ip $dst_ip 0000 $data +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected]) + +as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +dst_mac=505400000014 +dst_ip=$(ip_to_hex 10 0 0 14) + +send_icmp_packet 1 2 $src_mac $dst_mac $src_ip $dst_ip 0000 $data +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected]) + +as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +as hv1 reset_pcap_file hv1-vif3 hv1/vif3 + +# Send a packet from sw0-p2 to an unknown mac. Should be received +# by both sw0-p1 and sw0-p3 (as unknown is set). +AS_BOX([Send pkt from sw0-p2 to an unknown mac]) + +src_mac=505400000004 +src_ip=$(ip_to_hex 10 0 0 4) + +dst_mac=505400000023 +dst_ip=$(ip_to_hex 10 0 0 23) + +send_icmp_packet 1 2 $src_mac $dst_mac $src_ip $dst_ip 0000 $data + +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected]) +OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected]) + +AS_BOX([Flip the mac - 50:54:00:00:00:13 from sw0-p1 to sw0-p3]) + +# Use the src mac 50:54:00:00:00:13 +src_mac=505400000013 +src_ip=$(ip_to_hex 10 0 0 23) + +# send the packet to sw0-p2 +dst_mac=505400000004 +dst_ip=$(ip_to_hex 10 0 0 4) + +data=0800bee4391a0001 + +as hv2 reset_pcap_file hv2-vif1 hv2/vif1 +as hv1 reset_pcap_file hv1-vif3 hv1/vif3 + +# Send the pkt from sw0-p3 to sw0-p2. +send_icmp_packet 3 1 $src_mac $dst_mac $src_ip $dst_ip 0000 $data +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +# fdb row count should be still 2. But the mac 50:54:00:00:00:13 +# should be learnt on sw0-p3. + +wait_row_count FDB 2 + +check_column "50:54:00:00:00:13 50:54:00:00:00:14" fdb mac +check_column "$sw0_dpkey $sw0_dpkey" fdb dp_key +check_column "$sw0p1_dpkey $sw0p3_dpkey" fdb port_key + +check_column "$sw0p3_dpkey" fdb port_key mac="50\:54\:00\:00\:00\:13" + +as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +as hv1 reset_pcap_file hv1-vif3 hv1/vif3 + +# Send the packet from sw0-p2 to sw0-p3 with the dst mac 50:54:00:00:00:13 +src_mac=505400000004 +src_ip=$(ip_to_hex 10 0 0 4) + +dst_mac=505400000013 +dst_ip=$(ip_to_hex 10 0 0 13) + +send_icmp_packet 1 2 $src_mac $dst_mac $src_ip $dst_ip 0000 $data +OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected]) + +# sw0-p1 should not receive the packet. +: > expected +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected]) + +AS_BOX([Test routing]) + +# Test the routing. +# Send the packet from sw1-p2 (hv1) to sw0-p1 (hv1) with dst ip 10.0.0.14 +# The packet should be delivered to sw0-p1 with dst mac 50:54:00:00:00:14 +# Before sending add mac_binding entry for 10.0.0.14 + +lr0_dp_uuid=$(fetch_column datapath_binding _uuid external_ids:name=lr0) + +ovn-sbctl create mac_binding ip=10.0.0.14 logical_port=lr0-sw0 \ +mac="50\:54\:00\:00\:00\:14" datapath=$lr0_dp_uuid + +# Wait till the mac_binding flows appear in hv1 +OVS_WAIT_UNTIL([test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=66 \ +| grep -c reg0=0xa00000e)]) + +src_mac=405400000004 +src_ip=$(ip_to_hex 11 0 0 4) + +dst_mac=00000000ff02 # lr0-sw1 mac +dst_ip=$(ip_to_hex 10 0 0 14) + +as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +as hv1 reset_pcap_file hv1-vif3 hv1/vif3 + +send_icmp_packet 2 1 $src_mac $dst_mac $src_ip $dst_ip 0000 $data + +exp_packet=50540000001400000000ff0108004500001c00004000fe010100${src_ip}${dst_ip}${data} +echo $exp_packet > expected +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected]) + +# sw0-p3 should not receive the packet. +: > expected +OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected]) + +# Now the send the packet from sw1-p1 (hv2) to sw0-p1 (hv1) with dst ip 10.0.0.14 +# The acket should be delivered to sw0-p1 with dst mac 50:54:00:00:00:14 + +src_mac=405400000003 +src_ip=$(ip_to_hex 11 0 0 3) + +dst_mac=00000000ff02 # lr0-sw1 mac +dst_ip=$(ip_to_hex 10 0 0 14) + +as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +send_icmp_packet 2 2 $src_mac $dst_mac $src_ip $dst_ip 0000 $data + +exp_packet=50540000001400000000ff0108004500001c00004000fe010100${src_ip}${dst_ip}${data} +echo $exp_packet > expected +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected]) + +AS_BOX([Clear the FDB rows]) + +# Clear the fdb rows. +check ovn-sbctl --all destroy fdb +ovn-sbctl list fdb + +as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +as hv1 reset_pcap_file hv1-vif3 hv1/vif3 + +# Send the packet from sw0-p2 to sw0-p1 with the dst mac 50:54:00:00:00:14 +# It should be delivered to both sw0-p1 and sw0-p3 since we have cleared the +# FDB table. +src_mac=505400000004 +src_ip=$(ip_to_hex 10 0 0 4) + +dst_mac=505400000014 +dst_ip=$(ip_to_hex 10 0 0 13) + +send_icmp_packet 1 2 $src_mac $dst_mac $src_ip $dst_ip 0000 $data + +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected]) +OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [expected]) + +# Make sure that OVS tables 71 and 72 are empty. +as hv1 ovs-ofctl dump-flows br-int table=71 > hv1_offlows_table71.txt +as hv2 ovs-ofctl dump-flows br-int table=71 > hv2_offlows_table71.txt + +AT_CAPTURE_FILE([hv1_offlows_table71.txt]) +AT_CAPTURE_FILE([hv2_offlows_table71.txt]) +AT_CHECK([cat hv1_offlows_table71.txt | grep -v NXST], [1], [dnl +]) + +AT_CHECK([cat hv2_offlows_table71.txt | grep -v NXST], [1], [dnl +]) + +as hv1 ovs-ofctl dump-flows br-int table=72 > hv1_offlows_table72.txt +as hv2 ovs-ofctl dump-flows br-int table=72 > hv2_offlows_table72.txt + +AT_CAPTURE_FILE([hv1_offlows_table72.txt]) +AT_CAPTURE_FILE([hv2_offlows_table72.txt]) +AT_CHECK([cat hv1_offlows_table72.txt | grep -v NXST], [1], [dnl +]) + +AT_CHECK([cat hv2_offlows_table72.txt | grep -v NXST], [1], [dnl +]) + +OVN_CLEANUP([hv1], [hv2]) +AT_CLEANUP diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index fead759b49..6b883886fb 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -945,7 +945,7 @@ parse_lflow_for_datapath(const struct sbrec_logical_flow *sblf, .pipeline = (!strcmp(sblf->pipeline, "ingress") ? OVNACT_P_INGRESS : OVNACT_P_EGRESS), - .n_tables = 24, + .n_tables = LOG_PIPELINE_LEN, .cur_ltable = sblf->table_id, }; uint64_t stub[1024 / 8]; @@ -1184,6 +1184,11 @@ ovntrace_lookup_port(const void *dp_, const char *port_name, return true; } + if (!strcmp(port_name, "none")) { + *portp = 0; + return true; + } + const struct ovntrace_port *port = ovntrace_port_lookup_by_name(port_name); if (port) { if (port->dp == dp) { From patchwork Fri Feb 5 07:00:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1436464 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=) 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 4DX5t92lp8z9sWg for ; Fri, 5 Feb 2021 18:01:05 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id D00A12E105; Fri, 5 Feb 2021 07:01:03 +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 ER6hHl+qGhS7; Fri, 5 Feb 2021 07:00:54 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id A02C22E10B; Fri, 5 Feb 2021 07:00:45 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 83EC2C08A1; Fri, 5 Feb 2021 07:00:45 +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 47BA8C0174 for ; Fri, 5 Feb 2021 07:00:44 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 37D2E872BD for ; Fri, 5 Feb 2021 07:00:44 +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 eANaAo877weg for ; Fri, 5 Feb 2021 07:00:43 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) by hemlock.osuosl.org (Postfix) with ESMTPS id AE86D872EF for ; Fri, 5 Feb 2021 07:00:42 +0000 (UTC) X-Originating-IP: 115.99.223.251 Received: from nusiddiq.home.org.com (unknown [115.99.223.251]) (Authenticated sender: numans@ovn.org) by relay7-d.mail.gandi.net (Postfix) with ESMTPSA id 151102000A; Fri, 5 Feb 2021 07:00:37 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Fri, 5 Feb 2021 12:30:33 +0530 Message-Id: <20210205070033.40429-1-numans@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210205065622.39226-1-numans@ovn.org> References: <20210205065622.39226-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 6/6] northd: Cleanup stale FDB entries. 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: Numan Siddique Signed-off-by: Numan Siddique --- lib/ovn-util.c | 20 ++++++++++++--- lib/ovn-util.h | 1 + northd/ovn-northd.c | 40 ++++++++++++++++++++++++++++++ tests/ovn-northd.at | 60 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 4 deletions(-) diff --git a/lib/ovn-util.c b/lib/ovn-util.c index b6471063ef..8f6719471d 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -580,18 +580,30 @@ ovn_destroy_tnlids(struct hmap *tnlids) hmap_destroy(tnlids); } +/* Returns true if 'tnlid' is present in the hmap 'tnlids'. */ bool -ovn_add_tnlid(struct hmap *set, uint32_t tnlid) +ovn_tnlid_present(struct hmap *tnlids, uint32_t tnlid) { uint32_t hash = hash_int(tnlid, 0); struct tnlid_node *node; - HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash, set) { + HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash, tnlids) { if (node->tnlid == tnlid) { - return false; + return true; } } - node = xmalloc(sizeof *node); + return false; +} + +bool +ovn_add_tnlid(struct hmap *set, uint32_t tnlid) +{ + if (ovn_tnlid_present(set, tnlid)) { + return false; + } + + uint32_t hash = hash_int(tnlid, 0); + struct tnlid_node *node = xmalloc(sizeof *node); hmap_insert(set, &node->hmap_node, hash); node->tnlid = tnlid; return true; diff --git a/lib/ovn-util.h b/lib/ovn-util.h index df4b0bc989..40ecafe57e 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -126,6 +126,7 @@ void ovn_conn_show(struct unixctl_conn *conn, int argc OVS_UNUSED, struct hmap; void ovn_destroy_tnlids(struct hmap *tnlids); bool ovn_add_tnlid(struct hmap *set, uint32_t tnlid); +bool ovn_tnlid_present(struct hmap *tnlids, uint32_t tnlid); uint32_t ovn_allocate_tnlid(struct hmap *set, const char *name, uint32_t min, uint32_t max, uint32_t *hint); diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 23c26de36f..7b6f86802a 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -851,6 +851,20 @@ ovn_datapath_find(struct hmap *datapaths, const struct uuid *uuid) return NULL; } +static struct ovn_datapath * +ovn_datapath_find_by_key(struct hmap *datapaths, uint32_t dp_key) +{ + struct ovn_datapath *od; + + HMAP_FOR_EACH (od, key_node, datapaths) { + if (od->tunnel_key == dp_key) { + return od; + } + } + + return NULL; +} + static bool ovn_datapath_is_stale(const struct ovn_datapath *od) { @@ -3144,6 +3158,26 @@ cleanup_sb_ha_chassis_groups(struct northd_context *ctx, } } +static void +cleanup_stale_fdp_entries(struct northd_context *ctx, struct hmap *datapaths) +{ + const struct sbrec_fdb *fdb_e, *next; + SBREC_FDB_FOR_EACH_SAFE (fdb_e, next, ctx->ovnsb_idl) { + bool delete = true; + struct ovn_datapath *od + = ovn_datapath_find_by_key(datapaths, fdb_e->dp_key); + if (od) { + if (ovn_tnlid_present(&od->port_tnlids, fdb_e->port_key)) { + delete = false; + } + } + + if (delete) { + sbrec_fdb_delete(fdb_e); + } + } +} + struct service_monitor_info { struct hmap_node hmap_node; const struct sbrec_service_monitor *sbrec_mon; @@ -12714,6 +12748,7 @@ ovnnb_db_run(struct northd_context *ctx, sync_port_groups(ctx, &port_groups); sync_meters(ctx, datapaths, &meter_groups, &port_groups); sync_dns_entries(ctx, datapaths); + cleanup_stale_fdp_entries(ctx, datapaths); struct ovn_northd_lb *lb; HMAP_FOR_EACH_POP (lb, hmap_node, &lbs) { @@ -13701,6 +13736,11 @@ main(int argc, char *argv[]) ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_disc); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_src_port); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_fdb); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_mac); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_dp_key); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_port_key); + struct ovsdb_idl_index *sbrec_chassis_by_name = chassis_index_create(ovnsb_idl_loop.idl); diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 1b4160cfa0..76634043cc 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -2443,3 +2443,63 @@ check ovn-sbctl set chassis hv1 other_config:port-up-notif=true wait_row_count nb:Logical_Switch_Port 1 up=false name=lsp1 AT_CLEANUP + +AT_SETUP([ovn -- FDB cleanup]) + +ovn_start + +ovn-nbctl ls-add sw0 +ovn-nbctl lsp-add sw0 sw0-p1 +ovn-nbctl lsp-add sw0 sw0-p2 +ovn-nbctl lsp-add sw0 sw0-p3 + +ovn-nbctl ls-add sw1 +ovn-nbctl lsp-add sw1 sw1-p1 +ovn-nbctl lsp-add sw1 sw1-p2 +ovn-nbctl --wait=sb lsp-add sw1 sw1-p3 + +sw0_key=$(fetch_column datapath_binding tunnel_key external_ids:name=sw0) +sw1_key=$(fetch_column datapath_binding tunnel_key external_ids:name=sw1) +sw0p1_key=$(fetch_column port_binding tunnel_key logical_port=sw0-p1) +sw0p2_key=$(fetch_column port_binding tunnel_key logical_port=sw0-p2) +sw1p1_key=$(fetch_column port_binding tunnel_key logical_port=sw1-p1) + +ovn-sbctl create FDB mac="00\:00\:00\:00\:00\:01" dp_key=$sw0_key port_key=$sw0p1_key +ovn-sbctl create FDB mac="00\:00\:00\:00\:00\:02" dp_key=$sw0_key port_key=$sw0p1_key +ovn-sbctl create FDB mac="00\:00\:00\:00\:00\:03" dp_key=$sw0_key port_key=$sw0p2_key +ovn-sbctl create FDB mac="00\:00\:00\:00\:01\:01" dp_key=$sw1_key port_key=$sw1p1_key +ovn-sbctl create FDB mac="00\:00\:00\:00\:01\:02" dp_key=$sw1_key port_key=$sw1p1_key +ovn-sbctl create FDB mac="00\:00\:00\:00\:01\:03" dp_key=$sw1_key port_key=$sw1p1_key + +wait_row_count FDB 6 + +ovn-sbctl create fdb mac="00\:00\:00\:00\:01\:03" dp_key=$sw1_key port_key=10 +wait_row_count FDB 6 +ovn-sbctl create fdb mac="00\:00\:00\:00\:01\:03" dp_key=4 port_key=10 +wait_row_count FDB 6 + +ovn-nbctl --wait=sb ls-del sw1 +wait_row_count FDB 3 + +ovn-nbctl lsp-del sw0-p3 +wait_row_count FDB 3 + +ovn-nbctl lsp-del sw0-p1 +wait_row_count FDB 1 + +check_column '00:00:00:00:00:03' FDB mac +ovn-sbctl list fdb + +check_column $sw0_key FDB dp_key +check_column $sw0p2_key FDB port_key + +ovn-nbctl --wait=sb lsp-add sw0-p1 +wait_row_count FDB 1 + +ovn-nbctl lsp-del sw0-p2 +ovn-nbctl lsp-add sw0-p2 +wait_row_count FDB 0 + +ovn-sbctl list FDB + +AT_CLEANUP