datapath: Refuse module load if an active bridge exists.
authorBen Pfaff <blp@nicira.com>
Wed, 11 Mar 2009 18:13:01 +0000 (11:13 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 11 Mar 2009 18:13:18 +0000 (11:13 -0700)
Loading when an active bridge exists will cause an OOPS as soon as any
packet is received on a bridged interface, because the datapath will
attempt to interpret the bridge's "struct net_bridge_port" as a datapath
"struct net_bridge_port", which is completely wrong.

datapath/datapath.c
datapath/linux-2.6/compat-2.6/include/linux/netdevice.h

index 6aee55fa04f0d39c6d47301f845534673c96d849..851af969ecd70ed879380242e76a88496ea36ab1 100644 (file)
@@ -1522,9 +1522,23 @@ static int __init dp_init(void)
 
        /* Hook into callback used by the bridge to intercept packets.
         * Parasites we are. */
-       if (br_handle_frame_hook)
+       rtnl_lock();
+       if (br_handle_frame_hook) {
+               struct net_device *dev;
+               for_each_netdev (&init_net, dev) {
+                       if (!dev->br_port)
+                               continue;
+
+                       rtnl_unlock();
+                       printk("openflow: must delete bridges "
+                              "before loading\n");
+                       err = -EBUSY;
+                       goto error_unreg_notifier;
+               }
                printk("openflow: hijacking bridge hook\n");
+       }
        br_handle_frame_hook = dp_frame_hook;
+       rtnl_unlock();
 
        return 0;
 
index 015c6efd1037333509e11e4d55c1e4e158848f37..042e30d7543d0a88a694b19425de82d1413f4cf8 100644 (file)
@@ -17,4 +17,13 @@ struct net *dev_net(const struct net_device *dev)
 }
 #endif /* linux kernel < 2.6.26 */
 
+#ifndef for_each_netdev
+/* Linux before 2.6.22 didn't have for_each_netdev at all. */
+#define for_each_netdev(net, d) for (d = dev_base; d; d = d->next)
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+/* Linux 2.6.24 added a network namespace pointer to the macro. */
+#undef for_each_netdev
+#define for_each_netdev(net,d) list_for_each_entry(d, &dev_base_head, dev_list)
+#endif
+
 #endif