+ ports[(*n)++] = port;
+ return ports;
+}
+
+static void
+bridge_delete_or_reconfigure_ports(struct bridge *br)
+{
+ struct ofproto_port ofproto_port;
+ struct ofproto_port_dump dump;
+
+ struct sset ofproto_ports;
+ struct port *port, *port_next;
+
+ /* List of "ofp_port"s to delete. We make a list instead of deleting them
+ * right away because ofproto implementations aren't necessarily able to
+ * iterate through a changing list of ports in an entirely robust way. */
+ ofp_port_t *del;
+ size_t n, allocated;
+ size_t i;
+
+ del = NULL;
+ n = allocated = 0;
+ sset_init(&ofproto_ports);
+
+ /* Main task: Iterate over the ports in 'br->ofproto' and remove the ports
+ * that are not configured in the database. (This commonly happens when
+ * ports have been deleted, e.g. with "ovs-vsctl del-port".)
+ *
+ * Side tasks: Reconfigure the ports that are still in 'br'. Delete ports
+ * that have the wrong OpenFlow port number (and arrange to add them back
+ * with the correct OpenFlow port number). */
+ OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) {
+ ofp_port_t requested_ofp_port;
+ struct iface *iface;
+
+ sset_add(&ofproto_ports, ofproto_port.name);
+
+ iface = iface_lookup(br, ofproto_port.name);
+ if (!iface) {
+ /* No such iface is configured, so we should delete this
+ * ofproto_port.
+ *
+ * As a corner case exception, keep the port if it's a bond fake
+ * interface. */
+ if (bridge_has_bond_fake_iface(br, ofproto_port.name)
+ && !strcmp(ofproto_port.type, "internal")) {
+ continue;
+ }
+ goto delete;
+ }
+
+ if (strcmp(ofproto_port.type, iface->type)
+ || netdev_set_config(iface->netdev, &iface->cfg->options)) {
+ /* The interface is the wrong type or can't be configured.
+ * Delete it. */
+ goto delete;
+ }
+
+ /* If the requested OpenFlow port for 'iface' changed, and it's not
+ * already the correct port, then we might want to temporarily delete
+ * this interface, so we can add it back again with the new OpenFlow
+ * port number. */
+ requested_ofp_port = iface_get_requested_ofp_port(iface->cfg);
+ if (iface->ofp_port != OFPP_LOCAL &&
+ requested_ofp_port != OFPP_NONE &&
+ requested_ofp_port != iface->ofp_port) {
+ ofp_port_t victim_request;
+ struct iface *victim;
+
+ /* Check for an existing OpenFlow port currently occupying
+ * 'iface''s requested port number. If there isn't one, then
+ * delete this port. Otherwise we need to consider further. */
+ victim = iface_from_ofp_port(br, requested_ofp_port);
+ if (!victim) {
+ goto delete;
+ }
+
+ /* 'victim' is a port currently using 'iface''s requested port
+ * number. Unless 'victim' specifically requested that port
+ * number, too, then we can delete both 'iface' and 'victim'
+ * temporarily. (We'll add both of them back again later with new
+ * OpenFlow port numbers.)
+ *
+ * If 'victim' did request port number 'requested_ofp_port', just
+ * like 'iface', then that's a configuration inconsistency that we
+ * can't resolve. We might as well let it keep its current port
+ * number. */
+ victim_request = iface_get_requested_ofp_port(victim->cfg);
+ if (victim_request != requested_ofp_port) {
+ del = add_ofp_port(victim->ofp_port, del, &n, &allocated);
+ iface_destroy(victim);
+ goto delete;
+ }
+ }
+
+ /* Keep it. */
+ continue;
+
+ delete:
+ iface_destroy(iface);
+ del = add_ofp_port(ofproto_port.ofp_port, del, &n, &allocated);
+ }
+ for (i = 0; i < n; i++) {
+ ofproto_port_del(br->ofproto, del[i]);
+ }
+ free(del);
+
+ /* Iterate over this module's idea of interfaces in 'br'. Remove any ports
+ * that we didn't see when we iterated through the datapath, i.e. ports
+ * that disappeared underneath use. This is an unusual situation, but it
+ * can happen in some cases:
+ *
+ * - An admin runs a command like "ovs-dpctl del-port" (which is a bad
+ * idea but could happen).
+ *
+ * - The port represented a device that disappeared, e.g. a tuntap
+ * device destroyed via "tunctl -d", a physical Ethernet device
+ * whose module was just unloaded via "rmmod", or a virtual NIC for a
+ * VM whose VM was just terminated. */
+ HMAP_FOR_EACH_SAFE (port, port_next, hmap_node, &br->ports) {
+ struct iface *iface, *iface_next;
+
+ LIST_FOR_EACH_SAFE (iface, iface_next, port_elem, &port->ifaces) {
+ if (!sset_contains(&ofproto_ports, iface->name)) {
+ iface_destroy__(iface);
+ }
+ }
+
+ if (list_is_empty(&port->ifaces)) {
+ port_destroy(port);
+ }
+ }
+ sset_destroy(&ofproto_ports);
+}
+
+static void
+bridge_add_ports__(struct bridge *br, const struct shash *wanted_ports,
+ bool with_requested_port)
+{
+ struct shash_node *port_node;
+
+ SHASH_FOR_EACH (port_node, wanted_ports) {
+ const struct ovsrec_port *port_cfg = port_node->data;
+ size_t i;
+
+ for (i = 0; i < port_cfg->n_interfaces; i++) {
+ const struct ovsrec_interface *iface_cfg = port_cfg->interfaces[i];
+ ofp_port_t requested_ofp_port;
+
+ requested_ofp_port = iface_get_requested_ofp_port(iface_cfg);
+ if ((requested_ofp_port != OFPP_NONE) == with_requested_port) {
+ struct iface *iface = iface_lookup(br, iface_cfg->name);
+
+ if (!iface) {
+ iface_create(br, iface_cfg, port_cfg);
+ }
+ }
+ }
+ }
+}
+
+static void
+bridge_add_ports(struct bridge *br, const struct shash *wanted_ports)
+{
+ /* First add interfaces that request a particular port number. */
+ bridge_add_ports__(br, wanted_ports, true);
+
+ /* Then add interfaces that want automatic port number assignment.
+ * We add these afterward to avoid accidentally taking a specifically
+ * requested port number. */
+ bridge_add_ports__(br, wanted_ports, false);