static int do_add_port(struct dp_netdev *dp, const char *devname,
const char *type, odp_port_t port_no)
OVS_REQUIRES(dp->port_mutex);
-static int do_del_port(struct dp_netdev *dp, odp_port_t port_no)
+static void do_del_port(struct dp_netdev *dp, struct dp_netdev_port *)
OVS_REQUIRES(dp->port_mutex);
static void dp_netdev_destroy_all_queues(struct dp_netdev *dp)
OVS_REQ_WRLOCK(dp->queue_rwlock);
dp_netdev_flow_flush(dp);
ovs_mutex_lock(&dp->port_mutex);
CMAP_FOR_EACH (port, node, &cursor, &dp->ports) {
- do_del_port(dp, port->port_no);
+ do_del_port(dp, port);
}
ovs_mutex_unlock(&dp->port_mutex);
int error;
ovs_mutex_lock(&dp->port_mutex);
- error = port_no == ODPP_LOCAL ? EINVAL : do_del_port(dp, port_no);
+ if (port_no == ODPP_LOCAL) {
+ error = EINVAL;
+ } else {
+ struct dp_netdev_port *port;
+
+ error = get_port_by_number(dp, port_no, &port);
+ if (!error) {
+ do_del_port(dp, port);
+ }
+ }
ovs_mutex_unlock(&dp->port_mutex);
return error;
return ENOENT;
}
-static int
-do_del_port(struct dp_netdev *dp, odp_port_t port_no)
+static void
+do_del_port(struct dp_netdev *dp, struct dp_netdev_port *port)
OVS_REQUIRES(dp->port_mutex)
{
- struct dp_netdev_port *port;
- int error;
-
- error = get_port_by_number(dp, port_no, &port);
- if (error) {
- return error;
- }
-
- cmap_remove(&dp->ports, &port->node, hash_odp_port(port_no));
+ cmap_remove(&dp->ports, &port->node, hash_odp_port(port->port_no));
seq_change(dp->port_seq);
if (netdev_is_pmd(port->netdev)) {
dp_netdev_reload_pmd_threads(dp);
}
port_unref(port);
- return 0;
}
static void
dp_netdev_unref(dp);
}
+static void
+dpif_dummy_delete_port(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[], void *aux OVS_UNUSED)
+{
+ struct dp_netdev_port *port;
+ struct dp_netdev *dp;
+
+ 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_mutex_lock(&dp->port_mutex);
+ if (get_port_by_name(dp, argv[2], &port)) {
+ unixctl_command_reply_error(conn, "unknown port");
+ } else if (port->port_no == ODPP_LOCAL) {
+ unixctl_command_reply_error(conn, "can't delete local port");
+ } else {
+ do_del_port(dp, port);
+ unixctl_command_reply(conn, NULL);
+ }
+ ovs_mutex_unlock(&dp->port_mutex);
+
+ dp_netdev_unref(dp);
+}
+
static void
dpif_dummy_register__(const char *type)
{
unixctl_command_register("dpif-dummy/change-port-number",
"DP PORT NEW-NUMBER",
3, 3, dpif_dummy_change_port_number, NULL);
+ unixctl_command_register("dpif-dummy/delete-port", "DP PORT",
+ 2, 2, dpif_dummy_delete_port, NULL);
}
--- /dev/null
+AT_BANNER([bridge])
+
+dnl When a port disappears from a datapath, e.g. because an admin used
+dnl "ovs-dpctl del-port", the bridge code should be resilient enough to
+dnl notice and add it back the next time we reconfigure. A prior version
+dnl of the code failed to do this, so this test guards against regression.
+AT_SETUP([bridge - ports that disappear get added back])
+OVS_VSWITCHD_START
+
+# Add some ports and make sure that they show up in the datapath.
+ADD_OF_PORTS([br0], 1, 2)
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+dummy@ovs-dummy: hit:0 missed:0
+ br0:
+ br0 65534/100: (dummy)
+ p1 1/1: (dummy)
+ p2 2/2: (dummy)
+])
+
+# Delete p1 from the datapath as if by "ovs-dpctl del-port"
+# and check that it disappeared.
+AT_CHECK([ovs-appctl dpif-dummy/delete-port ovs-dummy p1])
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+dummy@ovs-dummy: hit:0 missed:0
+ br0:
+ br0 65534/100: (dummy)
+ p2 2/2: (dummy)
+])
+
+# Force reconfiguration and make sure that p1 got added back.
+AT_CHECK([ovs-vsctl del-port p2])
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+dummy@ovs-dummy: hit:0 missed:0
+ br0:
+ br0 65534/100: (dummy)
+ p1 1/1: (dummy)
+])
+AT_CLEANUP
AT_INIT
-AT_COPYRIGHT([Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+AT_COPYRIGHT([Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
m4_include([tests/ofproto.at])
m4_include([tests/dpif-netdev.at])
m4_include([tests/ofproto-dpif.at])
+m4_include([tests/bridge.at])
m4_include([tests/vlan-splinters.at])
m4_include([tests/ovsdb.at])
m4_include([tests/ovs-vsctl.at])