On Fri, Jun 24, 2016 at 02:59:15PM +0530, bscha...@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 <bscha...@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> _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev