From 9526bcfd633922bad77e3efdbc4de2ab8d6f4cd3 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 29 May 2009 15:32:59 -0700 Subject: [PATCH] datapath: Prevent bridge module from loading along with openvswitch. For some time, the openvswitch kernel module has checked whether the bridge module is loaded and refused to start if so. However, the bridge module doesn't check whether the openvswitch module is loaded, so it can end up loaded at the same time if something goes wrong, and then generally the system OOPSes sooner or later. This commit adds proper mutual exclusion, by registering an LLC SAP for the protocol used by spanning tree. This is the first thing that the bridge module does at initialization time also, and since there can only be one registration for a given protocol this prevents both modules from being loaded at the same time. This fixes an actual OOPS observed at boot time on a XenServer running the debug kernel that we built based on Citrix's 5.5.0-beta1 kernel. --- datapath/datapath.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index e6484ac7..66f9202a 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #include "openvswitch/datapath-protocol.h" #include "datapath.h" @@ -1538,6 +1540,17 @@ struct file_operations openvswitch_fops = { }; static int major; +static struct llc_sap *dp_stp_sap; + +static int dp_stp_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + /* We don't really care about STP packets, we just listen for them for + * mutual exclusion with the bridge module, so this just discards + * them. */ + kfree_skb(skb); + return 0; +} static int __init dp_init(void) { @@ -1545,6 +1558,17 @@ static int __init dp_init(void) printk("Open vSwitch %s, built "__DATE__" "__TIME__"\n", VERSION BUILDNR); + /* Register to receive STP packets because the bridge module also + * attempts to do so. Since there can only be a single listener for a + * given protocol, this provides mutual exclusion against the bridge + * module, preventing both of them from being loaded at the same + * time. */ + dp_stp_sap = llc_sap_open(LLC_SAP_BSPAN, dp_stp_rcv); + if (!dp_stp_sap) { + printk(KERN_ERR "openvswitch: can't register sap for STP (probably the bridge module is loaded)\n"); + return -EADDRINUSE; + } + err = flow_init(); if (err) goto error; @@ -1559,23 +1583,7 @@ static int __init dp_init(void) /* Hook into callback used by the bridge to intercept packets. * Parasites we are. */ - 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("openvswitch: must delete bridges " - "before loading\n"); - err = -EBUSY; - goto error_unreg_notifier; - } - printk("openvswitch: hijacking bridge hook\n"); - } br_handle_frame_hook = dp_frame_hook; - rtnl_unlock(); return 0; @@ -1594,6 +1602,7 @@ static void dp_cleanup(void) unregister_netdevice_notifier(&dp_device_notifier); flow_exit(); br_handle_frame_hook = NULL; + llc_sap_put(dp_stp_sap); } module_init(dp_init); -- 2.30.2