mgmt: Local config changes can cause update failures from controller.
[openvswitch] / datapath / datapath.c
index 015edc4bb60b1796e6db060301864f970ac08ea3..bf8043b6054fffa428fb827321325f16cdfa6f87 100644 (file)
@@ -1,6 +1,9 @@
 /*
- * Distributed under the terms of the GNU GPL version 2.
  * Copyright (c) 2007, 2008, 2009 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
+ * kernel, by Linus Torvalds and others.
  */
 
 /* Functions for managing the dp interface/device. */
 int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
 EXPORT_SYMBOL(dp_ioctl_hook);
 
-int (*dp_add_dp_hook)(struct datapath *dp);
-EXPORT_SYMBOL(dp_add_dp_hook);
-
-int (*dp_del_dp_hook)(struct datapath *dp);
-EXPORT_SYMBOL(dp_del_dp_hook);
-
-int (*dp_add_if_hook)(struct net_bridge_port *p);
-EXPORT_SYMBOL(dp_add_if_hook);
-
-int (*dp_del_if_hook)(struct net_bridge_port *p);
-EXPORT_SYMBOL(dp_del_if_hook);
-
 /* Datapaths.  Protected on the read side by rcu_read_lock, on the write side
  * by dp_mutex.  dp_mutex is almost completely redundant with genl_mutex
  * maintained by the Generic Netlink code, but the timeout path needs mutual
@@ -180,6 +171,16 @@ errout:
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
 }
 
+static void release_dp(struct kobject *kobj)
+{
+       struct datapath *dp = container_of(kobj, struct datapath, ifobj);
+       kfree(dp);
+}
+
+struct kobj_type dp_ktype = {
+       .release = release_dp
+};
+
 static int create_dp(int dp_idx, const char __user *devnamep)
 {
        struct net_device *dp_dev;
@@ -214,28 +215,37 @@ static int create_dp(int dp_idx, const char __user *devnamep)
        dp = kzalloc(sizeof *dp, GFP_KERNEL);
        if (dp == NULL)
                goto err_put_module;
-
+       INIT_LIST_HEAD(&dp->port_list);
        mutex_init(&dp->mutex);
        dp->dp_idx = dp_idx;
        for (i = 0; i < DP_N_QUEUES; i++)
                skb_queue_head_init(&dp->queues[i]);
        init_waitqueue_head(&dp->waitqueue);
 
-       /* Setup our datapath device */
-       dp_dev = dp_dev_create(dp, devname, ODPP_LOCAL);
-       err = PTR_ERR(dp_dev);
-       if (IS_ERR(dp_dev))
-               goto err_free_dp;
+       /* Initialize kobject for bridge.  This will be added as
+        * /sys/class/net/<devname>/bridge later, if sysfs is enabled. */
+       kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); /* "bridge" */
+       dp->ifobj.kset = NULL;
+       dp->ifobj.parent = NULL;
+       kobject_init(&dp->ifobj, &dp_ktype);
 
+       /* Allocate table. */
        err = -ENOMEM;
        rcu_assign_pointer(dp->table, dp_table_create(DP_L1_SIZE));
        if (!dp->table)
-               goto err_destroy_dp_dev;
-       INIT_LIST_HEAD(&dp->port_list);
+               goto err_free_dp;
+
+       /* Setup our datapath device */
+       dp_dev = dp_dev_create(dp, devname, ODPP_LOCAL);
+       err = PTR_ERR(dp_dev);
+       if (IS_ERR(dp_dev))
+               goto err_destroy_table;
 
        err = new_nbp(dp, dp_dev, ODPP_LOCAL);
-       if (err)
+       if (err) {
+               dp_dev_destroy(dp_dev);
                goto err_destroy_table;
+       }
 
        dp->drop_frags = 0;
        dp->stats_percpu = alloc_percpu(struct dp_stats_percpu);
@@ -246,17 +256,16 @@ static int create_dp(int dp_idx, const char __user *devnamep)
        mutex_unlock(&dp_mutex);
        rtnl_unlock();
 
-       if (dp_add_dp_hook)
-               dp_add_dp_hook(dp);
+#ifdef SUPPORT_SYSFS
+       dp_sysfs_add_dp(dp);
+#endif
 
        return 0;
 
 err_destroy_local_port:
