-send_port_status(struct ofproto *p, const struct ofport *ofport,
- uint8_t reason)
-{
- /* XXX Should limit the number of queued port status change messages. */
- struct ofconn *ofconn;
- LIST_FOR_EACH (ofconn, node, &p->all_conns) {
- struct ofp_port_status *ops;
- struct ofpbuf *b;
-
- /* Primary controllers, even slaves, should always get port status
- updates. Otherwise obey ofconn_receives_async_msgs(). */
- if (ofconn->type != OFCONN_PRIMARY
- && !ofconn_receives_async_msgs(ofconn)) {
- continue;
- }
-
- ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &b);
- ops->reason = reason;
- ops->desc = ofport->opp;
- hton_ofp_phy_port(&ops->desc);
- queue_tx(b, ofconn, NULL);
- }
-}
-
-static void
-ofport_install(struct ofproto *p, struct ofport *ofport)
-{
- const char *netdev_name = ofport->opp.name;
-
- netdev_monitor_add(p->netdev_monitor, ofport->netdev);
- hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->odp_port, 0));
- shash_add(&p->port_by_name, netdev_name, ofport);
- if (p->sflow) {
- ofproto_sflow_add_port(p->sflow, ofport->odp_port, netdev_name);
- }
-}
-
-static void
-ofport_remove(struct ofproto *p, struct ofport *ofport)
-{
- netdev_monitor_remove(p->netdev_monitor, ofport->netdev);
- hmap_remove(&p->ports, &ofport->hmap_node);
- shash_delete(&p->port_by_name,
- shash_find(&p->port_by_name, ofport->opp.name));
- if (p->sflow) {
- ofproto_sflow_del_port(p->sflow, ofport->odp_port);
- }
-}
-
-static void
-ofport_free(struct ofport *ofport)
-{
- if (ofport) {
- netdev_close(ofport->netdev);
- free(ofport);
- }
-}
-
-static struct ofport *
-get_port(const struct ofproto *ofproto, uint16_t odp_port)
-{
- struct ofport *port;
-
- HMAP_FOR_EACH_IN_BUCKET (port, hmap_node,
- hash_int(odp_port, 0), &ofproto->ports) {
- if (port->odp_port == odp_port) {
- return port;
- }
- }
- return NULL;
-}
-
-static void
-update_port(struct ofproto *p, const char *devname)
-{
- struct odp_port odp_port;
- struct ofport *old_ofport;
- struct ofport *new_ofport;
- int error;
-
- COVERAGE_INC(ofproto_update_port);
-
- /* Query the datapath for port information. */
- error = dpif_port_query_by_name(p->dpif, devname, &odp_port);
-
- /* Find the old ofport. */
- old_ofport = shash_find_data(&p->port_by_name, devname);
- if (!error) {
- if (!old_ofport) {
- /* There's no port named 'devname' but there might be a port with
- * the same port number. This could happen if a port is deleted
- * and then a new one added in its place very quickly, or if a port
- * is renamed. In the former case we want to send an OFPPR_DELETE
- * and an OFPPR_ADD, and in the latter case we want to send a
- * single OFPPR_MODIFY. We can distinguish the cases by comparing
- * the old port's ifindex against the new port, or perhaps less
- * reliably but more portably by comparing the old port's MAC
- * against the new port's MAC. However, this code isn't that smart
- * and always sends an OFPPR_MODIFY (XXX). */
- old_ofport = get_port(p, odp_port.port);
- }
- } else if (error != ENOENT && error != ENODEV) {
- VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error "
- "%s", strerror(error));
- return;
- }
-
- /* Create a new ofport. */
- new_ofport = !error ? make_ofport(&odp_port) : NULL;
-
- /* Eliminate a few pathological cases. */
- if (!old_ofport && !new_ofport) {
- return;
- } else if (old_ofport && new_ofport) {
- /* Most of the 'config' bits are OpenFlow soft state, but
- * OFPPC_PORT_DOWN is maintained by the kernel. So transfer the
- * OpenFlow bits from old_ofport. (make_ofport() only sets
- * OFPPC_PORT_DOWN and leaves the other bits 0.) */
- new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN;
-
- if (ofport_equal(old_ofport, new_ofport)) {
- /* False alarm--no change. */
- ofport_free(new_ofport);
- return;
- }
- }
-
- /* Now deal with the normal cases. */
- if (old_ofport) {
- ofport_remove(p, old_ofport);
- }
- if (new_ofport) {
- ofport_install(p, new_ofport);
- }
- send_port_status(p, new_ofport ? new_ofport : old_ofport,
- (!old_ofport ? OFPPR_ADD
- : !new_ofport ? OFPPR_DELETE
- : OFPPR_MODIFY));
- ofport_free(old_ofport);
-}
-
-static int
-init_ports(struct ofproto *p)