/*
- * Copyright (c) 2010 Nicira Networks.
+ * Copyright (c) 2010, 2011 Nicira Networks.
* Distributed under the terms of the GNU GPL version 2.
*
* Significant portions of this file may be copied from parts of the Linux
return err;
}
-static void vport_del_all(void)
-{
- int i;
-
- rtnl_lock();
- vport_lock();
-
- for (i = 0; i < VPORT_HASH_BUCKETS; i++) {
- struct hlist_head *bucket = &dev_table[i];
- struct vport *vport;
- struct hlist_node *node, *next;
-
- hlist_for_each_entry_safe(vport, node, next, bucket, hash_node)
- vport_del(vport);
- }
-
- vport_unlock();
- rtnl_unlock();
-}
-
/**
* vport_exit - shutdown vport subsystem
*
{
int i;
- vport_del_all();
-
for (i = 0; i < n_vport_types; i++) {
if (vport_ops_list[i]->exit)
vport_ops_list[i]->exit();
ASSERT_VPORT();
for (i = 0; i < n_vport_types; i++) {
- if (!strcmp(vport_ops_list[i]->type, parms->type)) {
+ if (vport_ops_list[i]->type == parms->type) {
vport = vport_ops_list[i]->create(parms);
if (IS_ERR(vport)) {
err = PTR_ERR(vport);
spin_unlock_bh(&vport->stats_lock);
return 0;
- } else if (vport->ops->set_stats)
- return vport->ops->set_stats(vport, stats);
- else
+ } else
return -EOPNOTSUPP;
}
* @vport: vport from which to retrieve the type.
*
* Retrieves the type of the given device. Either RTNL lock or rcu_read_lock
- * must be held for the entire duration that the type is in use.
+ * must be held.
*/
-const char *vport_get_type(const struct vport *vport)
+enum odp_vport_type vport_get_type(const struct vport *vport)
{
return vport->ops->type;
}
return NULL;
}
+static int vport_call_get_stats(struct vport *vport, struct rtnl_link_stats64 *stats)
+{
+ int err;
+
+ rcu_read_lock();
+ err = vport->ops->get_stats(vport, stats);
+ rcu_read_unlock();
+
+ return err;
+}
+
/**
* vport_get_stats - retrieve device stats (for kernel callers)
*
*/
int vport_get_stats(struct vport *vport, struct rtnl_link_stats64 *stats)
{
- struct rtnl_link_stats64 dev_stats;
- struct rtnl_link_stats64 *dev_statsp = NULL;
- int err;
-
- if (vport->ops->get_stats) {
- if (vport->ops->flags & VPORT_F_GEN_STATS)
- dev_statsp = &dev_stats;
- else
- dev_statsp = stats;
-
- rcu_read_lock();
- err = vport->ops->get_stats(vport, dev_statsp);
- rcu_read_unlock();
+ int i;
- if (err)
- goto out;
- }
+ if (!(vport->ops->flags & VPORT_F_GEN_STATS))
+ return vport_call_get_stats(vport, stats);
- if (vport->ops->flags & VPORT_F_GEN_STATS) {
- int i;
+ /* We potentially have 3 sources of stats that need to be
+ * combined: those we have collected (split into err_stats and
+ * percpu_stats), offset_stats from set_stats(), and device
+ * error stats from get_stats() (for errors that happen
+ * downstream and therefore aren't reported through our
+ * vport_record_error() function). */
- /* We potentially have 3 sources of stats that need to be
- * combined: those we have collected (split into err_stats and
- * percpu_stats), offset_stats from set_stats(), and device
- * error stats from get_stats() (for errors that happen
- * downstream and therefore aren't reported through our
- * vport_record_error() function). */
+ spin_lock_bh(&vport->stats_lock);
- spin_lock_bh(&vport->stats_lock);
+ *stats = vport->offset_stats;
- *stats = vport->offset_stats;
+ stats->rx_errors += vport->err_stats.rx_errors;
+ stats->tx_errors += vport->err_stats.tx_errors;
+ stats->tx_dropped += vport->err_stats.tx_dropped;
+ stats->rx_dropped += vport->err_stats.rx_dropped;
- stats->rx_errors += vport->err_stats.rx_errors;
- stats->tx_errors += vport->err_stats.tx_errors;
- stats->tx_dropped += vport->err_stats.tx_dropped;
- stats->rx_dropped += vport->err_stats.rx_dropped;
+ spin_unlock_bh(&vport->stats_lock);
- spin_unlock_bh(&vport->stats_lock);
-
- if (dev_statsp) {
- stats->rx_packets += dev_statsp->rx_packets;
- stats->tx_packets += dev_statsp->tx_packets;
- stats->rx_bytes += dev_statsp->rx_bytes;
- stats->tx_bytes += dev_statsp->tx_bytes;
- stats->rx_errors += dev_statsp->rx_errors;
- stats->tx_errors += dev_statsp->tx_errors;
- stats->rx_dropped += dev_statsp->rx_dropped;
- stats->tx_dropped += dev_statsp->tx_dropped;
- stats->multicast += dev_statsp->multicast;
- stats->collisions += dev_statsp->collisions;
- stats->rx_length_errors += dev_statsp->rx_length_errors;
- stats->rx_over_errors += dev_statsp->rx_over_errors;
- stats->rx_crc_errors += dev_statsp->rx_crc_errors;
- stats->rx_frame_errors += dev_statsp->rx_frame_errors;
- stats->rx_fifo_errors += dev_statsp->rx_fifo_errors;
- stats->rx_missed_errors += dev_statsp->rx_missed_errors;
- stats->tx_aborted_errors += dev_statsp->tx_aborted_errors;
- stats->tx_carrier_errors += dev_statsp->tx_carrier_errors;
- stats->tx_fifo_errors += dev_statsp->tx_fifo_errors;
- stats->tx_heartbeat_errors += dev_statsp->tx_heartbeat_errors;
- stats->tx_window_errors += dev_statsp->tx_window_errors;
- stats->rx_compressed += dev_statsp->rx_compressed;
- stats->tx_compressed += dev_statsp->tx_compressed;
- }
+ if (vport->ops->get_stats) {
+ struct rtnl_link_stats64 dev_stats;
+ int err;
- for_each_possible_cpu(i) {
- const struct vport_percpu_stats *percpu_stats;
- struct vport_percpu_stats local_stats;
- unsigned seqcount;
+ err = vport_call_get_stats(vport, &dev_stats);
+ if (err)
+ return err;
+
+ stats->rx_errors += dev_stats.rx_errors;
+ stats->tx_errors += dev_stats.tx_errors;
+ stats->rx_dropped += dev_stats.rx_dropped;
+ stats->tx_dropped += dev_stats.tx_dropped;
+ stats->multicast += dev_stats.multicast;
+ stats->collisions += dev_stats.collisions;
+ stats->rx_length_errors += dev_stats.rx_length_errors;
+ stats->rx_over_errors += dev_stats.rx_over_errors;
+ stats->rx_crc_errors += dev_stats.rx_crc_errors;
+ stats->rx_frame_errors += dev_stats.rx_frame_errors;
+ stats->rx_fifo_errors += dev_stats.rx_fifo_errors;
+ stats->rx_missed_errors += dev_stats.rx_missed_errors;
+ stats->tx_aborted_errors += dev_stats.tx_aborted_errors;
+ stats->tx_carrier_errors += dev_stats.tx_carrier_errors;
+ stats->tx_fifo_errors += dev_stats.tx_fifo_errors;
+ stats->tx_heartbeat_errors += dev_stats.tx_heartbeat_errors;
+ stats->tx_window_errors += dev_stats.tx_window_errors;
+ stats->rx_compressed += dev_stats.rx_compressed;
+ stats->tx_compressed += dev_stats.tx_compressed;
+ }
- percpu_stats = per_cpu_ptr(vport->percpu_stats, i);
+ for_each_possible_cpu(i) {
+ const struct vport_percpu_stats *percpu_stats;
+ struct vport_percpu_stats local_stats;
+ unsigned seqcount;
- do {
- seqcount = read_seqcount_begin(&percpu_stats->seqlock);
- local_stats = *percpu_stats;
- } while (read_seqcount_retry(&percpu_stats->seqlock, seqcount));
+ percpu_stats = per_cpu_ptr(vport->percpu_stats, i);
- stats->rx_bytes += local_stats.rx_bytes;
- stats->rx_packets += local_stats.rx_packets;
- stats->tx_bytes += local_stats.tx_bytes;
- stats->tx_packets += local_stats.tx_packets;
- }
+ do {
+ seqcount = read_seqcount_begin(&percpu_stats->seqlock);
+ local_stats = *percpu_stats;
+ } while (read_seqcount_retry(&percpu_stats->seqlock, seqcount));
- err = 0;
- } else
- err = -EOPNOTSUPP;
+ stats->rx_bytes += local_stats.rx_bytes;
+ stats->rx_packets += local_stats.rx_packets;
+ stats->tx_bytes += local_stats.tx_bytes;
+ stats->tx_packets += local_stats.tx_packets;
+ }
-out:
- return err;
+ return 0;
}
/**
*
* @vport: vport from which to retrieve index
*
- * Retrieves the system interface index of the given device. Not all devices
- * will have system indexes, in which case the index of the datapath local
- * port is returned. Returns a negative index on error. Either RTNL lock or
+ * Retrieves the system interface index of the given device or 0 if
+ * the device does not have one (in the case of virtual ports).
+ * Returns a negative index on error. Either RTNL lock or
* rcu_read_lock must be held.
*/
int vport_get_ifindex(const struct vport *vport)
{
if (vport->ops->get_ifindex)
return vport->ops->get_ifindex(vport);
-
- /* If we don't actually have an ifindex, use the local port's.
- * Userspace doesn't check it anyways. */
- return vport_get_ifindex(vport->dp->ports[ODPP_LOCAL]);
+ else
+ return 0;
}
/**
return vport->ops->get_mtu(vport);
}
+/**
+ * vport_get_config - retrieve device configuration
+ *
+ * @vport: vport from which to retrieve the configuration.
+ * @config: buffer to store config, which must be at least the length
+ * of VPORT_CONFIG_SIZE.
+ *
+ * Retrieves the configuration of the given device. Either RTNL lock or
+ * rcu_read_lock must be held.
+ */
+void vport_get_config(const struct vport *vport, void *config)
+{
+ if (vport->ops->get_config)
+ vport->ops->get_config(vport, config);
+}
+
/**
* vport_receive - pass up received packet to the datapath for processing
*