+ cfm = ofproto_iface_get_cfm(iface->port->bridge->ofproto, iface->dp_ifidx);
+
+ if (!cfm) {
+ unixctl_command_reply(conn, 501, "CFM not enabled");
+ return;
+ }
+
+ cfm_dump_ds(cfm, &ds);
+ unixctl_command_reply(conn, 200, ds_cstr(&ds));
+ ds_destroy(&ds);
+}
+\f
+/* QoS unixctl user interface functions. */
+
+struct qos_unixctl_show_cbdata {
+ struct ds *ds;
+ struct iface *iface;
+};
+
+static void
+qos_unixctl_show_cb(unsigned int queue_id,
+ const struct shash *details,
+ void *aux)
+{
+ struct qos_unixctl_show_cbdata *data = aux;
+ struct ds *ds = data->ds;
+ struct iface *iface = data->iface;
+ struct netdev_queue_stats stats;
+ struct shash_node *node;
+ int error;
+
+ ds_put_cstr(ds, "\n");
+ if (queue_id) {
+ ds_put_format(ds, "Queue %u:\n", queue_id);
+ } else {
+ ds_put_cstr(ds, "Default:\n");
+ }
+
+ SHASH_FOR_EACH (node, details) {
+ ds_put_format(ds, "\t%s: %s\n", node->name, (char *)node->data);
+ }
+
+ error = netdev_get_queue_stats(iface->netdev, queue_id, &stats);
+ if (!error) {
+ if (stats.tx_packets != UINT64_MAX) {
+ ds_put_format(ds, "\ttx_packets: %"PRIu64"\n", stats.tx_packets);
+ }
+
+ if (stats.tx_bytes != UINT64_MAX) {
+ ds_put_format(ds, "\ttx_bytes: %"PRIu64"\n", stats.tx_bytes);
+ }
+
+ if (stats.tx_errors != UINT64_MAX) {
+ ds_put_format(ds, "\ttx_errors: %"PRIu64"\n", stats.tx_errors);
+ }
+ } else {
+ ds_put_format(ds, "\tFailed to get statistics for queue %u: %s",
+ queue_id, strerror(error));
+ }
+}
+
+static void
+qos_unixctl_show(struct unixctl_conn *conn,
+ const char *args, void *aux OVS_UNUSED)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ struct shash sh = SHASH_INITIALIZER(&sh);
+ struct iface *iface;
+ const char *type;
+ struct shash_node *node;
+ struct qos_unixctl_show_cbdata data;
+ int error;
+
+ iface = iface_find(args);
+ if (!iface) {
+ unixctl_command_reply(conn, 501, "no such interface");
+ return;
+ }
+
+ netdev_get_qos(iface->netdev, &type, &sh);
+
+ if (*type != '\0') {
+ ds_put_format(&ds, "QoS: %s %s\n", iface->name, type);
+
+ SHASH_FOR_EACH (node, &sh) {
+ ds_put_format(&ds, "%s: %s\n", node->name, (char *)node->data);
+ }
+
+ data.ds = &ds;
+ data.iface = iface;
+ error = netdev_dump_queues(iface->netdev, qos_unixctl_show_cb, &data);
+
+ if (error) {
+ ds_put_format(&ds, "failed to dump queues: %s", strerror(error));
+ }
+ unixctl_command_reply(conn, 200, ds_cstr(&ds));
+ } else {
+ ds_put_format(&ds, "QoS not configured on %s\n", iface->name);
+ unixctl_command_reply(conn, 501, ds_cstr(&ds));
+ }
+
+ shash_destroy_free_data(&sh);
+ ds_destroy(&ds);
+}
+\f
+/* Bridge reconfiguration functions. */
+static struct bridge *
+bridge_create(const struct ovsrec_bridge *br_cfg)
+{
+ struct bridge *br;
+ int error;
+
+ assert(!bridge_lookup(br_cfg->name));
+ br = xzalloc(sizeof *br);
+
+ error = dpif_create_and_open(br_cfg->name, br_cfg->datapath_type,
+ &br->dpif);
+ if (error) {
+ free(br);
+ return NULL;
+ }
+
+ error = ofproto_create(br_cfg->name, br_cfg->datapath_type, &bridge_ofhooks,