From patchwork Sun Dec 4 22:06:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1712106 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=X4pgZ1/E; dkim-atps=neutral Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NQLPB1sdmz23nB for ; Mon, 5 Dec 2022 09:06:36 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 0FEA2409B3; Sun, 4 Dec 2022 22:06:33 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 0FEA2409B3 Authentication-Results: smtp4.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=X4pgZ1/E X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id uv2fjRhlfNyA; Sun, 4 Dec 2022 22:06:28 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 3A20D4092F; Sun, 4 Dec 2022 22:06:27 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 3A20D4092F Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id ED52CC0032; Sun, 4 Dec 2022 22:06:26 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 255BAC002D for ; Sun, 4 Dec 2022 22:06:25 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id EDC3D816F5 for ; Sun, 4 Dec 2022 22:06:24 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org EDC3D816F5 Authentication-Results: smtp1.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=X4pgZ1/E X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id uNqiQNuda_eP for ; Sun, 4 Dec 2022 22:06:23 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org CF63581656 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp1.osuosl.org (Postfix) with ESMTPS id CF63581656 for ; Sun, 4 Dec 2022 22:06:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1670191581; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=cUUf/U2MavFrUwupa1EBBzNqPCBkvmoGDVKTOo2rOYQ=; b=X4pgZ1/EMevSEmapFI2iE6tk/Z3bctosPVWiejTIMZ+uyiHY78gzqVqWxlTCTJ5giFshWG q/g/Z0qkZ47jpBuewNEG23MKeQmvri74yS6tL440AR2zk1ItzU6TYBxVtXvgZUTQgQVNZl CVtL48IpTP/t6t+ms5Z7hywnxelozxE= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-672-wgd6vA4ZMNaT5zpkTXikFg-1; Sun, 04 Dec 2022 17:06:19 -0500 X-MC-Unique: wgd6vA4ZMNaT5zpkTXikFg-1 Received: by mail-wr1-f72.google.com with SMTP id k1-20020adfb341000000b0024215e0f486so1861244wrd.21 for ; Sun, 04 Dec 2022 14:06:19 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=cUUf/U2MavFrUwupa1EBBzNqPCBkvmoGDVKTOo2rOYQ=; b=8HDMSi93vMCxbQKkp7NCho+Zx/2Rru5a6urWOWHziUP/75MqiCL5C7H6FpkWMwy/G/ ol4qiTMFtQnp4ODow08T8KlERmcIbEfL3eBkmqq8OcOGRjJM0m7Nn67I8tkldA9tJwf4 /ewtlUtmYHj1cCfzWzN0gOZmLPPRTmRS3pNt5lmQvSPXHK4tFZhyoSEs+j6b2f8/II48 SJYs0+By/LXVG3trSGz5P7yuQYc9MWFl+kvT2Z7JrpUjP8rSLBgYROf8YTLEcghG0kNB qRZQ3mOVSabJa9ux0aPd0/IWXZeKDsjJNzw8qG4EcpWOVJRwRToLjgVa/CenjeTOdmg4 IGUA== X-Gm-Message-State: ANoB5pk7f1vD25mWE/cfgrSsJNgIQH95MQ8fFPGPgsBLq2Aw50rzOKv0 27zDTPRdlmkaGxp2+efZ6ezd9KgAd+TEFMjrFona/eHVJiq58/vxKsL/asLaEzWifRpZvh6Mr6e dnSLjmBMhTnzwmN3ZyQ0Odfv7rRYxCbd+LqA8DAJimUZwoWxRTGr37nTg9WC/TaCPvR/iBlKPTd qmibIX X-Received: by 2002:a05:6000:50b:b0:235:e82c:ca7d with SMTP id a11-20020a056000050b00b00235e82cca7dmr40181719wrf.92.1670191578008; Sun, 04 Dec 2022 14:06:18 -0800 (PST) X-Google-Smtp-Source: AA0mqf4L3bEN7/XmDL+Kq2oOpihZmqY+nb9ZgR85ZwX8hutwIfXZikIOQJAK7+qY5moDIejvhI2tTA== X-Received: by 2002:a05:6000:50b:b0:235:e82c:ca7d with SMTP id a11-20020a056000050b00b00235e82cca7dmr40181704wrf.92.1670191577518; Sun, 04 Dec 2022 14:06:17 -0800 (PST) Received: from localhost (net-188-216-77-84.cust.vodafonedsl.it. [188.216.77.84]) by smtp.gmail.com with ESMTPSA id o37-20020a05600c512500b003cf5ec79bf9sm17787665wms.40.2022.12.04.14.06.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 04 Dec 2022 14:06:16 -0800 (PST) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Sun, 4 Dec 2022 23:06:03 +0100 Message-Id: <8554da1828dd12b9975158b5322993240b3c75ce.1670191403.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.38.1 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v4 ovn] binding: add the capability to apply QoS for lsp 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" Introduce the capability to apply QoS rules for logical switch ports claimed by ovn-controller. Rely on shash instead of sset for egress_ifaces. Acked-by: Mark Michelson Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2129742 Signed-off-by: Lorenzo Bianconi --- Changes since v3: - fix typo in new system-ovn test Changes since v2: - fix qos configuration restarting ovn-controller Changes since v1: - improve ovs interface lookup - improve system-tests --- controller/binding.c | 155 ++++++++++++++++++++++-------------- controller/binding.h | 5 +- controller/ovn-controller.c | 15 ++-- tests/system-ovn.at | 48 +++++++++++ 4 files changed, 156 insertions(+), 67 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index 5df62baef..53520263c 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -115,6 +115,7 @@ struct qos_queue { uint32_t min_rate; uint32_t max_rate; uint32_t burst; + char *port_name; }; void @@ -147,25 +148,50 @@ static void update_lport_tracking(const struct sbrec_port_binding *pb, struct hmap *tracked_dp_bindings, bool claimed); +static bool is_lport_vif(const struct sbrec_port_binding *pb); + +static struct qos_queue * +get_qos_map_entry(struct hmap *queue_map, const char *name) +{ + struct qos_queue *qos_node; + HMAP_FOR_EACH (qos_node, node, queue_map) { + if (!strcmp(qos_node->port_name, name)) { + return qos_node; + } + } + + return NULL; +} + static void -get_qos_params(const struct sbrec_port_binding *pb, struct hmap *queue_map) +update_qos_params(const struct sbrec_port_binding *pb, struct hmap *queue_map) { uint32_t min_rate = smap_get_int(&pb->options, "qos_min_rate", 0); uint32_t max_rate = smap_get_int(&pb->options, "qos_max_rate", 0); uint32_t burst = smap_get_int(&pb->options, "qos_burst", 0); uint32_t queue_id = smap_get_int(&pb->options, "qdisc_queue_id", 0); + struct qos_queue *node = get_qos_map_entry(queue_map, pb->logical_port); + if ((!min_rate && !max_rate && !burst) || !queue_id) { /* Qos is not configured for this port. */ + if (node) { + hmap_remove(queue_map, &node->node); + free(node->port_name); + free(node); + } return; } - struct qos_queue *node = xzalloc(sizeof *node); - hmap_insert(queue_map, &node->node, hash_int(queue_id, 0)); + if (!node) { + node = xzalloc(sizeof *node); + hmap_insert(queue_map, &node->node, hash_int(queue_id, 0)); + node->port_name = xstrdup(pb->logical_port); + } + node->queue_id = queue_id; node->min_rate = min_rate; node->max_rate = max_rate; node->burst = burst; - node->queue_id = queue_id; } static const struct ovsrec_qos * @@ -191,7 +217,7 @@ static bool set_noop_qos(struct ovsdb_idl_txn *ovs_idl_txn, const struct ovsrec_port_table *port_table, const struct ovsrec_qos_table *qos_table, - struct sset *egress_ifaces) + struct shash *egress_ifaces) { if (!ovs_idl_txn) { return false; @@ -206,11 +232,11 @@ set_noop_qos(struct ovsdb_idl_txn *ovs_idl_txn, size_t count = 0; OVSREC_PORT_TABLE_FOR_EACH (port, port_table) { - if (sset_contains(egress_ifaces, port->name)) { + if (shash_find(egress_ifaces, port->name)) { ovsrec_port_set_qos(port, noop_qos); count++; } - if (sset_count(egress_ifaces) == count) { + if (shash_count(egress_ifaces) == count) { break; } } @@ -236,7 +262,8 @@ set_qos_type(struct netdev *netdev, const char *type) } static void -setup_qos(const char *egress_iface, struct hmap *queue_map) +setup_qos(const char *egress_iface, const char *logical_port, + struct hmap *queue_map) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); struct netdev *netdev_phy; @@ -281,7 +308,7 @@ setup_qos(const char *egress_iface, struct hmap *queue_map) * a configuration setting. * * - Otherwise leave the qdisc alone. */ - if (hmap_is_empty(queue_map)) { + if (!get_qos_map_entry(queue_map, logical_port)) { if (!strcmp(qdisc_type, OVN_QOS_TYPE)) { set_qos_type(netdev_phy, ""); } @@ -338,6 +365,10 @@ setup_qos(const char *egress_iface, struct hmap *queue_map) continue; } + if (strcmp(sb_info->port_name, logical_port)) { + continue; + } + smap_clear(&queue_details); smap_add_format(&queue_details, "min-rate", "%d", sb_info->min_rate); smap_add_format(&queue_details, "max-rate", "%d", sb_info->max_rate); @@ -354,11 +385,12 @@ setup_qos(const char *egress_iface, struct hmap *queue_map) netdev_close(netdev_phy); } -static void +void destroy_qos_map(struct hmap *qos_map) { struct qos_queue *qos_queue; HMAP_FOR_EACH_POP (qos_queue, node, qos_map) { + free(qos_queue->port_name); free(qos_queue); } @@ -404,7 +436,7 @@ sbrec_get_port_encap(const struct sbrec_chassis *chassis_rec, static void add_localnet_egress_interface_mappings( const struct sbrec_port_binding *port_binding, - struct shash *bridge_mappings, struct sset *egress_ifaces) + struct shash *bridge_mappings, struct shash *egress_ifaces) { const char *network = smap_get(&port_binding->options, "network_name"); if (!network) { @@ -429,7 +461,8 @@ add_localnet_egress_interface_mappings( if (!is_egress_iface) { continue; } - sset_add(egress_ifaces, iface_rec->name); + shash_add(egress_ifaces, iface_rec->name, + port_binding->logical_port); } } } @@ -474,7 +507,7 @@ update_ld_multichassis_ports(const struct sbrec_port_binding *binding_rec, static void update_ld_localnet_port(const struct sbrec_port_binding *binding_rec, struct shash *bridge_mappings, - struct sset *egress_ifaces, + struct shash *egress_ifaces, struct hmap *local_datapaths) { /* Ignore localnet ports for unplugged networks. */ @@ -1456,7 +1489,7 @@ consider_vif_lport_(const struct sbrec_port_binding *pb, b_ctx_out->tracked_dp_bindings); } if (b_lport->lbinding->iface && qos_map && b_ctx_in->ovs_idl_txn) { - get_qos_params(pb, qos_map); + update_qos_params(pb, qos_map); } } else { /* We could, but can't claim the lport. */ @@ -1519,6 +1552,16 @@ consider_vif_lport(const struct sbrec_port_binding *pb, b_lport = local_binding_add_lport(binding_lports, lbinding, pb, LP_VIF); } + + if (lbinding->iface && + smap_get(&lbinding->iface->external_ids, "ovn-egress-iface")) { + const char *iface_id = smap_get(&lbinding->iface->external_ids, + "iface-id"); + if (iface_id) { + shash_add(b_ctx_out->egress_ifaces, lbinding->iface->name, + iface_id); + } + } } return consider_vif_lport_(pb, can_bind, b_ctx_in, b_ctx_out, @@ -1785,7 +1828,7 @@ consider_localnet_lport(const struct sbrec_port_binding *pb, update_local_lports(pb->logical_port, b_ctx_out); if (qos_map && b_ctx_in->ovs_idl_txn) { - get_qos_params(pb, qos_map); + update_qos_params(pb, qos_map); } update_related_lport(pb, b_ctx_out); @@ -1861,14 +1904,14 @@ build_local_bindings(struct binding_ctx_in *b_ctx_in, &b_ctx_out->lbinding_data->bindings; for (j = 0; j < port_rec->n_interfaces; j++) { const struct ovsrec_interface *iface_rec; + struct local_binding *lbinding = NULL; iface_rec = port_rec->interfaces[j]; iface_id = smap_get(&iface_rec->external_ids, "iface-id"); int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0; if (iface_id && ofport > 0) { - struct local_binding *lbinding = - local_binding_find(local_bindings, iface_id); + lbinding = local_binding_find(local_bindings, iface_id); if (!lbinding) { lbinding = local_binding_create(iface_id, iface_rec); local_binding_add(local_bindings, lbinding); @@ -1895,8 +1938,11 @@ build_local_bindings(struct binding_ctx_in *b_ctx_in, const char *tunnel_iface = smap_get(&iface_rec->status, "tunnel_egress_iface"); if (tunnel_iface) { - sset_add(b_ctx_out->egress_ifaces, tunnel_iface); + shash_add(b_ctx_out->egress_ifaces, tunnel_iface, ""); } + } else if (lbinding && smap_get(&iface_rec->external_ids, + "ovn-egress-iface")) { + shash_add(b_ctx_out->egress_ifaces, iface_rec->name, iface_id); } } } @@ -1910,16 +1956,11 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) } struct shash bridge_mappings = SHASH_INITIALIZER(&bridge_mappings); - struct hmap qos_map; - hmap_init(&qos_map); if (b_ctx_in->br_int) { build_local_bindings(b_ctx_in, b_ctx_out); } - struct hmap *qos_map_ptr = - !sset_is_empty(b_ctx_out->egress_ifaces) ? &qos_map : NULL; - struct ovs_list localnet_lports = OVS_LIST_INITIALIZER(&localnet_lports); struct ovs_list external_lports = OVS_LIST_INITIALIZER(&external_lports); struct ovs_list multichassis_ports = OVS_LIST_INITIALIZER( @@ -1956,7 +1997,8 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) break; case LP_VIF: - consider_vif_lport(pb, b_ctx_in, b_ctx_out, NULL, qos_map_ptr); + consider_vif_lport(pb, b_ctx_in, b_ctx_out, NULL, + b_ctx_out->qos_map); if (pb->additional_chassis) { struct lport *multichassis_lport = xmalloc( sizeof *multichassis_lport); @@ -1967,11 +2009,13 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) break; case LP_CONTAINER: - consider_container_lport(pb, b_ctx_in, b_ctx_out, qos_map_ptr); + consider_container_lport(pb, b_ctx_in, b_ctx_out, + b_ctx_out->qos_map); break; case LP_VIRTUAL: - consider_virtual_lport(pb, b_ctx_in, b_ctx_out, qos_map_ptr); + consider_virtual_lport(pb, b_ctx_in, b_ctx_out, + b_ctx_out->qos_map); break; case LP_L2GATEWAY: @@ -1994,7 +2038,8 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) break; case LP_LOCALNET: { - consider_localnet_lport(pb, b_ctx_in, b_ctx_out, &qos_map); + consider_localnet_lport(pb, b_ctx_in, b_ctx_out, + b_ctx_out->qos_map); struct lport *lnet_lport = xmalloc(sizeof *lnet_lport); lnet_lport->pb = pb; ovs_list_push_back(&localnet_lports, &lnet_lport->list_node); @@ -2051,17 +2096,15 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) shash_destroy(&bridge_mappings); - if (!sset_is_empty(b_ctx_out->egress_ifaces) + if (!shash_is_empty(b_ctx_out->egress_ifaces) && set_noop_qos(b_ctx_in->ovs_idl_txn, b_ctx_in->port_table, b_ctx_in->qos_table, b_ctx_out->egress_ifaces)) { - const char *entry; - SSET_FOR_EACH (entry, b_ctx_out->egress_ifaces) { - setup_qos(entry, &qos_map); + struct shash_node *entry; + SHASH_FOR_EACH (entry, b_ctx_out->egress_ifaces) { + setup_qos(entry->name, entry->data, b_ctx_out->qos_map); } } - destroy_qos_map(&qos_map); - cleanup_claimed_port_timestamps(); } @@ -2447,7 +2490,7 @@ binding_handle_ovs_interface_changes(struct binding_ctx_in *b_ctx_in, } if (smap_get(&iface_rec->external_ids, "ovn-egress-iface") || - sset_contains(b_ctx_out->egress_ifaces, iface_rec->name)) { + shash_find(b_ctx_out->egress_ifaces, iface_rec->name)) { handled = false; break; } @@ -2493,10 +2536,6 @@ binding_handle_ovs_interface_changes(struct binding_ctx_in *b_ctx_in, return false; } - struct hmap qos_map = HMAP_INITIALIZER(&qos_map); - struct hmap *qos_map_ptr = - sset_is_empty(b_ctx_out->egress_ifaces) ? NULL : &qos_map; - /* * We consider an OVS interface for claiming if the following * 2 conditions are met: @@ -2525,24 +2564,22 @@ binding_handle_ovs_interface_changes(struct binding_ctx_in *b_ctx_in, if (iface_id && ofport > 0 && is_iface_in_int_bridge(iface_rec, b_ctx_in->br_int)) { handled = consider_iface_claim(iface_rec, iface_id, b_ctx_in, - b_ctx_out, qos_map_ptr); + b_ctx_out, b_ctx_out->qos_map); if (!handled) { break; } } } - if (handled && qos_map_ptr && set_noop_qos(b_ctx_in->ovs_idl_txn, - b_ctx_in->port_table, - b_ctx_in->qos_table, - b_ctx_out->egress_ifaces)) { - const char *entry; - SSET_FOR_EACH (entry, b_ctx_out->egress_ifaces) { - setup_qos(entry, &qos_map); + if (handled && + set_noop_qos(b_ctx_in->ovs_idl_txn, b_ctx_in->port_table, + b_ctx_in->qos_table, b_ctx_out->egress_ifaces)) { + struct shash_node *entry; + SHASH_FOR_EACH (entry, b_ctx_out->egress_ifaces) { + setup_qos(entry->name, entry->data, b_ctx_out->qos_map); } } - destroy_qos_map(&qos_map); return handled; } @@ -2977,10 +3014,6 @@ delete_done: return false; } - struct hmap qos_map = HMAP_INITIALIZER(&qos_map); - struct hmap *qos_map_ptr = - sset_is_empty(b_ctx_out->egress_ifaces) ? NULL : &qos_map; - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, b_ctx_in->port_binding_table) { /* Loop to handle create and update changes only. */ @@ -2992,7 +3025,8 @@ delete_done: update_ld_peers(pb, b_ctx_out->local_datapaths); } - handled = handle_updated_port(b_ctx_in, b_ctx_out, pb, qos_map_ptr); + handled = handle_updated_port(b_ctx_in, b_ctx_out, pb, + b_ctx_out->qos_map); if (!handled) { break; } @@ -3009,7 +3043,8 @@ delete_done: sset_find_and_delete(b_ctx_out->postponed_ports, port_name); continue; } - handled = handle_updated_port(b_ctx_in, b_ctx_out, pb, qos_map_ptr); + handled = handle_updated_port(b_ctx_in, b_ctx_out, pb, + b_ctx_out->qos_map); if (!handled) { break; } @@ -3055,17 +3090,15 @@ delete_done: shash_destroy(&bridge_mappings); } - if (handled && qos_map_ptr && set_noop_qos(b_ctx_in->ovs_idl_txn, - b_ctx_in->port_table, - b_ctx_in->qos_table, - b_ctx_out->egress_ifaces)) { - const char *entry; - SSET_FOR_EACH (entry, b_ctx_out->egress_ifaces) { - setup_qos(entry, &qos_map); + if (handled && + set_noop_qos(b_ctx_in->ovs_idl_txn, b_ctx_in->port_table, + b_ctx_in->qos_table, b_ctx_out->egress_ifaces)) { + struct shash_node *entry; + SHASH_FOR_EACH (entry, b_ctx_out->egress_ifaces) { + setup_qos(entry->name, entry->data, b_ctx_out->qos_map); } } - destroy_qos_map(&qos_map); return handled; } diff --git a/controller/binding.h b/controller/binding.h index 6c3a98b02..8be33eddb 100644 --- a/controller/binding.h +++ b/controller/binding.h @@ -91,7 +91,8 @@ struct binding_ctx_out { */ bool non_vif_ports_changed; - struct sset *egress_ifaces; + struct shash *egress_ifaces; + struct hmap *qos_map; /* smap of OVS interface name as key and * OVS interface external_ids:iface-id as value. */ struct smap *local_iface_ids; @@ -195,6 +196,8 @@ void set_pb_chassis_in_sbrec(const struct sbrec_port_binding *pb, const struct sbrec_chassis *chassis_rec, bool is_set); +void destroy_qos_map(struct hmap *qos_map); + /* Corresponds to each Port_Binding.type. */ enum en_lport_type { LP_UNKNOWN, diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index d6251afb8..066d76869 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -1276,7 +1276,8 @@ struct ed_type_runtime_data { struct sset active_tunnels; /* runtime data engine private data. */ - struct sset egress_ifaces; + struct shash egress_ifaces; + struct hmap qos_map; struct smap local_iface_ids; /* Tracked data. See below for more details and comments. */ @@ -1372,7 +1373,8 @@ en_runtime_data_init(struct engine_node *node OVS_UNUSED, sset_init(&data->local_lports); related_lports_init(&data->related_lports); sset_init(&data->active_tunnels); - sset_init(&data->egress_ifaces); + shash_init(&data->egress_ifaces); + hmap_init(&data->qos_map); smap_init(&data->local_iface_ids); local_binding_data_init(&data->lbinding_data); shash_init(&data->local_active_ports_ipv6_pd); @@ -1392,7 +1394,8 @@ en_runtime_data_cleanup(void *data) sset_destroy(&rt_data->local_lports); related_lports_destroy(&rt_data->related_lports); sset_destroy(&rt_data->active_tunnels); - sset_destroy(&rt_data->egress_ifaces); + shash_destroy(&rt_data->egress_ifaces); + destroy_qos_map(&rt_data->qos_map); smap_destroy(&rt_data->local_iface_ids); local_datapaths_destroy(&rt_data->local_datapaths); shash_destroy(&rt_data->local_active_ports_ipv6_pd); @@ -1481,6 +1484,7 @@ init_binding_ctx(struct engine_node *node, b_ctx_out->related_lports_changed = false; b_ctx_out->non_vif_ports_changed = false; b_ctx_out->egress_ifaces = &rt_data->egress_ifaces; + b_ctx_out->qos_map = &rt_data->qos_map; b_ctx_out->lbinding_data = &rt_data->lbinding_data; b_ctx_out->local_iface_ids = &rt_data->local_iface_ids; b_ctx_out->postponed_ports = rt_data->postponed_ports; @@ -1510,13 +1514,14 @@ en_runtime_data_run(struct engine_node *node, void *data) sset_destroy(local_lports); related_lports_destroy(&rt_data->related_lports); sset_destroy(active_tunnels); - sset_destroy(&rt_data->egress_ifaces); + shash_clear(&rt_data->egress_ifaces); + destroy_qos_map(&rt_data->qos_map); + hmap_init(&rt_data->qos_map); smap_destroy(&rt_data->local_iface_ids); hmap_init(local_datapaths); sset_init(local_lports); related_lports_init(&rt_data->related_lports); sset_init(active_tunnels); - sset_init(&rt_data->egress_ifaces); smap_init(&rt_data->local_iface_ids); local_binding_data_init(&rt_data->lbinding_data); } diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 3e904c9dc..c986198a2 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -6335,6 +6335,10 @@ ADD_NAMESPACES(sw01) ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03") ovn-nbctl lsp-add sw0 sw01 \ -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2" +ADD_NAMESPACES(sw02) +ADD_VETH(sw02, sw02, br-int, "192.168.1.3/24", "f2:00:00:01:02:03") +ovn-nbctl lsp-add sw0 sw02 \ + -- lsp-set-addresses sw02 "f2:00:00:01:02:03 192.168.1.3" ADD_NAMESPACES(public) ADD_VETH(public, public, br-ext, "192.168.2.2/24", "f0:00:00:01:02:05") @@ -6345,6 +6349,7 @@ ovn-nbctl lsp-add sw0 public \ -- lsp-set-type public localnet \ -- lsp-set-options public network_name=phynet +# Setup QoS on a localnet port AT_CHECK([ovn-nbctl set Logical_Switch_Port public options:qos_min_rate=200000]) AT_CHECK([ovn-nbctl set Logical_Switch_Port public options:qos_max_rate=300000]) AT_CHECK([ovn-nbctl set Logical_Switch_Port public options:qos_burst=3000000]) @@ -6353,15 +6358,58 @@ OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-public']) OVS_WAIT_UNTIL([tc class show dev ovs-public | \ grep -q 'class htb .* rate 200Kbit ceil 300Kbit burst 375000b cburst 375000b']) +# Setup QoS on a logical switch ports +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw01 options:qos_min_rate=400000]) +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw01 options:qos_max_rate=800000]) +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw01 options:qos_burst=5000000]) +AT_CHECK([ovs-vsctl set interface ovs-sw01 external-ids:ovn-egress-iface=true]) +OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-sw01']) +OVS_WAIT_UNTIL([tc class show dev ovs-sw01 | \ + grep -q 'class htb .* rate 400Kbit ceil 800Kbit burst 625000b cburst 625000b']) + +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw02 options:qos_min_rate=600000]) +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw02 options:qos_max_rate=6000000]) +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw02 options:qos_burst=6000000]) +AT_CHECK([ovs-vsctl set interface ovs-sw02 external-ids:ovn-egress-iface=true]) +OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-sw02']) +OVS_WAIT_UNTIL([tc class show dev ovs-sw02 | \ + grep -q 'class htb .* rate 600Kbit ceil 6Mbit burst 750000b cburst 750000b']) + +AT_CHECK([ovn-appctl -t ovn-controller exit --restart]) +OVS_WAIT_UNTIL([test "$(pidof ovn-controller)" = ""]) +start_daemon ovn-controller +OVS_WAIT_UNTIL([test "$(pidof ovn-controller)" != ""]) + +OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-public']) +OVS_WAIT_UNTIL([tc class show dev ovs-public | \ + grep -q 'class htb .* rate 200Kbit ceil 300Kbit burst 375000b cburst 375000b']) +OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-sw01']) +OVS_WAIT_UNTIL([tc class show dev ovs-sw01 | \ + grep -q 'class htb .* rate 400Kbit ceil 800Kbit burst 625000b cburst 625000b']) +OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-sw02']) +OVS_WAIT_UNTIL([tc class show dev ovs-sw02 | \ + grep -q 'class htb .* rate 600Kbit ceil 6Mbit burst 750000b cburst 750000b']) AT_CHECK([ovn-nbctl remove Logical_Switch_Port public options qos_max_rate=300000]) OVS_WAIT_UNTIL([tc class show dev ovs-public | \ grep -q 'class htb .* rate 200Kbit ceil 34359Mbit burst 375000b .*']) AT_CHECK([ovn-nbctl remove Logical_Switch_Port public options qos_min_rate=200000]) +AT_CHECK([ovn-nbctl remove Logical_Switch_Port public options qos_max_rate=300000]) AT_CHECK([ovn-nbctl remove Logical_Switch_Port public options qos_burst=3000000]) OVS_WAIT_UNTIL([test "$(tc qdisc show | grep 'htb 1: dev ovs-public')" = ""]) +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw01 options:qos_min_rate=200000]) +OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-sw01']) +OVS_WAIT_UNTIL([tc class show dev ovs-sw01 | \ + grep -q 'class htb .* rate 200Kbit ceil 800Kbit burst 625000b cburst 625000b']) + +# Disable QoS rules from logical switch ports +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw01 options:qdisc_queue_id=0]) +AT_CHECK([ovn-nbctl set Logical_Switch_Port sw02 options:qdisc_queue_id=0]) +OVS_WAIT_UNTIL([test "$(tc qdisc show | grep 'htb 1: dev ovs-sw01')" = ""]) +OVS_WAIT_UNTIL([test "$(tc qdisc show | grep 'htb 1: dev ovs-sw02')" = ""]) + kill $(pidof ovn-controller) as ovn-sb