-       dp_del_port(dp->ports[ODPP_LOCAL], NULL);
+       dp_del_port(dp->ports[ODPP_LOCAL]);
 err_destroy_table:
        dp_table_destroy(dp->table, 0);
-err_destroy_dp_dev:
-       dp_dev_destroy(dp_dev);
 err_free_dp:
        kfree(dp);
 err_put_module:
@@ -268,38 +277,37 @@ err:
        return err;
 }
 
-static void do_destroy_dp(struct datapath *dp, struct list_head *dp_devs)
+static void do_destroy_dp(struct datapath *dp)
 {
        struct net_bridge_port *p, *n;
        int i;
 
-       if (dp_del_dp_hook)
-               dp_del_dp_hook(dp);
-
-       /* Drop references to DP. */
        list_for_each_entry_safe (p, n, &dp->port_list, node)
-               dp_del_port(p, dp_devs);
+               if (p->port_no != ODPP_LOCAL)
+                       dp_del_port(p);
+
+#ifdef SUPPORT_SYSFS
+       dp_sysfs_del_dp(dp);
+#endif
 
        rcu_assign_pointer(dps[dp->dp_idx], NULL);
-       synchronize_rcu();
 
-       /* Wait until no longer in use, then destroy it. */
-       synchronize_rcu();
+       dp_del_port(dp->ports[ODPP_LOCAL]);
+
        dp_table_destroy(dp->table, 1);
+
        for (i = 0; i < DP_N_QUEUES; i++)
                skb_queue_purge(&dp->queues[i]);
        for (i = 0; i < DP_MAX_GROUPS; i++)
                kfree(dp->groups[i]);
        free_percpu(dp->stats_percpu);
-       kfree(dp);
+       kobject_put(&dp->ifobj);
        module_put(THIS_MODULE);
 }
 
 static int destroy_dp(int dp_idx)
 {
-       struct dp_dev *dp_dev, *next;
        struct datapath *dp;
-       LIST_HEAD(dp_devs);
        int err;
 
        rtnl_lock();
@@ -309,17 +317,28 @@ static int destroy_dp(int dp_idx)
        if (!dp)
                goto err_unlock;
 
-       do_destroy_dp(dp, &dp_devs);
+       do_destroy_dp(dp);
        err = 0;
 
 err_unlock:
        mutex_unlock(&dp_mutex);
        rtnl_unlock();
-       list_for_each_entry_safe (dp_dev, next, &dp_devs, list)
-               free_netdev(dp_dev->dev);
        return err;
 }
 
+static void release_nbp(struct kobject *kobj)
+{
+       struct net_bridge_port *p = container_of(kobj, struct net_bridge_port, kobj);
+       kfree(p);
+}
+
+struct kobj_type brport_ktype = {
+#ifdef SUPPORT_SYSFS
+       .sysfs_ops = &brport_sysfs_ops,
+#endif
+       .release = release_nbp
+};
+
 /* Called with RTNL lock and dp_mutex. */
 static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no)
 {
@@ -349,6 +368,13 @@ static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no)
        list_add_rcu(&p->node, &dp->port_list);
        dp->n_ports++;
 
+       /* Initialize kobject for bridge.  This will be added as
+        * /sys/class/net/<devname>/brport later, if sysfs is enabled. */
+       kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); /* "brport" */
+       p->kobj.kset = NULL;
+       p->kobj.parent = &p->dev->NETDEV_DEV_MEMBER.kobj;
+       kobject_init(&p->kobj, &brport_ktype);
+
        dp_ifinfo_notify(RTM_NEWLINK, p);
 
        return 0;
@@ -404,8 +430,9 @@ static int add_port(int dp_idx, struct odp_port __user *portp)
        if (err)
                goto out_put;
 
-       if (dp_add_if_hook)
-               dp_add_if_hook(dp->ports[port_no]);
+#ifdef SUPPORT_SYSFS
+       dp_sysfs_add_if(dp->ports[port_no]);
+#endif
 
 out_put:
        dev_put(dev);
@@ -417,13 +444,13 @@ out:
        return err;
 }
 
