Until now, asking ovs-vswitchd to shut down gracefully, e.g. with
"ovs-appctl exit", would cause it to first remove all the ports from
kernel-based datapaths. This has the unfortunate side effect that IP
addresses on any removed "internal" ports are lost, even if the ports are
added again when ovs-vswitchd is restarted. This is long-standing
behavior, but it only became important when the OVS control scripts were
changed to try to do graceful shutdown first instead of using a signal.
This commit changes graceful shutdown so that it leaves ports in the
datapath, fixing the problem.
Fixes:
9b5422a98f8 (ovs-lib: Try to call exit before killing.)
Reported-by: Edgar Cantu <eocantu@us.ibm.com>
Reported-at: http://openvswitch.org/pipermail/discuss/2016-January/020024.html
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Gurucharan Shetty <guru@ovn.org>
}
static void
-port_destruct(struct ofport *port_)
+port_destruct(struct ofport *port_, bool del)
{
struct ofport_dpif *port = ofport_dpif_cast(port_);
struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
dp_port_name = netdev_vport_get_dpif_port(port->up.netdev, namebuf,
sizeof namebuf);
- if (dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
+ if (del && dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
/* The underlying device is still there, so delete it. This
* happens when the ofproto is being destroyed, since the caller
* assumes that removal of attached ports will happen as part of
/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* initialization, and construct and destruct ofports to reflect all of
* the changes.
*
+ * - On graceful shutdown, the base ofproto code will destruct all
+ * the ports.
+ *
* ->port_construct() returns 0 if successful, otherwise a positive errno
* value.
+ *
+ *
+ * ->port_destruct()
+ * =================
+ *
+ * ->port_destruct() takes a 'del' parameter. If the provider implements
+ * the datapath itself (e.g. dpif-netdev, it can ignore 'del'. On the
+ * other hand, if the provider is an interface to an external datapath
+ * (e.g. to a kernel module that implement the datapath) then 'del' should
+ * influence destruction behavior in the following way:
+ *
+ * - If 'del' is true, it should remove the port from the underlying
+ * implementation. This is the common case.
+ *
+ * - If 'del' is false, it should leave the port in the underlying
+ * implementation. This is used when Open vSwitch is performing a
+ * graceful shutdown and ensures that, across Open vSwitch restarts,
+ * the underlying ports are not removed and recreated. That makes an
+ * important difference for, e.g., "internal" ports that have
+ * configured IP addresses; without this distinction, the IP address
+ * and other configured state for the port is lost.
*/
struct ofport *(*port_alloc)(void);
int (*port_construct)(struct ofport *ofport);
- void (*port_destruct)(struct ofport *ofport);
+ void (*port_destruct)(struct ofport *ofport, bool del);
void (*port_dealloc)(struct ofport *ofport);
/* Called after 'ofport->netdev' is replaced by a new netdev object. If
/* ofport. */
static void ofport_destroy__(struct ofport *) OVS_EXCLUDED(ofproto_mutex);
-static void ofport_destroy(struct ofport *);
+static void ofport_destroy(struct ofport *, bool del);
static int update_port(struct ofproto *, const char *devname);
static int init_ports(struct ofproto *);
}
void
-ofproto_destroy(struct ofproto *p)
+ofproto_destroy(struct ofproto *p, bool del)
OVS_EXCLUDED(ofproto_mutex)
{
struct ofport *ofport, *next_ofport;
ofproto_flush__(p);
HMAP_FOR_EACH_SAFE (ofport, next_ofport, hmap_node, &p->ports) {
- ofport_destroy(ofport);
+ ofport_destroy(ofport, del);
}
HMAP_FOR_EACH_SAFE (usage, next_usage, hmap_node, &p->ofport_usage) {
{
connmgr_send_port_status(ofport->ofproto->connmgr, NULL, &ofport->pp,
OFPPR_DELETE);
- ofport_destroy(ofport);
+ ofport_destroy(ofport, true);
}
/* If 'ofproto' contains an ofport named 'name', removes it from 'ofproto' and
}
static void
-ofport_destroy(struct ofport *port)
+ofport_destroy(struct ofport *port, bool del)
{
if (port) {
dealloc_ofp_port(port->ofproto, port->ofp_port);
- port->ofproto->ofproto_class->port_destruct(port);
+ port->ofproto->ofproto_class->port_destruct(port, del);
ofport_destroy__(port);
}
}
/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
int ofproto_create(const char *datapath, const char *datapath_type,
struct ofproto **ofprotop);
-void ofproto_destroy(struct ofproto *);
+void ofproto_destroy(struct ofproto *, bool del);
int ofproto_delete(const char *name, const char *type);
int ofproto_run(struct ofproto *);
static void add_del_bridges(const struct ovsrec_open_vswitch *);
static void bridge_run__(void);
static void bridge_create(const struct ovsrec_bridge *);
-static void bridge_destroy(struct bridge *);
+static void bridge_destroy(struct bridge *, bool del);
static struct bridge *bridge_lookup(const char *name);
static unixctl_cb_func bridge_unixctl_dump_flows;
static unixctl_cb_func bridge_unixctl_reconnect;
if_notifier_destroy(ifnotifier);
HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
- bridge_destroy(br);
+ bridge_destroy(br, false);
}
ovsdb_idl_destroy(idl);
}
VLOG_ERR("failed to create bridge %s: %s", br->name,
ovs_strerror(error));
shash_destroy(&br->wanted_ports);
- bridge_destroy(br);
+ bridge_destroy(br, true);
} else {
/* Trigger storing datapath version. */
seq_change(connectivity_seq_get());
br->cfg = shash_find_data(&new_br, br->name);
if (!br->cfg || strcmp(br->type, ofproto_normalize_type(
br->cfg->datapath_type))) {
- bridge_destroy(br);
+ bridge_destroy(br, true);
}
}
(long int) getpid());
HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
- bridge_destroy(br);
+ bridge_destroy(br, false);
}
/* Since we will not be running system_stats_run() in this process
* with the current situation of multiple ovs-vswitchd daemons,
}
static void
-bridge_destroy(struct bridge *br)
+bridge_destroy(struct bridge *br, bool del)
{
if (br) {
struct mirror *mirror, *next_mirror;
}
hmap_remove(&all_bridges, &br->node);
- ofproto_destroy(br->ofproto);
+ ofproto_destroy(br->ofproto, del);
hmap_destroy(&br->ifaces);
hmap_destroy(&br->ports);
hmap_destroy(&br->iface_by_name);