X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=d4a08b92fd36a1c8513ec2f6902a40d7c4840cd0;hb=07c2523c0c48a7b285b0931f33a49fc129f2c396;hp=e4e582ca7ec99a9f3ced688db8c7a2d2e200803c;hpb=1e0b752d3d6ff8bd63831ec32a39b4900b963d76;p=openvswitch diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index e4e582ca..d4a08b92 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -186,10 +186,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, @@ -267,6 +273,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 +294,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++) { @@ -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) {