-
- /* Choose the MAC address to represent the port. */
- if (port->cfg->mac && eth_addr_from_string(port->cfg->mac, iface_ea)) {
- /* Find the interface with this Ethernet address (if any) so that
- * we can provide the correct devname to the caller. */
- iface = NULL;
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *candidate = port->ifaces[j];
- uint8_t candidate_ea[ETH_ADDR_LEN];
- if (!netdev_get_etheraddr(candidate->netdev, candidate_ea)
- && eth_addr_equals(iface_ea, candidate_ea)) {
- iface = candidate;
- }
- }
- } else {
- /* Choose the interface whose MAC address will represent the port.
- * The Linux kernel bonding code always chooses the MAC address of
- * the first slave added to a bond, and the Fedora networking
- * scripts always add slaves to a bond in alphabetical order, so
- * for compatibility we choose the interface with the name that is
- * first in alphabetical order. */
- iface = port->ifaces[0];
- for (j = 1; j < port->n_ifaces; j++) {
- struct iface *candidate = port->ifaces[j];
- if (strcmp(candidate->name, iface->name) < 0) {
- iface = candidate;
- }
- }
-
- /* The local port doesn't count (since we're trying to choose its
- * MAC address anyway). */
- if (iface->dp_ifidx == ODPP_LOCAL) {
- continue;
- }
-
- /* Grab MAC. */
- error = netdev_get_etheraddr(iface->netdev, iface_ea);
- if (error) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_ERR_RL(&rl, "failed to obtain Ethernet address of %s: %s",
- iface->name, strerror(error));
- continue;
- }
- }
-
- /* Compare against our current choice. */
- if (!eth_addr_is_multicast(iface_ea) &&
- !eth_addr_is_local(iface_ea) &&
- !eth_addr_is_reserved(iface_ea) &&
- !eth_addr_is_zero(iface_ea) &&
- eth_addr_compare_3way(iface_ea, ea) < 0)
- {
- memcpy(ea, iface_ea, ETH_ADDR_LEN);
- *hw_addr_iface = iface;
- }
- }
- if (eth_addr_is_multicast(ea)) {
- memcpy(ea, br->default_ea, ETH_ADDR_LEN);
- *hw_addr_iface = NULL;
- VLOG_WARN("bridge %s: using default bridge Ethernet "
- "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
- } else {
- VLOG_DBG("bridge %s: using bridge Ethernet address "ETH_ADDR_FMT,
- br->name, ETH_ADDR_ARGS(ea));
- }
-}
-
-/* Choose and returns the datapath ID for bridge 'br' given that the bridge
- * Ethernet address is 'bridge_ea'. If 'bridge_ea' is the Ethernet address of
- * an interface on 'br', then that interface must be passed in as
- * 'hw_addr_iface'; if 'bridge_ea' was derived some other way, then
- * 'hw_addr_iface' must be passed in as a null pointer. */
-static uint64_t
-bridge_pick_datapath_id(struct bridge *br,
- const uint8_t bridge_ea[ETH_ADDR_LEN],
- struct iface *hw_addr_iface)
-{
- /*
- * The procedure for choosing a bridge MAC address will, in the most
- * ordinary case, also choose a unique MAC that we can use as a datapath
- * ID. In some special cases, though, multiple bridges will end up with
- * the same MAC address. This is OK for the bridges, but it will confuse
- * the OpenFlow controller, because each datapath needs a unique datapath
- * ID.
- *
- * Datapath IDs must be unique. It is also very desirable that they be
- * stable from one run to the next, so that policy set on a datapath
- * "sticks".
- */
- const char *datapath_id;
- uint64_t dpid;
-
- datapath_id = bridge_get_other_config(br->cfg, "datapath-id");
- if (datapath_id && dpid_from_string(datapath_id, &dpid)) {
- return dpid;
- }
-
- if (hw_addr_iface) {
- int vlan;
- if (!netdev_get_vlan_vid(hw_addr_iface->netdev, &vlan)) {
- /*
- * A bridge whose MAC address is taken from a VLAN network device
- * (that is, a network device created with vconfig(8) or similar
- * tool) will have the same MAC address as a bridge on the VLAN
- * device's physical network device.
- *
- * Handle this case by hashing the physical network device MAC
- * along with the VLAN identifier.
- */
- uint8_t buf[ETH_ADDR_LEN + 2];
- memcpy(buf, bridge_ea, ETH_ADDR_LEN);
- buf[ETH_ADDR_LEN] = vlan >> 8;
- buf[ETH_ADDR_LEN + 1] = vlan;
- return dpid_from_hash(buf, sizeof buf);
- } else {
- /*
- * Assume that this bridge's MAC address is unique, since it
- * doesn't fit any of the cases we handle specially.
- */
- }
- } else {
- /*
- * A purely internal bridge, that is, one that has no non-virtual
- * network devices on it at all, is more difficult because it has no
- * natural unique identifier at all.
- *
- * When the host is a XenServer, we handle this case by hashing the
- * host's UUID with the name of the bridge. Names of bridges are
- * persistent across XenServer reboots, although they can be reused if
- * an internal network is destroyed and then a new one is later
- * created, so this is fairly effective.
- *
- * When the host is not a XenServer, we punt by using a random MAC
- * address on each run.
- */
- const char *host_uuid = xenserver_get_host_uuid();
- if (host_uuid) {
- char *combined = xasprintf("%s,%s", host_uuid, br->name);
- dpid = dpid_from_hash(combined, strlen(combined));
- free(combined);
- return dpid;
- }
- }
-
- return eth_addr_to_uint64(bridge_ea);
-}
-
-static uint64_t
-dpid_from_hash(const void *data, size_t n)
-{
- uint8_t hash[SHA1_DIGEST_SIZE];
-
- BUILD_ASSERT_DECL(sizeof hash >= ETH_ADDR_LEN);
- sha1_bytes(data, n, hash);
- eth_addr_mark_random(hash);
- return eth_addr_to_uint64(hash);
-}
-
-static void
-iface_refresh_status(struct iface *iface)
-{
- struct shash sh;
-
- enum netdev_flags flags;
- uint32_t current;
- int64_t bps;
- int mtu;
- int64_t mtu_64;
- int error;
-
- shash_init(&sh);
-
- if (!netdev_get_status(iface->netdev, &sh)) {
- size_t n;
- char **keys, **values;
-
- shash_to_ovs_idl_map(&sh, &keys, &values, &n);
- ovsrec_interface_set_status(iface->cfg, keys, values, n);
-
- free(keys);
- free(values);
- } else {
- ovsrec_interface_set_status(iface->cfg, NULL, NULL, 0);
- }
-
- shash_destroy_free_data(&sh);
-
- error = netdev_get_flags(iface->netdev, &flags);
- if (!error) {
- ovsrec_interface_set_admin_state(iface->cfg, flags & NETDEV_UP ? "up" : "down");
- }
- else {
- ovsrec_interface_set_admin_state(iface->cfg, NULL);
- }
-
- error = netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL);
- if (!error) {
- ovsrec_interface_set_duplex(iface->cfg,
- netdev_features_is_full_duplex(current)
- ? "full" : "half");
- /* warning: uint64_t -> int64_t conversion */
- bps = netdev_features_to_bps(current);
- ovsrec_interface_set_link_speed(iface->cfg, &bps, 1);
- }
- else {
- ovsrec_interface_set_duplex(iface->cfg, NULL);
- ovsrec_interface_set_link_speed(iface->cfg, NULL, 0);
- }
-
-
- ovsrec_interface_set_link_state(iface->cfg,
- netdev_get_carrier(iface->netdev)
- ? "up" : "down");
-
- error = netdev_get_mtu(iface->netdev, &mtu);
- if (!error && mtu != INT_MAX) {
- mtu_64 = mtu;
- ovsrec_interface_set_mtu(iface->cfg, &mtu_64, 1);
- }
- else {
- ovsrec_interface_set_mtu(iface->cfg, NULL, 0);
- }
-}
-
-static void
-iface_refresh_cfm_stats(struct iface *iface)
-{
- size_t i;
- struct cfm *cfm;
- const struct ovsrec_monitor *mon;
-
- mon = iface->cfg->monitor;
- cfm = iface->cfm;
-
- if (!cfm || !mon) {
- return;
- }
-
- for (i = 0; i < mon->n_remote_mps; i++) {
- const struct ovsrec_maintenance_point *mp;
- const struct remote_mp *rmp;
-
- mp = mon->remote_mps[i];
- rmp = cfm_get_remote_mp(cfm, mp->mpid);
-
- ovsrec_maintenance_point_set_fault(mp, &rmp->fault, 1);
- }
-
- if (hmap_is_empty(&cfm->x_remote_mps)) {
- ovsrec_monitor_set_unexpected_remote_mpids(mon, NULL, 0);
- } else {
- size_t length;
- struct remote_mp *rmp;
- int64_t *x_remote_mps;
-
- length = hmap_count(&cfm->x_remote_mps);
- x_remote_mps = xzalloc(length * sizeof *x_remote_mps);
-
- i = 0;
- HMAP_FOR_EACH (rmp, node, &cfm->x_remote_mps) {
- x_remote_mps[i++] = rmp->mpid;
- }
-
- ovsrec_monitor_set_unexpected_remote_mpids(mon, x_remote_mps, length);
- free(x_remote_mps);
- }
-
- if (hmap_is_empty(&cfm->x_remote_maids)) {
- ovsrec_monitor_set_unexpected_remote_maids(mon, NULL, 0);
- } else {
- size_t length;
- char **x_remote_maids;
- struct remote_maid *rmaid;
-
- length = hmap_count(&cfm->x_remote_maids);
- x_remote_maids = xzalloc(length * sizeof *x_remote_maids);
-
- i = 0;
- HMAP_FOR_EACH (rmaid, node, &cfm->x_remote_maids) {
- size_t j;
-
- x_remote_maids[i] = xzalloc(CCM_MAID_LEN * 2 + 1);
-
- for (j = 0; j < CCM_MAID_LEN; j++) {
- snprintf(&x_remote_maids[i][j * 2], 3, "%02hhx",
- rmaid->maid[j]);
- }
- i++;
- }
- ovsrec_monitor_set_unexpected_remote_maids(mon, x_remote_maids, length);
-
- for (i = 0; i < length; i++) {
- free(x_remote_maids[i]);
- }
- free(x_remote_maids);
- }
-
- ovsrec_monitor_set_fault(mon, &cfm->fault, 1);
-}
-
-static void
-iface_refresh_stats(struct iface *iface)
-{
- struct iface_stat {
- char *name;
- int offset;
- };
- static const struct iface_stat iface_stats[] = {
- { "rx_packets", offsetof(struct netdev_stats, rx_packets) },
- { "tx_packets", offsetof(struct netdev_stats, tx_packets) },
- { "rx_bytes", offsetof(struct netdev_stats, rx_bytes) },
- { "tx_bytes", offsetof(struct netdev_stats, tx_bytes) },
- { "rx_dropped", offsetof(struct netdev_stats, rx_dropped) },
- { "tx_dropped", offsetof(struct netdev_stats, tx_dropped) },
- { "rx_errors", offsetof(struct netdev_stats, rx_errors) },
- { "tx_errors", offsetof(struct netdev_stats, tx_errors) },
- { "rx_frame_err", offsetof(struct netdev_stats, rx_frame_errors) },
- { "rx_over_err", offsetof(struct netdev_stats, rx_over_errors) },
- { "rx_crc_err", offsetof(struct netdev_stats, rx_crc_errors) },
- { "collisions", offsetof(struct netdev_stats, collisions) },
- };
- enum { N_STATS = ARRAY_SIZE(iface_stats) };
- const struct iface_stat *s;
-
- char *keys[N_STATS];
- int64_t values[N_STATS];
- int n;
-
- struct netdev_stats stats;
-
- /* Intentionally ignore return value, since errors will set 'stats' to
- * all-1s, and we will deal with that correctly below. */
- netdev_get_stats(iface->netdev, &stats);
-
- n = 0;
- for (s = iface_stats; s < &iface_stats[N_STATS]; s++) {
- uint64_t value = *(uint64_t *) (((char *) &stats) + s->offset);
- if (value != UINT64_MAX) {
- keys[n] = s->name;
- values[n] = value;
- n++;
- }
- }
-
- ovsrec_interface_set_statistics(iface->cfg, keys, values, n);
-}
-
-static void
-refresh_system_stats(const struct ovsrec_open_vswitch *cfg)
-{
- struct ovsdb_datum datum;
- struct shash stats;
-
- shash_init(&stats);
- get_system_stats(&stats);
-
- ovsdb_datum_from_shash(&datum, &stats);
- ovsdb_idl_txn_write(&cfg->header_, &ovsrec_open_vswitch_col_statistics,
- &datum);
-}
-
-static inline const char *
-nx_role_to_str(enum nx_role role)
-{
- switch (role) {
- case NX_ROLE_OTHER:
- return "other";
- case NX_ROLE_MASTER:
- return "master";
- case NX_ROLE_SLAVE:
- return "slave";
- default:
- return "*** INVALID ROLE ***";
- }
-}
-
-static void
-bridge_refresh_controller_status(const struct bridge *br)
-{
- struct shash info;
- const struct ovsrec_controller *cfg;
-
- ofproto_get_ofproto_controller_info(br->ofproto, &info);
-
- OVSREC_CONTROLLER_FOR_EACH(cfg, idl) {
- struct ofproto_controller_info *cinfo =
- shash_find_data(&info, cfg->target);
-
- if (cinfo) {
- ovsrec_controller_set_is_connected(cfg, cinfo->is_connected);
- ovsrec_controller_set_role(cfg, nx_role_to_str(cinfo->role));
- ovsrec_controller_set_status(cfg, (char **) cinfo->pairs.keys,
- (char **) cinfo->pairs.values,
- cinfo->pairs.n);
- } else {
- ovsrec_controller_set_is_connected(cfg, false);
- ovsrec_controller_set_role(cfg, NULL);
- ovsrec_controller_set_status(cfg, NULL, NULL, 0);
- }
- }
-
- ofproto_free_ofproto_controller_info(&info);
-}
-
-void
-bridge_run(void)
-{
- const struct ovsrec_open_vswitch *cfg;
-
- bool datapath_destroyed;
- bool database_changed;
- struct bridge *br;
-
- /* Let each bridge do the work that it needs to do. */
- datapath_destroyed = false;
- LIST_FOR_EACH (br, node, &all_bridges) {
- int error = bridge_run_one(br);
- if (error) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_ERR_RL(&rl, "bridge %s: datapath was destroyed externally, "
- "forcing reconfiguration", br->name);
- datapath_destroyed = true;
- }
- }
-
- /* (Re)configure if necessary. */
- database_changed = ovsdb_idl_run(idl);
- cfg = ovsrec_open_vswitch_first(idl);
-#ifdef HAVE_OPENSSL
- /* Re-configure SSL. We do this on every trip through the main loop,
- * instead of just when the database changes, because the contents of the
- * key and certificate files can change without the database changing.
- *
- * We do this before bridge_reconfigure() because that function might
- * initiate SSL connections and thus requires SSL to be configured. */
- if (cfg && cfg->ssl) {
- const struct ovsrec_ssl *ssl = cfg->ssl;
-
- stream_ssl_set_key_and_cert(ssl->private_key, ssl->certificate);
- stream_ssl_set_ca_cert_file(ssl->ca_cert, ssl->bootstrap_ca_cert);
- }
-#endif
- if (database_changed || datapath_destroyed) {
- if (cfg) {
- struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl);
-
- bridge_configure_once(cfg);
- bridge_reconfigure(cfg);
-
- ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg);
- ovsdb_idl_txn_commit(txn);
- ovsdb_idl_txn_destroy(txn); /* XXX */
- } else {
- /* We still need to reconfigure to avoid dangling pointers to
- * now-destroyed ovsrec structures inside bridge data. */
- static const struct ovsrec_open_vswitch null_cfg;
-
- bridge_reconfigure(&null_cfg);
- }
- }
-
- /* Refresh system and interface stats if necessary. */
- if (time_msec() >= stats_timer) {
- if (cfg) {
- struct ovsdb_idl_txn *txn;
-
- txn = ovsdb_idl_txn_create(idl);
- LIST_FOR_EACH (br, node, &all_bridges) {
- size_t i;
-
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
- size_t j;
-
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- iface_refresh_stats(iface);
- iface_refresh_cfm_stats(iface);
- iface_refresh_status(iface);
- }
- }
- bridge_refresh_controller_status(br);
- }
- refresh_system_stats(cfg);
- ovsdb_idl_txn_commit(txn);
- ovsdb_idl_txn_destroy(txn); /* XXX */
- }
-
- stats_timer = time_msec() + STATS_INTERVAL;
- }
-}
-
-void
-bridge_wait(void)
-{
- struct bridge *br;
-
- LIST_FOR_EACH (br, node, &all_bridges) {
- size_t i;
-
- ofproto_wait(br->ofproto);
- if (ofproto_has_primary_controller(br->ofproto)) {
- continue;
- }
-
- mac_learning_wait(br->ml);
-
- for (i = 0; i < br->n_ports; i++) {
- port_wait(br->ports[i]);
- }
- }
- ovsdb_idl_wait(idl);
- poll_timer_wait_until(stats_timer);
-}
-
-/* Forces 'br' to revalidate all of its flows. This is appropriate when 'br''s
- * configuration changes. */
-static void
-bridge_flush(struct bridge *br)
-{
- COVERAGE_INC(bridge_flush);
- br->flush = true;
- mac_learning_flush(br->ml);
-}
-
-/* Returns the 'br' interface for the ODPP_LOCAL port, or null if 'br' has no
- * such interface. */
-static struct iface *
-bridge_get_local_iface(struct bridge *br)
-{
- size_t i, j;
-
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- if (iface->dp_ifidx == ODPP_LOCAL) {
- return iface;
- }
- }
- }
-
- return NULL;
-}
-\f
-/* Bridge unixctl user interface functions. */
-static void
-bridge_unixctl_fdb_show(struct unixctl_conn *conn,
- const char *args, void *aux OVS_UNUSED)
-{
- struct ds ds = DS_EMPTY_INITIALIZER;
- const struct bridge *br;
- const struct mac_entry *e;
-
- br = bridge_lookup(args);
- if (!br) {
- unixctl_command_reply(conn, 501, "no such bridge");
- return;
- }
-
- ds_put_cstr(&ds, " port VLAN MAC Age\n");
- LIST_FOR_EACH (e, lru_node, &br->ml->lrus) {
- if (e->port < 0 || e->port >= br->n_ports) {
- continue;
- }
- ds_put_format(&ds, "%5d %4d "ETH_ADDR_FMT" %3d\n",
- br->ports[e->port]->ifaces[0]->dp_ifidx,
- e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
- }
- unixctl_command_reply(conn, 200, ds_cstr(&ds));
- ds_destroy(&ds);
-}
-\f
-/* QoS unixctl user interface functions. */
-
-struct qos_unixctl_show_cbdata {
- struct ds *ds;
- struct iface *iface;
-};
-
-static void
-qos_unixctl_show_cb(unsigned int queue_id,
- const struct shash *details,
- void *aux)
-{
- struct qos_unixctl_show_cbdata *data = aux;
- struct ds *ds = data->ds;
- struct iface *iface = data->iface;
- struct netdev_queue_stats stats;
- struct shash_node *node;
- int error;
-
- ds_put_cstr(ds, "\n");
- if (queue_id) {
- ds_put_format(ds, "Queue %u:\n", queue_id);
- } else {
- ds_put_cstr(ds, "Default:\n");
- }
-
- SHASH_FOR_EACH (node, details) {
- ds_put_format(ds, "\t%s: %s\n", node->name, (char *)node->data);
- }
-
- error = netdev_get_queue_stats(iface->netdev, queue_id, &stats);
- if (!error) {
- if (stats.tx_packets != UINT64_MAX) {
- ds_put_format(ds, "\ttx_packets: %"PRIu64"\n", stats.tx_packets);
- }
-
- if (stats.tx_bytes != UINT64_MAX) {
- ds_put_format(ds, "\ttx_bytes: %"PRIu64"\n", stats.tx_bytes);
- }
-
- if (stats.tx_errors != UINT64_MAX) {
- ds_put_format(ds, "\ttx_errors: %"PRIu64"\n", stats.tx_errors);
- }
- } else {
- ds_put_format(ds, "\tFailed to get statistics for queue %u: %s",
- queue_id, strerror(error));
- }
-}
-
-static void
-qos_unixctl_show(struct unixctl_conn *conn,
- const char *args, void *aux OVS_UNUSED)
-{
- struct ds ds = DS_EMPTY_INITIALIZER;
- struct shash sh = SHASH_INITIALIZER(&sh);
- struct iface *iface;
- const char *type;
- struct shash_node *node;
- struct qos_unixctl_show_cbdata data;
- int error;
-
- iface = iface_find(args);
- if (!iface) {
- unixctl_command_reply(conn, 501, "no such interface");
- return;
- }
-
- netdev_get_qos(iface->netdev, &type, &sh);
-
- if (*type != '\0') {
- ds_put_format(&ds, "QoS: %s %s\n", iface->name, type);
-
- SHASH_FOR_EACH (node, &sh) {
- ds_put_format(&ds, "%s: %s\n", node->name, (char *)node->data);
- }
-
- data.ds = &ds;
- data.iface = iface;
- error = netdev_dump_queues(iface->netdev, qos_unixctl_show_cb, &data);
-
- if (error) {
- ds_put_format(&ds, "failed to dump queues: %s", strerror(error));
- }
- unixctl_command_reply(conn, 200, ds_cstr(&ds));
- } else {
- ds_put_format(&ds, "QoS not configured on %s\n", iface->name);
- unixctl_command_reply(conn, 501, ds_cstr(&ds));
- }
-
- shash_destroy_free_data(&sh);
- ds_destroy(&ds);
-}
-\f
-/* Bridge reconfiguration functions. */
-static struct bridge *
-bridge_create(const struct ovsrec_bridge *br_cfg)
-{
- struct bridge *br;
- int error;
-
- assert(!bridge_lookup(br_cfg->name));
- br = xzalloc(sizeof *br);
-
- error = dpif_create_and_open(br_cfg->name, br_cfg->datapath_type,
- &br->dpif);
- if (error) {
- free(br);
- return NULL;
- }
- dpif_flow_flush(br->dpif);
-
- error = ofproto_create(br_cfg->name, br_cfg->datapath_type, &bridge_ofhooks,
- br, &br->ofproto);
- if (error) {
- VLOG_ERR("failed to create switch %s: %s", br_cfg->name,
- strerror(error));
- dpif_delete(br->dpif);
- dpif_close(br->dpif);
- free(br);
- return NULL;
- }
-
- br->name = xstrdup(br_cfg->name);
- br->cfg = br_cfg;
- br->ml = mac_learning_create();
- eth_addr_nicira_random(br->default_ea);
-
- hmap_init(&br->ifaces);
-
- shash_init(&br->port_by_name);
- shash_init(&br->iface_by_name);
-
- br->flush = false;
-
- list_push_back(&all_bridges, &br->node);
-
- VLOG_INFO("created bridge %s on %s", br->name, dpif_name(br->dpif));
-
- return br;
-}
-
-static void
-bridge_destroy(struct bridge *br)
-{
- if (br) {
- int error;
-
- while (br->n_ports > 0) {
- port_destroy(br->ports[br->n_ports - 1]);
- }
- list_remove(&br->node);
- error = dpif_delete(br->dpif);
- if (error && error != ENOENT) {
- VLOG_ERR("failed to delete %s: %s",
- dpif_name(br->dpif), strerror(error));
- }
- dpif_close(br->dpif);
- ofproto_destroy(br->ofproto);
- mac_learning_destroy(br->ml);
- hmap_destroy(&br->ifaces);
- shash_destroy(&br->port_by_name);
- shash_destroy(&br->iface_by_name);
- free(br->ports);
- free(br->name);
- free(br);
- }
-}
-
-static struct bridge *
-bridge_lookup(const char *name)
-{
- struct bridge *br;
-
- LIST_FOR_EACH (br, node, &all_bridges) {
- if (!strcmp(br->name, name)) {
- return br;
- }
- }
- return NULL;
-}
-
-/* Handle requests for a listing of all flows known by the OpenFlow
- * stack, including those normally hidden. */
-static void
-bridge_unixctl_dump_flows(struct unixctl_conn *conn,
- const char *args, void *aux OVS_UNUSED)
-{
- struct bridge *br;
- struct ds results;
-
- br = bridge_lookup(args);
- if (!br) {
- unixctl_command_reply(conn, 501, "Unknown bridge");
- return;
- }
-
- ds_init(&results);
- ofproto_get_all_flows(br->ofproto, &results);
-
- unixctl_command_reply(conn, 200, ds_cstr(&results));
- ds_destroy(&results);
-}
-
-/* "bridge/reconnect [BRIDGE]": makes BRIDGE drop all of its controller
- * connections and reconnect. If BRIDGE is not specified, then all bridges
- * drop their controller connections and reconnect. */
-static void
-bridge_unixctl_reconnect(struct unixctl_conn *conn,
- const char *args, void *aux OVS_UNUSED)
-{
- struct bridge *br;
- if (args[0] != '\0') {
- br = bridge_lookup(args);
- if (!br) {
- unixctl_command_reply(conn, 501, "Unknown bridge");
- return;
- }
- ofproto_reconnect_controllers(br->ofproto);
- } else {
- LIST_FOR_EACH (br, node, &all_bridges) {
- ofproto_reconnect_controllers(br->ofproto);
- }
- }
- unixctl_command_reply(conn, 200, NULL);
-}
-
-static int
-bridge_run_one(struct bridge *br)
-{
- size_t i;
- int error;
-
- error = ofproto_run1(br->ofproto);
- if (error) {
- return error;
- }
-
- mac_learning_run(br->ml, ofproto_get_revalidate_set(br->ofproto));
-
- for (i = 0; i < br->n_ports; i++) {
- port_run(br->ports[i]);
- }
-
- error = ofproto_run2(br->ofproto, br->flush);
- br->flush = false;
-
- return error;
-}
-
-static size_t
-bridge_get_controllers(const struct bridge *br,
- struct ovsrec_controller ***controllersp)
-{
- struct ovsrec_controller **controllers;
- size_t n_controllers;
-
- controllers = br->cfg->controller;
- n_controllers = br->cfg->n_controller;
-
- if (n_controllers == 1 && !strcmp(controllers[0]->target, "none")) {
- controllers = NULL;
- n_controllers = 0;
- }
-
- if (controllersp) {
- *controllersp = controllers;
- }
- return n_controllers;
-}
-
-static void
-bridge_reconfigure_one(struct bridge *br)
-{
- struct shash old_ports, new_ports;
- struct svec snoops, old_snoops;
- struct shash_node *node;
- enum ofproto_fail_mode fail_mode;
- size_t i;
-
- /* Collect old ports. */
- shash_init(&old_ports);
- for (i = 0; i < br->n_ports; i++) {
- shash_add(&old_ports, br->ports[i]->name, br->ports[i]);
- }
-
- /* Collect new ports. */
- shash_init(&new_ports);
- for (i = 0; i < br->cfg->n_ports; i++) {
- const char *name = br->cfg->ports[i]->name;
- if (!shash_add_once(&new_ports, name, br->cfg->ports[i])) {
- VLOG_WARN("bridge %s: %s specified twice as bridge port",
- br->name, name);
- }
- }
-
- /* If we have a controller, then we need a local port. Complain if the
- * user didn't specify one.
- *
- * XXX perhaps we should synthesize a port ourselves in this case. */
- if (bridge_get_controllers(br, NULL)) {
- char local_name[IF_NAMESIZE];
- int error;
-
- error = dpif_port_get_name(br->dpif, ODPP_LOCAL,
- local_name, sizeof local_name);
- if (!error && !shash_find(&new_ports, local_name)) {
- VLOG_WARN("bridge %s: controller specified but no local port "
- "(port named %s) defined",
- br->name, local_name);
- }
- }
-
- /* Get rid of deleted ports.
- * Get rid of deleted interfaces on ports that still exist. */
- SHASH_FOR_EACH (node, &old_ports) {
- struct port *port = node->data;
- const struct ovsrec_port *port_cfg;
-
- port_cfg = shash_find_data(&new_ports, node->name);
- if (!port_cfg) {
- port_destroy(port);
- } else {
- port_del_ifaces(port, port_cfg);
- }
- }
-
- /* Create new ports.
- * Add new interfaces to existing ports.
- * Reconfigure existing ports. */
- SHASH_FOR_EACH (node, &new_ports) {
- struct port *port = shash_find_data(&old_ports, node->name);
- if (!port) {
- port = port_create(br, node->name);
- }
-
- port_reconfigure(port, node->data);
- if (!port->n_ifaces) {
- VLOG_WARN("bridge %s: port %s has no interfaces, dropping",
- br->name, port->name);
- port_destroy(port);
- }
- }
- shash_destroy(&old_ports);
- shash_destroy(&new_ports);
-
- /* Set the fail-mode */
- fail_mode = !br->cfg->fail_mode
- || !strcmp(br->cfg->fail_mode, "standalone")
- ? OFPROTO_FAIL_STANDALONE
- : OFPROTO_FAIL_SECURE;
- if (ofproto_get_fail_mode(br->ofproto) != fail_mode
- && !ofproto_has_primary_controller(br->ofproto)) {
- ofproto_flush_flows(br->ofproto);
- }
- ofproto_set_fail_mode(br->ofproto, fail_mode);
-
- /* Delete all flows if we're switching from connected to standalone or vice
- * versa. (XXX Should we delete all flows if we are switching from one
- * controller to another?) */
-
- /* Configure OpenFlow controller connection snooping. */
- svec_init(&snoops);
- svec_add_nocopy(&snoops, xasprintf("punix:%s/%s.snoop",
- ovs_rundir(), br->name));
- svec_init(&old_snoops);
- ofproto_get_snoops(br->ofproto, &old_snoops);
- if (!svec_equal(&snoops, &old_snoops)) {
- ofproto_set_snoops(br->ofproto, &snoops);
- }
- svec_destroy(&snoops);
- svec_destroy(&old_snoops);
-
- mirror_reconfigure(br);
-}
-
-/* Initializes 'oc' appropriately as a management service controller for
- * 'br'.
- *
- * The caller must free oc->target when it is no longer needed. */
-static void
-bridge_ofproto_controller_for_mgmt(const struct bridge *br,
- struct ofproto_controller *oc)
-{
- oc->target = xasprintf("punix:%s/%s.mgmt", ovs_rundir(), br->name);
- oc->max_backoff = 0;
- oc->probe_interval = 60;
- oc->band = OFPROTO_OUT_OF_BAND;
- oc->rate_limit = 0;
- oc->burst_limit = 0;
-}
-
-/* Converts ovsrec_controller 'c' into an ofproto_controller in 'oc'. */
-static void
-bridge_ofproto_controller_from_ovsrec(const struct ovsrec_controller *c,
- struct ofproto_controller *oc)
-{
- oc->target = c->target;
- oc->max_backoff = c->max_backoff ? *c->max_backoff / 1000 : 8;
- oc->probe_interval = c->inactivity_probe ? *c->inactivity_probe / 1000 : 5;
- oc->band = (!c->connection_mode || !strcmp(c->connection_mode, "in-band")
- ? OFPROTO_IN_BAND : OFPROTO_OUT_OF_BAND);
- oc->rate_limit = c->controller_rate_limit ? *c->controller_rate_limit : 0;
- oc->burst_limit = (c->controller_burst_limit
- ? *c->controller_burst_limit : 0);
-}
-
-/* Configures the IP stack for 'br''s local interface properly according to the
- * configuration in 'c'. */
-static void
-bridge_configure_local_iface_netdev(struct bridge *br,
- struct ovsrec_controller *c)
-{
- struct netdev *netdev;
- struct in_addr mask, gateway;
-
- struct iface *local_iface;
- struct in_addr ip;
-
- /* If there's no local interface or no IP address, give up. */
- local_iface = bridge_get_local_iface(br);
- if (!local_iface || !c->local_ip || !inet_aton(c->local_ip, &ip)) {
- return;
- }
-
- /* Bring up the local interface. */
- netdev = local_iface->netdev;
- netdev_turn_flags_on(netdev, NETDEV_UP, true);
-
- /* Configure the IP address and netmask. */
- if (!c->local_netmask
- || !inet_aton(c->local_netmask, &mask)
- || !mask.s_addr) {
- mask.s_addr = guess_netmask(ip.s_addr);
- }
- if (!netdev_set_in4(netdev, ip, mask)) {
- VLOG_INFO("bridge %s: configured IP address "IP_FMT", netmask "IP_FMT,
- br->name, IP_ARGS(&ip.s_addr), IP_ARGS(&mask.s_addr));
- }
-
- /* Configure the default gateway. */
- if (c->local_gateway
- && inet_aton(c->local_gateway, &gateway)
- && gateway.s_addr) {
- if (!netdev_add_router(netdev, gateway)) {
- VLOG_INFO("bridge %s: configured gateway "IP_FMT,
- br->name, IP_ARGS(&gateway.s_addr));
- }
- }
-}
-
-static void
-bridge_reconfigure_remotes(struct bridge *br,
- const struct sockaddr_in *managers,
- size_t n_managers)
-{
- const char *disable_ib_str, *queue_id_str;
- bool disable_in_band = false;
- int queue_id;
-
- struct ovsrec_controller **controllers;
- size_t n_controllers;
- bool had_primary;
-
- struct ofproto_controller *ocs;
- size_t n_ocs;
- size_t i;
-
- /* Check if we should disable in-band control on this bridge. */
- disable_ib_str = bridge_get_other_config(br->cfg, "disable-in-band");
- if (disable_ib_str && !strcmp(disable_ib_str, "true")) {
- disable_in_band = true;
- }
-
- /* Set OpenFlow queue ID for in-band control. */
- queue_id_str = bridge_get_other_config(br->cfg, "in-band-queue");
- queue_id = queue_id_str ? strtol(queue_id_str, NULL, 10) : -1;
- ofproto_set_in_band_queue(br->ofproto, queue_id);
-
- if (disable_in_band) {
- ofproto_set_extra_in_band_remotes(br->ofproto, NULL, 0);
- } else {
- ofproto_set_extra_in_band_remotes(br->ofproto, managers, n_managers);
- }
- had_primary = ofproto_has_primary_controller(br->ofproto);
-
- n_controllers = bridge_get_controllers(br, &controllers);
-
- ocs = xmalloc((n_controllers + 1) * sizeof *ocs);
- n_ocs = 0;
-
- bridge_ofproto_controller_for_mgmt(br, &ocs[n_ocs++]);
- for (i = 0; i < n_controllers; i++) {
- struct ovsrec_controller *c = controllers[i];
-
- if (!strncmp(c->target, "punix:", 6)
- || !strncmp(c->target, "unix:", 5)) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-
- /* Prevent remote ovsdb-server users from accessing arbitrary Unix
- * domain sockets and overwriting arbitrary local files. */
- VLOG_ERR_RL(&rl, "%s: not adding Unix domain socket controller "
- "\"%s\" due to possibility for remote exploit",
- dpif_name(br->dpif), c->target);
- continue;
- }
-
- bridge_configure_local_iface_netdev(br, c);
- bridge_ofproto_controller_from_ovsrec(c, &ocs[n_ocs]);
- if (disable_in_band) {
- ocs[n_ocs].band = OFPROTO_OUT_OF_BAND;
- }
- n_ocs++;
- }
-
- ofproto_set_controllers(br->ofproto, ocs, n_ocs);
- free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */
- free(ocs);
-
- if (had_primary != ofproto_has_primary_controller(br->ofproto)) {
- ofproto_flush_flows(br->ofproto);
- }
-
- /* If there are no controllers and the bridge is in standalone
- * mode, set up a flow that matches every packet and directs
- * them to OFPP_NORMAL (which goes to us). Otherwise, the
- * switch is in secure mode and we won't pass any traffic until
- * a controller has been defined and it tells us to do so. */
- if (!n_controllers
- && ofproto_get_fail_mode(br->ofproto) == OFPROTO_FAIL_STANDALONE) {
- union ofp_action action;
- struct cls_rule rule;
-
- memset(&action, 0, sizeof action);
- action.type = htons(OFPAT_OUTPUT);
- action.output.len = htons(sizeof action);
- action.output.port = htons(OFPP_NORMAL);
- cls_rule_init_catchall(&rule, 0);
- ofproto_add_flow(br->ofproto, &rule, &action, 1);
- }
-}
-
-static void
-bridge_get_all_ifaces(const struct bridge *br, struct shash *ifaces)
-{
- size_t i, j;
-
- shash_init(ifaces);
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- shash_add_once(ifaces, iface->name, iface);
- }
- if (port->n_ifaces > 1 && port->cfg->bond_fake_iface) {
- shash_add_once(ifaces, port->name, NULL);
- }
- }
-}
-
-/* For robustness, in case the administrator moves around datapath ports behind
- * our back, we re-check all the datapath port numbers here.
- *
- * This function will set the 'dp_ifidx' members of interfaces that have
- * disappeared to -1, so only call this function from a context where those
- * 'struct iface's will be removed from the bridge. Otherwise, the -1
- * 'dp_ifidx'es will cause trouble later when we try to send them to the
- * datapath, which doesn't support UINT16_MAX+1 ports. */
-static void
-bridge_fetch_dp_ifaces(struct bridge *br)
-{
- struct dpif_port_dump dump;
- struct dpif_port dpif_port;
- size_t i, j;
-
- /* Reset all interface numbers. */
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- iface->dp_ifidx = -1;