From patchwork Wed Apr 19 15:35:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Alvarez Sanchez X-Patchwork-Id: 752337 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3w7R0B6jqgz9s65 for ; Thu, 20 Apr 2017 01:35:22 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 68D3CBD4; Wed, 19 Apr 2017 15:35:19 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id D854ABCD for ; Wed, 19 Apr 2017 15:35:18 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 1408018A for ; Wed, 19 Apr 2017 15:35:18 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 728178553C for ; Wed, 19 Apr 2017 15:35:17 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 728178553C Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=dalvarez@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 728178553C Received: from devstack.novalocal (unknown [10.16.19.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id 15AC1832A0; Wed, 19 Apr 2017 15:35:17 +0000 (UTC) From: Daniel Alvarez To: dev@openvswitch.org Date: Wed, 19 Apr 2017 15:35:34 +0000 Message-Id: <1492616134-9890-1-git-send-email-dalvarez@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Wed, 19 Apr 2017 15:35:17 +0000 (UTC) X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH] [RFC] localport type support X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch introduces a new type of OVN ports called "localport". These ports will be present in every hypervisor and may have the same IP/MAC addresses. They are not bound to any chassis and traffic to these ports will never go through a tunnel. Its main use case is the metadata API support which relies on a local agent running on every hypervisor and serving metadata to VM's locally. This service is described in detail at [0]. TODO: write a test case for localport ports [0] https://review.openstack.org/#/c/452811/ Signed-off-by: Daniel Alvarez --- ovn/controller/binding.c | 84 +++++++++++++++++++++++++++++++++++++++-------- ovn/controller/physical.c | 6 ++++ ovn/northd/ovn-northd.c | 6 ++-- 3 files changed, 80 insertions(+), 16 deletions(-) diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c index 95e9deb..1eff3d4 100644 --- a/ovn/controller/binding.c +++ b/ovn/controller/binding.c @@ -352,6 +352,43 @@ setup_qos(const char *egress_iface, struct hmap *queue_map) hmap_destroy(&consistent_queues); netdev_close(netdev_phy); } +static bool +set_ovsport_external_ids(struct controller_ctx *ctx, + const struct ovsrec_bridge *bridge, + const struct ovsrec_interface *iface_rec, + const char *key, + const char *value) +{ + if (!ctx->ovs_idl_txn) { + return false; + } + + /* Find the port with this interface and add the key/value pair to its + * external_ids. Assume 1-1 relationship between port and interface. */ + int i; + for (i = 0; i < bridge->n_ports; i++) { + const struct ovsrec_port *port_rec = bridge->ports[i]; + int j; + + if (!strcmp(port_rec->name, bridge->name)) { + continue; + } + + for (j = 0; j < port_rec->n_interfaces; j++) { + if (port_rec->interfaces[j] == iface_rec) { + struct smap new_ids; + smap_clone(&new_ids, &port_rec->external_ids); + smap_replace(&new_ids, key, value); + ovsrec_port_verify_external_ids(port_rec); + ovsrec_port_set_external_ids(port_rec, &new_ids); + smap_destroy(&new_ids); + return true; + } + } + } + return false; +} + static void consider_local_datapath(struct controller_ctx *ctx, @@ -359,6 +396,7 @@ consider_local_datapath(struct controller_ctx *ctx, const struct lport_index *lports, const struct sbrec_chassis *chassis_rec, const struct sbrec_port_binding *binding_rec, + const struct ovsrec_bridge *bridge, struct hmap *qos_map, struct hmap *local_datapaths, struct shash *lport_to_iface, @@ -368,19 +406,37 @@ consider_local_datapath(struct controller_ctx *ctx, = shash_find_data(lport_to_iface, binding_rec->logical_port); bool our_chassis = false; - if (iface_rec - || (binding_rec->parent_port && binding_rec->parent_port[0] && - sset_contains(local_lports, binding_rec->parent_port))) { - if (binding_rec->parent_port && binding_rec->parent_port[0]) { - /* Add child logical port to the set of all local ports. */ - sset_add(local_lports, binding_rec->logical_port); - } - add_local_datapath(ldatapaths, lports, binding_rec->datapath, - false, local_datapaths); - if (iface_rec && qos_map && ctx->ovs_idl_txn) { - get_qos_params(binding_rec, qos_map); + + if (iface_rec && !strcmp(binding_rec->type, "localport")) { + /* Make sure localport external_id is present, otherwise set it + * for both interface and port. This should only happen the first + * time. */ + if (!smap_get(&iface_rec->external_ids, "ovn-localport-port")) { + if (set_ovsport_external_ids(ctx, bridge, iface_rec, + "ovn-localport-port", + binding_rec->logical_port)) { + struct smap new_ids; + smap_clone(&new_ids, &iface_rec->external_ids); + smap_replace(&new_ids, "ovn-localport-port", + binding_rec->logical_port); + ovsrec_interface_verify_external_ids(iface_rec); + ovsrec_interface_set_external_ids(iface_rec, &new_ids); + smap_destroy(&new_ids); + } } - our_chassis = true; + } else if (iface_rec + || (binding_rec->parent_port && binding_rec->parent_port[0] && + sset_contains(local_lports, binding_rec->parent_port))) { + if (binding_rec->parent_port && binding_rec->parent_port[0]) { + /* Add child logical port to the set of all local ports. */ + sset_add(local_lports, binding_rec->logical_port); + } + add_local_datapath(ldatapaths, lports, binding_rec->datapath, + false, local_datapaths); + if (iface_rec && qos_map && ctx->ovs_idl_txn) { + get_qos_params(binding_rec, qos_map); + } + our_chassis = true; } else if (!strcmp(binding_rec->type, "l2gateway")) { const char *chassis_id = smap_get(&binding_rec->options, "l2gateway-chassis"); @@ -468,8 +524,8 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, consider_local_datapath(ctx, ldatapaths, lports, chassis_rec, binding_rec, sset_is_empty(&egress_ifaces) ? NULL : - &qos_map, local_datapaths, &lport_to_iface, - local_lports); + br_int, &qos_map, local_datapaths, + &lport_to_iface, local_lports); } diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c index 0f1aa63..187bff5 100644 --- a/ovn/controller/physical.c +++ b/ovn/controller/physical.c @@ -784,6 +784,8 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, "ovn-localnet-port"); const char *l2gateway = smap_get(&port_rec->external_ids, "ovn-l2gateway-port"); + const char *localport = smap_get(&port_rec->external_ids, + "ovn-localport-port"); for (int j = 0; j < port_rec->n_interfaces; j++) { const struct ovsrec_interface *iface_rec = port_rec->interfaces[j]; @@ -808,6 +810,10 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, /* L2 gateway patch ports can be handled just like VIFs. */ simap_put(&new_localvif_to_ofport, l2gateway, ofport); break; + } else if (localport) { + /* localport ports can be handled just like VIFs. */ + simap_put(&new_localvif_to_ofport, localport, ofport); + break; } else if (chassis_id) { enum chassis_tunnel_type tunnel_type; if (!strcmp(iface_rec->type, "geneve")) { diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 5a2e5ab..09f55c8 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -3166,9 +3166,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, /* * Add ARP/ND reply flows if either the * - port is up or - * - port type is router + * - port type is router or + * - port type is localport */ - if (!lsp_is_up(op->nbsp) && strcmp(op->nbsp->type, "router")) { + if (!lsp_is_up(op->nbsp) && strcmp(op->nbsp->type, "router") && + strcmp(op->nbsp->type, "localport")) { continue; }