struct datapath *sysfs_get_dp(struct net_device *netdev)
{
- return vport_get_dp_port(internal_dev_get_vport(netdev))->dp;
-}
+ struct vport *vport = internal_dev_get_vport(netdev);
+ struct dp_port *dp_port;
+
+ if (!vport)
+ return NULL;
+ dp_port = vport_get_dp_port(vport);
+ if (!dp_port)
+ return NULL;
+
+ return dp_port->dp;
+}
/*
* Common code for storing bridge parameters.
*/
const char *buf, size_t len,
void (*set)(struct datapath *, unsigned long))
{
- struct datapath *dp = sysfs_get_dp(to_net_dev(d));
char *endp;
unsigned long val;
+ ssize_t result = len;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
* xxx ignore the request.
*/
if (val != 0) {
- printk("%s: xxx writing dp parms not supported yet!\n",
- dp_name(dp));
+ struct datapath *dp;
+
+ rcu_read_lock();
+
+ dp = sysfs_get_dp(to_net_dev(d));
+ if (dp)
+ printk("%s: xxx writing dp parms not supported yet!\n",
+ dp_name(dp));
+ else
+ result = -ENODEV;
+
+ rcu_read_unlock();
}
- return len;
+ return result;
}
const char *buf,
size_t len)
{
- struct datapath *dp = sysfs_get_dp(to_net_dev(d));
+ struct datapath *dp;
+ ssize_t result = len;
+
+ rcu_read_lock();
- printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
+ dp = sysfs_get_dp(to_net_dev(d));
+ if (dp)
+ printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
+ else
+ result = -ENODEV;
- return len;
+ rcu_read_unlock();
+
+ return result;
}
static INTERNAL_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
store_stp_state);
static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
{
- struct datapath *dp = sysfs_get_dp(to_net_dev(d));
- const unsigned char *addr = vport_get_addr(dp->ports[ODPP_LOCAL]->vport);
+ struct vport *vport;
+ ssize_t result;
+
+ rcu_read_lock();
+
+ vport = internal_dev_get_vport(to_net_dev(d));
+ if (vport) {
+ const unsigned char *addr;
+
+ addr = vport_get_addr(vport);
+ result = sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
+ 0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ } else
+ result = -ENODEV;
- /* xxx Do we need a lock of some sort? */
- return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
- 0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ rcu_read_unlock();
+
+ return result;
}
static INTERNAL_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
static ssize_t store_group_addr(DEVICE_PARAMS,
const char *buf, size_t len)
{
- struct datapath *dp = sysfs_get_dp(to_net_dev(d));
+ struct datapath *dp;
+ ssize_t result = len;
+
+ rcu_read_lock();
+
+ dp = sysfs_get_dp(to_net_dev(d));
+ if (dp)
+ printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
+ else
+ result = -ENODEV;
+
+ rcu_read_unlock();
- printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
- return len;
+ return result;
}
static INTERNAL_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
#include "vport-netdev.h"
struct internal_dev {
- struct vport *vport;
+ struct vport *attached_vport, *vport;
struct net_device_stats stats;
};
/* Called with rcu_read_lock and bottom-halves disabled. */
static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
{
- struct vport *vport = internal_dev_get_vport(netdev);
+ struct internal_dev *internal_dev = internal_dev_priv(netdev);
+ struct vport *vport = rcu_dereference(internal_dev->vport);
/* We need our own clone. */
skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb) {
+ if (unlikely(!skb)) {
vport_record_error(vport, VPORT_E_RX_DROPPED);
return 0;
}
static void internal_dev_getinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
- struct dp_port *dp_port = vport_get_dp_port(internal_dev_get_vport(netdev));
+ struct vport *vport = internal_dev_get_vport(netdev);
+ struct dp_port *dp_port;
strcpy(info->driver, "openvswitch");
+
+ if (!vport)
+ return;
+
+ dp_port = vport_get_dp_port(vport);
if (dp_port)
sprintf(info->bus_info, "%d.%d", dp_port->dp->dp_idx, dp_port->port_no);
}
static int internal_dev_change_mtu(struct net_device *netdev, int new_mtu)
{
- struct dp_port *dp_port = vport_get_dp_port(internal_dev_get_vport(netdev));
+ struct vport *vport = internal_dev_get_vport(netdev);
if (new_mtu < 68)
return -EINVAL;
- if (dp_port) {
- if (new_mtu > dp_min_mtu(dp_port->dp))
- return -EINVAL;
+ if (vport) {
+ struct dp_port *dp_port = vport_get_dp_port(vport);
+
+ if (dp_port) {
+ if (new_mtu > dp_min_mtu(dp_port->dp))
+ return -EINVAL;
+ }
}
netdev->mtu = new_mtu;
}
internal_dev = internal_dev_priv(netdev_vport->dev);
- internal_dev->vport = vport;
+ rcu_assign_pointer(internal_dev->vport, vport);
err = register_netdevice(netdev_vport->dev);
if (err)
static int internal_dev_attach(struct vport *vport)
{
struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
+ struct internal_dev *internal_dev = internal_dev_priv(netdev_vport->dev);
+ rcu_assign_pointer(internal_dev->attached_vport, internal_dev->vport);
dev_set_promiscuity(netdev_vport->dev, 1);
-
- /* It would make sense to assign dev->br_port here too, but
- * that causes packets received on internal ports to get caught
- * in netdev_frame_hook(). In turn netdev_frame_hook() can reject them
- * back to the network stack, but that's a waste of time. */
+ netif_start_queue(netdev_vport->dev);
return 0;
}
static int internal_dev_detach(struct vport *vport)
{
struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
+ struct internal_dev *internal_dev = internal_dev_priv(netdev_vport->dev);
+ netif_stop_queue(netdev_vport->dev);
dev_set_promiscuity(netdev_vport->dev, -1);
-
- /* Make sure that no packets arrive from now on, since
- * internal_dev_xmit() will try to find itself through
- * p->dp->ports[], and we're about to set that to null. */
- netif_tx_disable(netdev_vport->dev);
+ rcu_assign_pointer(internal_dev->attached_vport, NULL);
return 0;
}
struct vport *internal_dev_get_vport(struct net_device *netdev)
{
struct internal_dev *internal_dev = internal_dev_priv(netdev);
- return rcu_dereference(internal_dev->vport);
+ return rcu_dereference(internal_dev->attached_vport);
}