-int dp_del_port(struct net_bridge_port *p, struct list_head *dp_devs)
+int dp_del_port(struct net_bridge_port *p)
 {
        ASSERT_RTNL();
 
 #ifdef SUPPORT_SYSFS
-       if (p->port_no != ODPP_LOCAL && dp_del_if_hook)
-               sysfs_remove_link(&p->dp->ifobj, p->dev->name);
+       if (p->port_no != ODPP_LOCAL)
+               dp_sysfs_del_if(p);
 #endif
        dp_ifinfo_notify(RTM_DELLINK, p);
 
@@ -445,26 +472,16 @@ int dp_del_port(struct net_bridge_port *p, struct list_head *dp_devs)
        /* Then wait until no one is still using it, and destroy it. */
        synchronize_rcu();
 
-       if (is_dp_dev(p->dev)) {
+       if (is_dp_dev(p->dev))
                dp_dev_destroy(p->dev);
-               if (dp_devs) {
-                       struct dp_dev *dp_dev = dp_dev_priv(p->dev);
-                       list_add(&dp_dev->list, dp_devs);
-               }
-       }
-       if (p->port_no != ODPP_LOCAL && dp_del_if_hook) {
-               dp_del_if_hook(p);
-       } else {
-               dev_put(p->dev);
-               kfree(p);
-       }
+       dev_put(p->dev);
+       kobject_put(&p->kobj);
 
        return 0;
 }
 
 static int del_port(int dp_idx, int port_no)
 {
-       struct dp_dev *dp_dev, *next;
        struct net_bridge_port *p;
        struct datapath *dp;
        LIST_HEAD(dp_devs);
@@ -485,15 +502,13 @@ static int del_port(int dp_idx, int port_no)
        if (!p)
                goto out_unlock_dp;
 
-       err = dp_del_port(p, &dp_devs);
+       err = dp_del_port(p);
 
 out_unlock_dp:
        mutex_unlock(&dp->mutex);
 out_unlock_rtnl:
        rtnl_unlock();
 out:
-       list_for_each_entry_safe (dp_dev, next, &dp_devs, list)
-               free_netdev(dp_dev->dev);
        return err;
 }
 
@@ -524,7 +539,6 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p)
        struct sw_flow *flow;
 
        WARN_ON_ONCE(skb_shared(skb));
-       WARN_ON_ONCE(skb->destructor);
 
        /* BHs are off so we don't have to use get_cpu()/put_cpu() here. */
        stats = percpu_ptr(dp->stats_percpu, smp_processor_id());
@@ -1193,6 +1207,29 @@ get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
        return copy_to_user(statsp, &stats, sizeof stats) ? -EFAULT : 0;
 }
 
+/* MTU of the dp pseudo-device: ETH_DATA_LEN or the minimum of the ports */
+int dp_min_mtu(const struct datapath *dp)
+{
+       struct net_bridge_port *p;
+       int mtu = 0;
+
+       ASSERT_RTNL();
+
+       list_for_each_entry_rcu (p, &dp->port_list, node) {
+               struct net_device *dev = p->dev;
+
+               /* Skip any internal ports, since that's what we're trying to
+                * set. */
+               if (is_dp_dev(dev))
+                       continue;
+
+               if (!mtu || dev->mtu < mtu)
+                       mtu = dev->mtu;
+       }
+
+       return mtu ? mtu : ETH_DATA_LEN;
+}
+
 static int
 put_port(const struct net_bridge_port *p, struct odp_port __user *uop)
 {
@@ -1461,6 +1498,7 @@ static int dp_has_packet_of_interest(struct datapath *dp, int listeners)
 ssize_t openvswitch_read(struct file *f, char __user *buf, size_t nbytes,
                      loff_t *ppos)
 {
+       /* XXX is there sufficient synchronization here? */
        int listeners = (int) f->private_data;
        int dp_idx = iminor(f->f_dentry->d_inode);
        struct datapath *dp = get_dp(dp_idx);
@@ -1515,6 +1553,7 @@ error:
 
 static unsigned int openvswitch_poll(struct file *file, poll_table *wait)
 {
+       /* XXX is there sufficient synchronization here? */
        int dp_idx = iminor(file->f_dentry->d_inode);
        struct datapath *dp = get_dp(dp_idx);
        unsigned int mask;