+
+static void
+dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[], void *aux OVS_UNUSED)
+{
+ struct dp_netdev_port *port;
+ struct dp_netdev *dp;
+ odp_port_t port_no;
+
+ ovs_mutex_lock(&dp_netdev_mutex);
+ dp = shash_find_data(&dp_netdevs, argv[1]);
+ if (!dp || !dpif_netdev_class_is_dummy(dp->class)) {
+ ovs_mutex_unlock(&dp_netdev_mutex);
+ unixctl_command_reply_error(conn, "unknown datapath or not a dummy");
+ return;
+ }
+ ovs_refcount_ref(&dp->ref_cnt);
+ ovs_mutex_unlock(&dp_netdev_mutex);
+
+ ovs_rwlock_wrlock(&dp->port_rwlock);
+ if (get_port_by_name(dp, argv[2], &port)) {
+ unixctl_command_reply_error(conn, "unknown port");
+ goto exit;
+ }
+
+ port_no = u32_to_odp(atoi(argv[3]));
+ if (!port_no || port_no == ODPP_NONE) {
+ unixctl_command_reply_error(conn, "bad port number");
+ goto exit;
+ }
+ if (dp_netdev_lookup_port(dp, port_no)) {
+ unixctl_command_reply_error(conn, "port number already in use");
+ goto exit;
+ }
+ hmap_remove(&dp->ports, &port->node);
+ port->port_no = port_no;
+ hmap_insert(&dp->ports, &port->node, hash_int(odp_to_u32(port_no), 0));
+ seq_change(dp->port_seq);
+ unixctl_command_reply(conn, NULL);
+
+exit:
+ ovs_rwlock_unlock(&dp->port_rwlock);
+ dp_netdev_unref(dp);
+}
+
+static void
+dpif_dummy_register__(const char *type)
+{
+ struct dpif_class *class;
+
+ class = xmalloc(sizeof *class);
+ *class = dpif_netdev_class;
+ class->type = xstrdup(type);
+ dp_register_provider(class);
+}
+
+void
+dpif_dummy_register(bool override)
+{
+ if (override) {
+ struct sset types;
+ const char *type;
+
+ sset_init(&types);
+ dp_enumerate_types(&types);
+ SSET_FOR_EACH (type, &types) {
+ if (!dp_unregister_provider(type)) {
+ dpif_dummy_register__(type);
+ }
+ }
+ sset_destroy(&types);
+ }
+
+ dpif_dummy_register__("dummy");
+
+ unixctl_command_register("dpif-dummy/change-port-number",
+ "DP PORT NEW-NUMBER",
+ 3, 3, dpif_dummy_change_port_number, NULL);
+}