/*
- * Copyright (c) 2009, 2011 Nicira Networks.
- * Distributed under the terms of the GNU GPL version 2.
+ * Copyright (c) 2007-2012 Nicira Networks.
*
- * Significant portions of this file may be copied from parts of the Linux
- * kernel, by Linus Torvalds and others.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/completion.h>
static struct sk_buff *brc_reply; /* Reply from userspace. */
static u32 brc_seq; /* Sequence number for current op. */
-static struct sk_buff *brc_send_command(struct sk_buff *,
+static struct sk_buff *brc_send_command(struct net *,
+ struct sk_buff *,
struct nlattr **attrs);
-static int brc_send_simple_command(struct sk_buff *);
+static int brc_send_simple_command(struct net *, struct sk_buff *);
static struct sk_buff *brc_make_request(int op, const char *bridge,
const char *port)
return NULL;
}
-static int brc_send_simple_command(struct sk_buff *request)
+static int brc_send_simple_command(struct net *net, struct sk_buff *request)
{
struct nlattr *attrs[BRC_GENL_A_MAX + 1];
struct sk_buff *reply;
int error;
- reply = brc_send_command(request, attrs);
+ reply = brc_send_command(net, request, attrs);
if (IS_ERR(reply))
return PTR_ERR(reply);
return -error;
}
-static int brc_add_del_bridge(char __user *uname, int add)
+static int brc_add_del_bridge(struct net *net, char __user *uname, int add)
{
struct sk_buff *request;
char name[IFNAMSIZ];
if (!request)
return -ENOMEM;
- return brc_send_simple_command(request);
+ return brc_send_simple_command(net, request);
}
-static int brc_get_indices(int op, const char *br_name,
+static int brc_get_indices(struct net *net,
+ int op, const char *br_name,
int __user *uindices, int n)
{
struct nlattr *attrs[BRC_GENL_A_MAX + 1];
if (!request)
return -ENOMEM;
- reply = brc_send_command(request, attrs);
+ reply = brc_send_command(net, request, attrs);
ret = PTR_ERR(reply);
if (IS_ERR(reply))
goto exit;
}
/* Called with br_ioctl_mutex. */
-static int brc_get_bridges(int __user *uindices, int n)
+static int brc_get_bridges(struct net *net, int __user *uindices, int n)
{
- return brc_get_indices(BRC_GENL_C_GET_BRIDGES, NULL, uindices, n);
+ return brc_get_indices(net, BRC_GENL_C_GET_BRIDGES, NULL, uindices, n);
}
/* Legacy deviceless bridge ioctl's. Called with br_ioctl_mutex. */
-static int old_deviceless(void __user *uarg)
+static int old_deviceless(struct net *net, void __user *uarg)
{
unsigned long args[3];
switch (args[0]) {
case BRCTL_GET_BRIDGES:
- return brc_get_bridges((int __user *)args[1], args[2]);
+ return brc_get_bridges(net, (int __user *)args[1], args[2]);
case BRCTL_ADD_BRIDGE:
- return brc_add_del_bridge((void __user *)args[1], 1);
+ return brc_add_del_bridge(net, (void __user *)args[1], 1);
case BRCTL_DEL_BRIDGE:
- return brc_add_del_bridge((void __user *)args[1], 0);
+ return brc_add_del_bridge(net, (void __user *)args[1], 0);
}
return -EOPNOTSUPP;
static int
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
brc_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg)
+{
+ struct net *net = NULL;
#else
brc_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg)
-#endif
{
+#endif
switch (cmd) {
case SIOCGIFBR:
case SIOCSIFBR:
- return old_deviceless(uarg);
+ return old_deviceless(net, uarg);
case SIOCBRADDBR:
- return brc_add_del_bridge(uarg, 1);
+ return brc_add_del_bridge(net, uarg, 1);
case SIOCBRDELBR:
- return brc_add_del_bridge(uarg, 0);
+ return brc_add_del_bridge(net, uarg, 0);
}
return -EOPNOTSUPP;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- port = __dev_get_by_index(&init_net, port_ifindex);
+ port = __dev_get_by_index(dev_net(dev), port_ifindex);
if (!port)
return -EINVAL;
return -ENOMEM;
rtnl_unlock();
- err = brc_send_simple_command(request);
+ err = brc_send_simple_command(dev_net(dev), request);
rtnl_lock();
return err;
int retval;
rtnl_unlock();
- retval = brc_get_indices(BRC_GENL_C_GET_PORTS, dev->name,
+ retval = brc_get_indices(dev_net(dev), BRC_GENL_C_GET_PORTS, dev->name,
uindices, num);
rtnl_lock();
NLA_PUT_U64(request, BRC_GENL_A_FDB_SKIP, offset);
rtnl_unlock();
- reply = brc_send_command(request, attrs);
+ reply = brc_send_command(dev_net(dev), request, attrs);
retval = PTR_ERR(reply);
if (IS_ERR(reply))
goto exit;
.name = BRC_GENL_FAMILY_NAME,
.version = 1,
.maxattr = BRC_GENL_A_MAX,
+ SET_NETNSOK
};
static int brc_genl_query(struct sk_buff *skb, struct genl_info *info)
},
};
-static struct sk_buff *brc_send_command(struct sk_buff *request,
+static struct sk_buff *brc_send_command(struct net *net,
+ struct sk_buff *request,
struct nlattr **attrs)
{
unsigned long int flags;
nlmsg_end(request, nlmsg_hdr(request));
/* Send message. */
- error = genlmsg_multicast(request, 0, brc_mc_group.id, GFP_KERNEL);
+ error = genlmsg_multicast_netns(net, request, 0,
+ brc_mc_group.id, GFP_KERNEL);
if (error < 0)
goto error;
brioctl_set(brc_ioctl_deviceless_stub);
/* Set the openvswitch_mod device ioctl handler */
- dp_ioctl_hook = brc_dev_ioctl;
+ ovs_dp_ioctl_hook = brc_dev_ioctl;
/* Randomize the initial sequence number. This is not a security
* feature; it only helps avoid crossed wires between userspace and
static void brc_cleanup(void)
{
/* Unregister ioctl hooks */
- dp_ioctl_hook = NULL;
+ ovs_dp_ioctl_hook = NULL;
brioctl_set(NULL);
genl_unregister_family(&brc_genl_family);
MODULE_DESCRIPTION("Open vSwitch bridge compatibility");
MODULE_AUTHOR("Nicira Networks");
MODULE_LICENSE("GPL");
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+/*
+ * In kernels 2.6.36 and later, Open vSwitch can safely coexist with
+ * the Linux bridge module, but it does not make sense to load both bridge and
+ * brcompat_mod, so this prevents it.
+ */
+BRIDGE_MUTUAL_EXCLUSION;
+#endif