> On Fri, Dec 9, 2022 at 9:43 AM Lorenzo Bianconi
> <[email protected]> wrote:
> >
> > > On Sun, Dec 4, 2022 at 5:06 PM Lorenzo Bianconi
> > > <[email protected]> wrote:
> > > >
> > > > 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 <[email protected]>
> > > > Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2129742
> > > > Signed-off-by: Lorenzo Bianconi <[email protected]>
> > >
> > > Hi Lorenzo,
> >
> > Hi Numan,
> >
> > thx for the review :)
> >
> > >
> > > Thanks for addressing the comments.
> > >
> > > I tested this version and compared with the present main.
> > >
> > > I see a few differences.
> > >
> > > With the main version, when I configure qos params to a localnet
> > > logical port, ovn-controller creates a qdisc on the tunnel interface
> > > which I guess is expected.
> > > But I'm still not sure why we need to configure qdiscs on the tunnel
> > > interface. But that's a story. Perhaps I need to see the original
> > > QoS commits and understand why it was added.
> > >
> > > With your patch, I don't see that happening. Perhaps there is a bug
> > > in setup_qos() function now that 'shash' is used to store the egress
> > > ifaces with the logical port and
> > > there is no logical port for the tunnel interfaces.
> >
> > uhm, I can look into this. Do you think we should keep this behaviour?
>
> Frankly I don't know. We need to find out why qos was configured in
> the first place.
>
> I do agree with Ilya's comment that it is odd to configure qos on the
> tunnel interface
> and that could impact the other traffic.
>
>
> >
> > >
> > > Regarding the option - "ovn-egress-iface". I suppose the expectation
> > > from the CMS is to set the qos parameters in the logical port and also
> > > set this option in the
> > > ovs interface right ? I don't really see a need for this. I think if
> > > CMS configures the qos parameters in the logical port options,
> > > ovn-controller should configure the qos.
> > > I think otherwise this would complicate the CMS implementation. Thoughts
> > > ?
> >
> > ovn-egress-iface is mandatory since it is used in setup_qos() to look for
> > the
> > proper netdevice pointer to configure ovs qdisc (please note it is used to
> > identify ovs interfaces and not ovn ones).
> > I think it can be doable (not sure about the complexity) to avoid it for
> > logical switch ports (since we have iface-id in them external_ids column of
> > ovs interface table) but I do not think we can avoid to set
> > "ovn-egress-iface"
> > for localnet port since afaik there is no direct link between ovn localnet
> > port
> > and ovs interface used to connect the underlay network, right? If so I guess
> > it is better to keep it for both localnet and lsp ports. Do you agree?
>
> I think it's ok to expect CMS to set "ovn-egress-iface" for the
> physical nic connected to the
> provider bridge. But I don't think we should do the same for the
> normal logical port VIFs.
does it worth to introduce a difference here?
>
>
>
> >
> > >
> > >
> > > Please see a few comments below
> > >
> > > > ---
> > > > 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);
> > >
> > > When a qos is configured on a logical port, this patch is adding 2
> > > entries in the 'egress_ifaces' shash for the same logical port.
> > > I think it's because of the above 'shash_add'. I think you should use
> > > shash_replace instead.
> >
> > ack, I will fix it.
> >
> > >
> > > When a full recompute happens, the function build_local_bindings()
> > > also adds the qos configured logical ports to the 'egress_ifaces'
> > > and later if there are any updates to the logical port, this function
> > > - consider_vif_lport() also adds it to the shash.
> > >
> > > IMO the qos support in OVN needs a different approach. Instead of
> > > configuring the qos using netdev() perhaps we should rely on the OVS
> > > meters.
> > > Maybe this was brought up earlier too.
> >
> > >
> > > I'm of the opinion that instead of supporting Qos for logical ports
> > > using netdev, we should use OVS meters (not just for logical ports,
> > > even for localnet ports). Thoughts ?
> >
> > ovn qos is used for egress traffic (shaping) while ovn meters are used
> > for incoming one (policing).
> > What we can do is to avoid configuring directly netdev qdisc and rely on
> > ovs to perform this configuration but this would be quite a massive rework.
> > Do you think we should do it now before adding this feature or it is ok
> > to do it after we added this feature? I do not have a strong opinion about
> > it.
>
> IMO its better to add this new feature using the native OVS QoS support.
> And along with that we can remove the netdev implementation from OVN.
>
> This is what I think. Anyway this feature is out of window for 22.12.
> We can perhaps target this feature with the new approach in 23.03.
>
> Although I will not object if other maintainers are fine getting this
> feature first
> and then reimplement using OVS native QoS support.
I am fine to work on a proper solution for lsp and then move localnet port too.
Regards,
Lorenzo
>
> Thanks
> Numan
>
> >
> > Regards,
> > Lorenzo
> >
> > >
> > > @Dumitru Ceara @Han Zhou @Mark Michelson @Ilya Maximets Do you have
> > > any comments or suggestions here ?
> > >
> > > Thanks
> > > Numan
> > >
> > >
> > >
> > > > + }
> > > > + }
> > > > }
> > > >
> > > > 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
> > > > --
> > > > 2.38.1
> > > >
> > > > _______________________________________________
> > > > dev mailing list
> > > > [email protected]
> > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> > > >
> > >
> > _______________________________________________
> > dev mailing list
> > [email protected]
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev