[ovs-dev] [PATCH v4 1/2] Check and allocate free qdisc queue id for ports with qos parameters
Ben Pfaff
blp at ovn.org
Fri Jun 24 20:10:11 UTC 2016
On Fri, Jun 24, 2016 at 02:59:15PM +0530, bschanmu at redhat.com wrote:
> ovn-northd processes the list of Port_Bindings and hashes the list of
> queues per chassis. When it finds a port with qos_parameters and without
> a queue_id, it allocates a free queue for the chassis that this port belongs.
> The queue_id information is stored in the options field of Port_binding table.
> Adds an action set_queue to the ingress table 0 of the logical flows
> which will be translated to openflow set_queue by ovn-controller
>
> ovn-controller opens the netdev corresponding to the tunnel interface's
> status:tunnel_egress_iface value and configures a HTB qdisc on it. Then for
> each SB port_binding that has queue_id set, it allocates a queue with the
> qos_parameters of that port. It also frees up unused queues.
>
> This patch replaces the older approach of policing
>
> Signed-off-by: Babu Shanmugam <bschanmu at redhat.com>
Thanks for the new version.
I'm passing along an incremental to fold in. Some of the changes are
style. Others:
* Put hmap_node at the start of structs because it makes valgrind's
memory leak checker confident about pointers instead of calling
them "possible leaks".
* Avoid trying to modify the OVS database when there's no transaction
open.
* Log errors from netdev operations.
* Don't log a warning when setting up QoS.
* Fix a couple of memory leaks.
I was going to just apply this but there's an ongoing situation where we
might need to revert patches in this same area (see
http://openvswitch.org/pipermail/dev/2016-June/073608.html) and I don't
want to make that harder. So please sit on this until that situation
resolves.
--8<--------------------------cut here-------------------------->8--
diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index 97f9aee..c53554f 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -41,10 +41,10 @@ binding_reset_processing(void)
}
struct qos_queue {
+ struct hmap_node node;
uint32_t queue_id;
uint32_t max_rate;
uint32_t burst;
- struct hmap_node node;
};
void
@@ -189,37 +189,42 @@ get_qos_params(const struct sbrec_port_binding *pb, struct hmap *queue_map)
}
struct qos_queue *node = xzalloc(sizeof *node);
-
+ hmap_insert(queue_map, &node->node, hash_int(queue_id, 0));
node->max_rate = max_rate;
node->burst = burst;
node->queue_id = queue_id;
- hmap_insert(queue_map, &node->node, hash_int(queue_id, 0));
}
static const struct ovsrec_qos *
get_noop_qos(struct controller_ctx *ctx)
{
const struct ovsrec_qos *qos;
-
- OVSREC_QOS_FOR_EACH(qos, ctx->ovs_idl) {
+ OVSREC_QOS_FOR_EACH (qos, ctx->ovs_idl) {
if (!strcmp(qos->type, "linux-noop")) {
return qos;
}
}
+ if (!ctx->ovs_idl_txn) {
+ return NULL;
+ }
qos = ovsrec_qos_insert(ctx->ovs_idl_txn);
ovsrec_qos_set_type(qos, "linux-noop");
return qos;
}
-static void
+static bool
set_noop_qos(struct controller_ctx *ctx, struct sset *egress_ifaces)
{
const struct ovsrec_qos *noop_qos = get_noop_qos(ctx);
+ if (!noop_qos) {
+ return false;
+ }
+
const struct ovsrec_port *port;
size_t count = 0;
- OVSREC_PORT_FOR_EACH(port, ctx->ovs_idl) {
+ OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) {
if (sset_contains(egress_ifaces, port->name)) {
ovsrec_port_set_qos(port, noop_qos);
count++;
@@ -228,22 +233,24 @@ set_noop_qos(struct controller_ctx *ctx, struct sset *egress_ifaces)
break;
}
}
+ return true;
}
static void
setup_qos(const char *egress_iface, struct hmap *queue_map)
{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
struct netdev *netdev_phy;
if (!egress_iface) {
/* Queues cannot be configured. */
return;
}
- VLOG_WARN("Setting up qos on %s", egress_iface);
- if (netdev_open(egress_iface, NULL, &netdev_phy) != 0) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_WARN_RL(&rl, "Unable to open netdev %s\n", egress_iface);
+ int error = netdev_open(egress_iface, NULL, &netdev_phy);
+ if (error) {
+ VLOG_WARN_RL(&rl, "%s: could not open netdev (%s)",
+ egress_iface, ovs_strerror(error));
return;
}
@@ -258,7 +265,11 @@ setup_qos(const char *egress_iface, struct hmap *queue_map)
return;
}
if (strcmp(qdisc_type, OVN_QOS_TYPE)) {
- netdev_set_qos(netdev_phy, OVN_QOS_TYPE, &qdisc_details);
+ error = netdev_set_qos(netdev_phy, OVN_QOS_TYPE, &qdisc_details);
+ if (error) {
+ VLOG_WARN_RL(&rl, "%s: could not configure QoS (%s)",
+ egress_iface, ovs_strerror(error));
+ }
}
/* Check and delete if needed. */
@@ -270,7 +281,7 @@ setup_qos(const char *egress_iface, struct hmap *queue_map)
smap_init(&queue_details);
hmap_init(&consistent_queues);
- NETDEV_QUEUE_FOR_EACH(&queue_id, &queue_details, &dump, netdev_phy) {
+ NETDEV_QUEUE_FOR_EACH (&queue_id, &queue_details, &dump, netdev_phy) {
bool is_queue_needed = false;
HMAP_FOR_EACH_WITH_HASH (sb_info, node, hash_int(queue_id, 0),
@@ -287,12 +298,16 @@ setup_qos(const char *egress_iface, struct hmap *queue_map)
}
if (!is_queue_needed) {
- netdev_delete_queue(netdev_phy, queue_id);
+ error = netdev_delete_queue(netdev_phy, queue_id);
+ if (error) {
+ VLOG_WARN_RL(&rl, "%s: could not delete queue %u (%s)",
+ egress_iface, queue_id, ovs_strerror(error));
+ }
}
}
/* Create/Update queues. */
- HMAP_FOR_EACH(sb_info, node, queue_map) {
+ HMAP_FOR_EACH (sb_info, node, queue_map) {
if (hmap_contains(&consistent_queues, &sb_info->node)) {
hmap_remove(&consistent_queues, &sb_info->node);
continue;
@@ -301,7 +316,12 @@ setup_qos(const char *egress_iface, struct hmap *queue_map)
smap_clear(&queue_details);
smap_add_format(&queue_details, "max-rate", "%d", sb_info->max_rate);
smap_add_format(&queue_details, "burst", "%d", sb_info->burst);
- netdev_set_queue(netdev_phy, sb_info->queue_id, &queue_details);
+ error = netdev_set_queue(netdev_phy, sb_info->queue_id,
+ &queue_details);
+ if (error) {
+ VLOG_WARN_RL(&rl, "%s: could not configure queue %u (%s)",
+ egress_iface, sb_info->queue_id, ovs_strerror(error));
+ }
}
smap_destroy(&queue_details);
hmap_destroy(&consistent_queues);
@@ -419,11 +439,9 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
}
}
- if (!sset_is_empty(&egress_ifaces)) {
+ if (!sset_is_empty(&egress_ifaces) && set_noop_qos(ctx, &egress_ifaces)) {
const char *entry;
-
- set_noop_qos(ctx, &egress_ifaces);
- SSET_FOR_EACH(entry, &egress_ifaces) {
+ SSET_FOR_EACH (entry, &egress_ifaces) {
setup_qos(entry, &qos_map);
}
}
diff --git a/ovn/lib/actions.h b/ovn/lib/actions.h
index 14c23e8..81a38c5 100644
--- a/ovn/lib/actions.h
+++ b/ovn/lib/actions.h
@@ -22,8 +22,8 @@
#include "compiler.h"
#include "util.h"
-#define QDISC_MIN_QUEUE_ID (1)
-#define QDISC_MAX_QUEUE_ID (0xf000)
+#define QDISC_MIN_QUEUE_ID 0
+#define QDISC_MAX_QUEUE_ID 0xf000
struct expr;
struct lexer;
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 9da8614..f3495d7 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -239,8 +239,8 @@ allocate_tnlid(struct hmap *set, const char *name, uint32_t max,
}
struct ovn_chassis_qdisc_queues {
- uint32_t queue_id;
struct hmap_node key_node;
+ uint32_t queue_id;
};
static void
@@ -305,7 +305,8 @@ free_chassis_queueid(struct hmap *set, const char * chassis, uint32_t queue_id)
}
static inline bool
-port_has_qos_params(struct smap * opts) {
+port_has_qos_params(const struct smap *opts)
+{
return (smap_get(opts, "qos_max_rate") ||
smap_get(opts, "qos_burst"));
}
@@ -803,16 +804,11 @@ ovn_port_update_sbrec(const struct ovn_port *op,
if (strcmp(op->nbs->type, "router")) {
uint32_t queue_id = smap_get_int(
&op->sb->options, "qdisc_queue_id", 0);
- struct smap options;
-
- smap_clone(&options, &op->nbs->options);
- if (op->sb->chassis && port_has_qos_params(&options)
- && !queue_id) {
+ bool has_qos = port_has_qos_params(&op->nbs->options);
+ if (op->sb->chassis && has_qos && !queue_id) {
queue_id = allocate_chassis_queueid(chassis_qdisc_queues,
op->sb->chassis->name);
- }
- if (!port_has_qos_params(&options) && queue_id) {
- /* Free this queue. */
+ } else if (!has_qos && queue_id) {
free_chassis_queueid(chassis_qdisc_queues,
op->sb->chassis->name,
queue_id);
@@ -820,12 +816,16 @@ ovn_port_update_sbrec(const struct ovn_port *op,
}
if (queue_id) {
- /* Only when there is a valid queue. */
+ struct smap options;
+ smap_clone(&options, &op->nbs->options);
smap_add_format(&options,
"qdisc_queue_id", "%d", queue_id);
+ sbrec_port_binding_set_options(op->sb, &options);
+ smap_destroy(&options);
+ } else {
+ sbrec_port_binding_set_options(op->sb, &op->sb->options);
}
sbrec_port_binding_set_type(op->sb, op->nbs->type);
- sbrec_port_binding_set_options(op->sb, &options);
} else {
const char *chassis = NULL;
if (op->peer && op->peer->od && op->peer->od->nbr) {
@@ -1656,12 +1656,13 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
&match);
const char *queue_id = smap_get(&op->sb->options, "qdisc_queue_id");
if (queue_id) {
- ds_put_format(&action, "set_queue(%s);", queue_id);
+ ds_put_format(&action, "set_queue(%s); ", queue_id);
}
ds_put_cstr(&action, "next;");
ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50,
ds_cstr(&match), ds_cstr(&action));
ds_destroy(&match);
+ ds_destroy(&action);
if (op->nbs->n_port_security) {
build_port_security_ip(P_IN, op, lflows);
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index 6655fab..c559d56 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -1070,12 +1070,18 @@
<dd>
<p>
- <b>Parameters</b>: Queue number <var>queue_number</var>, 32-bit
+ <b>Parameters</b>: Queue number <var>queue_number</var>, in the range 0 to 61440.
</p>
<p>
- This is equivalent to Openflow set_queue. queue_number should be
- in the range of 1 to 61440
+ This is a logical equivalent of the OpenFlow <code>set_queue</code>
+ action. It affects packets that egress a hypervisor through a
+ physical interface. For nonzero <var>queue_number</var>, it
+ configures packet queuing to match the settings configured for the
+ <ref table="Port_Binding"/> with
+ <code>options:qdisc_queue_id</code> matching
+ <var>queue_number</var>. When <var>queue_number</var> is zero, it
+ resets queuing to the default strategy.
</p>
<p><b>Example:</b> <code>set_queue(10);</code></p>
More information about the dev
mailing list