X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=e4d9cb7bcfcd76e605aff105361dfc918554473a;hb=af9af3e21d307b5de2cdb69aecb3b8b5e7505cbc;hp=e4e582ca7ec99a9f3ced688db8c7a2d2e200803c;hpb=1e0b752d3d6ff8bd63831ec32a39b4900b963d76;p=openvswitch diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index e4e582ca..e4d9cb7b 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -46,6 +46,7 @@ #include "ofpbuf.h" #include "ofproto/netflow.h" #include "ofproto/ofproto.h" +#include "ovsdb-data.h" #include "packets.h" #include "poll-loop.h" #include "port-array.h" @@ -104,6 +105,7 @@ struct mirror { struct bridge *bridge; size_t idx; char *name; + struct uuid uuid; /* UUID of this "mirror" record in database. */ /* Selection criteria. */ struct shash src_ports; /* Name is port name; data is always NULL. */ @@ -186,10 +188,16 @@ static struct list all_bridges = LIST_INITIALIZER(&all_bridges); /* OVSDB IDL used to obtain configuration. */ static struct ovsdb_idl *idl; +/* Each time this timer expires, the bridge fetches statistics for every + * interface and pushes them into the database. */ +#define IFACE_STATS_INTERVAL (5 * 1000) /* In milliseconds. */ +static long long int iface_stats_timer = LLONG_MIN; + static struct bridge *bridge_create(const struct ovsrec_bridge *br_cfg); static void bridge_destroy(struct bridge *); static struct bridge *bridge_lookup(const char *name); static unixctl_cb_func bridge_unixctl_dump_flows; +static unixctl_cb_func bridge_unixctl_reconnect; static int bridge_run_one(struct bridge *); static size_t bridge_get_controllers(const struct ovsrec_open_vswitch *ovs_cfg, const struct bridge *br, @@ -233,7 +241,7 @@ static void port_update_bond_compat(struct port *); static void port_update_vlan_compat(struct port *); static void port_update_bonding(struct port *); -static struct mirror *mirror_create(struct bridge *, const char *name); +static void mirror_create(struct bridge *, struct ovsrec_mirror *); static void mirror_destroy(struct mirror *); static void mirror_reconfigure(struct bridge *); static void mirror_reconfigure_one(struct mirror *, struct ovsrec_mirror *); @@ -267,6 +275,8 @@ bridge_init(const char *remote) unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL); unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows, NULL); + unixctl_command_register("bridge/reconnect", bridge_unixctl_reconnect, + NULL); bond_init(); } @@ -286,6 +296,8 @@ bridge_configure_once(const struct ovsrec_open_vswitch *cfg) } already_configured_once = true; + iface_stats_timer = time_msec() + IFACE_STATS_INTERVAL; + /* Get all the configured bridges' names from 'cfg' into 'bridge_names'. */ svec_init(&bridge_names); for (i = 0; i < cfg->n_bridges; i++) { @@ -635,9 +647,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) shash_init(&cur_ifaces); for (i = 0; i < n_dpif_ports; i++) { const char *name = dpif_ports[i].devname; - if (!shash_find(&cur_ifaces, name)) { - shash_add(&cur_ifaces, name, NULL); - } + shash_add_once(&cur_ifaces, name, NULL); } free(dpif_ports); @@ -835,25 +845,25 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) } static const char * -get_ovsrec_key_value(const char *key, char **keys, char **values, size_t n) +get_ovsrec_key_value(const struct ovsdb_idl_row *row, + const struct ovsdb_idl_column *column, + const char *key) { - size_t i; - - for (i = 0; i < n; i++) { - if (!strcmp(keys[i], key)) { - return values[i]; - } - } - return NULL; + const struct ovsdb_datum *datum; + union ovsdb_atom atom; + unsigned int idx; + + datum = ovsdb_idl_get(row, column, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING); + atom.string = (char *) key; + idx = ovsdb_datum_find_key(datum, &atom, OVSDB_TYPE_STRING); + return idx == UINT_MAX ? NULL : datum->values[idx].string; } static const char * bridge_get_other_config(const struct ovsrec_bridge *br_cfg, const char *key) { - return get_ovsrec_key_value(key, - br_cfg->key_other_config, - br_cfg->value_other_config, - br_cfg->n_other_config); + return get_ovsrec_key_value(&br_cfg->header_, + &ovsrec_bridge_col_other_config, key); } static void @@ -1049,6 +1059,53 @@ dpid_from_hash(const void *data, size_t n) return eth_addr_to_uint64(hash); } +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); +} + void bridge_run(void) { @@ -1087,6 +1144,30 @@ bridge_run(void) bridge_reconfigure(&null_cfg); } } + + /* Refresh interface stats if necessary. */ + if (time_msec() >= iface_stats_timer) { + struct ovsdb_idl_txn *txn; + + txn = ovsdb_idl_txn_create(idl); + LIST_FOR_EACH (br, struct bridge, 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); + } + } + } + ovsdb_idl_txn_commit(txn); + ovsdb_idl_txn_destroy(txn); /* XXX */ + + iface_stats_timer = time_msec() + IFACE_STATS_INTERVAL; + } } void @@ -1104,6 +1185,7 @@ bridge_wait(void) bond_wait(br); } ovsdb_idl_wait(idl); + poll_timer_wait_until(iface_stats_timer); } /* Forces 'br' to revalidate all of its flows. This is appropriate when 'br''s @@ -1274,6 +1356,29 @@ bridge_unixctl_dump_flows(struct unixctl_conn *conn, 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, struct bridge, node, &all_bridges) { + ofproto_reconnect_controllers(br->ofproto); + } + } + unixctl_command_reply(conn, 200, NULL); +} + static int bridge_run_one(struct bridge *br) { @@ -3134,10 +3239,10 @@ static const char * get_port_other_config(const struct ovsrec_port *port, const char *key, const char *default_value) { - const char *value = get_ovsrec_key_value(key, - port->key_other_config, - port->value_other_config, - port->n_other_config); + const char *value; + + value = get_ovsrec_key_value(&port->header_, &ovsrec_port_col_other_config, + key); return value ? value : default_value; } @@ -3651,27 +3756,16 @@ shash_from_ovs_idl_map(char **keys, char **values, size_t n, struct iface_delete_queues_cbdata { struct netdev *netdev; - const int64_t *queue_ids; - size_t n_queue_ids; + const struct ovsdb_datum *queues; }; static bool -queue_ids_include(const int64_t *ids, size_t n, int64_t target) +queue_ids_include(const struct ovsdb_datum *queues, int64_t target) { - size_t low = 0; - size_t high = n; + union ovsdb_atom atom; - while (low < high) { - size_t mid = low + (high - low) / 2; - if (target > ids[mid]) { - high = mid; - } else if (target < ids[mid]) { - low = mid + 1; - } else { - return true; - } - } - return false; + atom.integer = target; + return ovsdb_datum_find_key(queues, &atom, OVSDB_TYPE_INTEGER) != UINT_MAX; } static void @@ -3680,7 +3774,7 @@ iface_delete_queues(unsigned int queue_id, { struct iface_delete_queues_cbdata *cbdata = cbdata_; - if (!queue_ids_include(cbdata->queue_ids, cbdata->n_queue_ids, queue_id)) { + if (!queue_ids_include(cbdata->queues, queue_id)) { netdev_delete_queue(cbdata->netdev, queue_id); } } @@ -3703,8 +3797,8 @@ iface_update_qos(struct iface *iface, const struct ovsrec_qos *qos) /* Deconfigure queues that were deleted. */ cbdata.netdev = iface->netdev; - cbdata.queue_ids = qos->key_queues; - cbdata.n_queue_ids = qos->n_queues; + cbdata.queues = ovsrec_qos_get_queues(qos, OVSDB_TYPE_INTEGER, + OVSDB_TYPE_UUID); netdev_dump_queues(iface->netdev, iface_delete_queues, &cbdata); /* Configure queues for 'iface'. */ @@ -3723,50 +3817,51 @@ iface_update_qos(struct iface *iface, const struct ovsrec_qos *qos) /* Port mirroring. */ +static struct mirror * +mirror_find_by_uuid(struct bridge *br, const struct uuid *uuid) +{ + int i; + + for (i = 0; i < MAX_MIRRORS; i++) { + struct mirror *m = br->mirrors[i]; + if (m && uuid_equals(uuid, &m->uuid)) { + return m; + } + } + return NULL; +} + static void mirror_reconfigure(struct bridge *br) { - struct shash old_mirrors, new_mirrors; - struct shash_node *node; unsigned long *rspan_vlans; int i; - /* Collect old mirrors. */ - shash_init(&old_mirrors); + /* Get rid of deleted mirrors. */ for (i = 0; i < MAX_MIRRORS; i++) { - if (br->mirrors[i]) { - shash_add(&old_mirrors, br->mirrors[i]->name, br->mirrors[i]); + struct mirror *m = br->mirrors[i]; + if (m) { + const struct ovsdb_datum *mc; + union ovsdb_atom atom; + + mc = ovsrec_bridge_get_mirrors(br->cfg, OVSDB_TYPE_UUID); + atom.uuid = br->mirrors[i]->uuid; + if (ovsdb_datum_find_key(mc, &atom, OVSDB_TYPE_UUID) == UINT_MAX) { + mirror_destroy(m); + } } } - /* Collect new mirrors. */ - shash_init(&new_mirrors); + /* Add new mirrors and reconfigure existing ones. */ for (i = 0; i < br->cfg->n_mirrors; i++) { struct ovsrec_mirror *cfg = br->cfg->mirrors[i]; - if (!shash_add_once(&new_mirrors, cfg->name, cfg)) { - VLOG_WARN("bridge %s: %s specified twice as mirror", - br->name, cfg->name); - } - } - - /* Get rid of deleted mirrors and add new mirrors. */ - SHASH_FOR_EACH (node, &old_mirrors) { - if (!shash_find(&new_mirrors, node->name)) { - mirror_destroy(node->data); - } - } - SHASH_FOR_EACH (node, &new_mirrors) { - struct mirror *mirror = shash_find_data(&old_mirrors, node->name); - if (!mirror) { - mirror = mirror_create(br, node->name); - if (!mirror) { - break; - } + struct mirror *m = mirror_find_by_uuid(br, &cfg->header_.uuid); + if (m) { + mirror_reconfigure_one(m, cfg); + } else { + mirror_create(br, cfg); } - mirror_reconfigure_one(mirror, node->data); } - shash_destroy(&old_mirrors); - shash_destroy(&new_mirrors); /* Update port reserved status. */ for (i = 0; i < br->n_ports; i++) { @@ -3801,8 +3896,8 @@ mirror_reconfigure(struct bridge *br) } } -static struct mirror * -mirror_create(struct bridge *br, const char *name) +static void +mirror_create(struct bridge *br, struct ovsrec_mirror *cfg) { struct mirror *m; size_t i; @@ -3810,21 +3905,21 @@ mirror_create(struct bridge *br, const char *name) for (i = 0; ; i++) { if (i >= MAX_MIRRORS) { VLOG_WARN("bridge %s: maximum of %d port mirrors reached, " - "cannot create %s", br->name, MAX_MIRRORS, name); - return NULL; + "cannot create %s", br->name, MAX_MIRRORS, cfg->name); + return; } if (!br->mirrors[i]) { break; } } - VLOG_INFO("created port mirror %s on bridge %s", name, br->name); + VLOG_INFO("created port mirror %s on bridge %s", cfg->name, br->name); bridge_flush(br); br->mirrors[i] = m = xzalloc(sizeof *m); m->bridge = br; m->idx = i; - m->name = xstrdup(name); + m->name = xstrdup(cfg->name); shash_init(&m->src_ports); shash_init(&m->dst_ports); m->vlans = NULL; @@ -3832,7 +3927,7 @@ mirror_create(struct bridge *br, const char *name) m->out_vlan = -1; m->out_port = NULL; - return m; + mirror_reconfigure_one(m, cfg); } static void @@ -3852,6 +3947,7 @@ mirror_destroy(struct mirror *m) free(m->vlans); m->bridge->mirrors[m->idx] = NULL; + free(m->name); free(m); bridge_flush(br); @@ -3933,6 +4029,12 @@ mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg) int *vlans; size_t i; + /* Set name. */ + if (strcmp(cfg->name, m->name)) { + free(m->name); + m->name = xstrdup(cfg->name); + } + /* Get output port. */ if (cfg->output_port) { out_port = port_lookup(m->bridge, cfg->output_port->name);