ovs_mutex_lock(&netdev_class_mutex);
HMAP_FOR_EACH (rc, hmap_node, &netdev_classes) {
const char *dpif_port = netdev_vport_class_get_dpif_port(rc->class);
- if (dpif_port && !strcmp(dpif_port, name)) {
+ if (dpif_port && !strncmp(name, dpif_port, strlen(dpif_port))) {
ovs_mutex_unlock(&netdev_class_mutex);
return true;
}
/* Reconfigures the device 'netdev' with 'args'. 'args' may be empty
* or NULL if none are needed. */
int
-netdev_set_config(struct netdev *netdev, const struct smap *args)
+netdev_set_config(struct netdev *netdev, const struct smap *args, char **errp)
OVS_EXCLUDED(netdev_mutex)
{
if (netdev->netdev_class->set_config) {
error = netdev->netdev_class->set_config(netdev,
args ? args : &no_args);
if (error) {
- VLOG_WARN("%s: could not set configuration (%s)",
- netdev_get_name(netdev), ovs_strerror(error));
+ VLOG_WARN_BUF(errp, "%s: could not set configuration (%s)",
+ netdev_get_name(netdev), ovs_strerror(error));
}
return error;
} else if (args && !smap_is_empty(args)) {
- VLOG_WARN("%s: arguments provided to device that is not configurable",
- netdev_get_name(netdev));
+ VLOG_WARN_BUF(errp, "%s: arguments provided to device that is not configurable",
+ netdev_get_name(netdev));
}
return 0;
}
dev->netdev_class->destruct(dev);
- shash_delete(&netdev_shash, dev->node);
+ if (dev->node) {
+ shash_delete(&netdev_shash, dev->node);
+ }
free(dev->name);
dev->netdev_class->dealloc(dev);
ovs_mutex_unlock(&netdev_mutex);
}
}
+/* Removes 'netdev' from the global shash and unrefs 'netdev'.
+ *
+ * This allows handler and revalidator threads to still retain references
+ * to this netdev while the main thread changes interface configuration.
+ *
+ * This function should only be called by the main thread when closing
+ * netdevs during user configuration changes. Otherwise, netdev_close should be
+ * used to close netdevs. */
+void
+netdev_remove(struct netdev *netdev)
+{
+ if (netdev) {
+ ovs_mutex_lock(&netdev_mutex);
+ if (netdev->node) {
+ shash_delete(&netdev_shash, netdev->node);
+ netdev->node = NULL;
+ netdev_change_seq_changed(netdev);
+ }
+ netdev_unref(netdev);
+ }
+}
+
/* Parses 'netdev_name_', which is of the form [type@]name into its component
* pieces. 'name' and 'type' must be freed by the caller. */
void
* This function may be set to null if it would always return EOPNOTSUPP
* anyhow. */
int
-netdev_rxq_recv(struct netdev_rxq *rx, struct ofpbuf **buffers, int *cnt)
+netdev_rxq_recv(struct netdev_rxq *rx, struct dpif_packet **buffers, int *cnt)
{
int retval;
: 0);
}
-/* Sends 'buffer' on 'netdev'. Returns 0 if successful, otherwise a positive
- * errno value. Returns EAGAIN without blocking if the packet cannot be queued
- * immediately. Returns EMSGSIZE if a partial packet was transmitted or if
- * the packet is too big or too small to transmit on the device.
+/* Sends 'buffers' on 'netdev'. Returns 0 if successful (for every packet),
+ * otherwise a positive errno value. Returns EAGAIN without blocking if
+ * at least one the packets cannot be queued immediately. Returns EMSGSIZE
+ * if a partial packet was transmitted or if a packet is too big or too small
+ * to transmit on the device.
+ *
+ * If the function returns a non-zero value, some of the packets might have
+ * been sent anyway.
*
* To retain ownership of 'buffer' caller can set may_steal to false.
*
* Some network devices may not implement support for this function. In such
* cases this function will always return EOPNOTSUPP. */
int
-netdev_send(struct netdev *netdev, struct ofpbuf *buffer, bool may_steal)
+netdev_send(struct netdev *netdev, struct dpif_packet **buffers, int cnt,
+ bool may_steal)
{
int error;
error = (netdev->netdev_class->send
- ? netdev->netdev_class->send(netdev, buffer, may_steal)
+ ? netdev->netdev_class->send(netdev, buffers, cnt, may_steal)
: EOPNOTSUPP);
if (!error) {
COVERAGE_INC(netdev_sent);