aboutsummaryrefslogtreecommitdiff
path: root/datapath/brcompat.c
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2009-08-07 15:11:40 -0700
committerBen Pfaff <blp@nicira.com>2009-08-07 15:11:40 -0700
commitdb322751d8bba32152e89eea476cb47a010616b1 (patch)
tree0813665b87e910e7dfdb9d0fe96cf6836b30c062 /datapath/brcompat.c
parentae1281cfa015b710817822002f21a4f6195cb740 (diff)
brcompat: Move BRCTL_GET_BRIDGES, BRCTL_GET_PORT_LIST into userspace.
The Citrix QA scripts assume that "brctl show" will show a topology as if the Linux bridge were still in use; that is, as if there were one bridge per VLAN and as if bonds were network devices of their own instead of separate devices. However, we were showing the datapath topology, i.e. all VLANs and bond devices lumped together into a single datapath. This commit fixes the VLAN end of the problem, by moving the implementation of the ioctls that brctl uses into userspace in ovs-brcompatd and putting the necessary translation logic into ovs-brcompatd. By itself, this commit does not fix the problem for bonds: the port name for a bond does not (normally) under Open vSwitch exist as an actual Linux network device, and thus it has no ifindex, and so ovs-brcompatd can't pass it back to the kernel to report to brctl. This fix will have to wait for another commit. Bug NIC-19.
Diffstat (limited to 'datapath/brcompat.c')
-rw-r--r--datapath/brcompat.c98
1 files changed, 44 insertions, 54 deletions
diff --git a/datapath/brcompat.c b/datapath/brcompat.c
index be361ece..10b94f73 100644
--- a/datapath/brcompat.c
+++ b/datapath/brcompat.c
@@ -45,36 +45,6 @@ static u32 brc_seq; /* Sequence number for current op. */
static struct sk_buff *brc_send_command(struct sk_buff *, struct nlattr **attrs);
static int brc_send_simple_command(struct sk_buff *);
-static int
-get_dp_ifindices(int *indices, int num)
-{
- int i, index = 0;
-
- rcu_read_lock();
- for (i=0; i < ODP_MAX && index < num; i++) {
- struct datapath *dp = get_dp(i);
- if (!dp)
- continue;
- indices[index++] = dp->ports[ODPP_LOCAL]->dev->ifindex;
- }
- rcu_read_unlock();
-
- return index;
-}
-
-static void
-get_port_ifindices(struct datapath *dp, int *ifindices, int num)
-{
- struct net_bridge_port *p;
-
- rcu_read_lock();
- list_for_each_entry_rcu (p, &dp->port_list, node) {
- if (p->port_no < num)
- ifindices[p->port_no] = p->dev->ifindex;
- }
- rcu_read_unlock();
-}
-
static struct sk_buff *
brc_make_request(int op, const char *bridge, const char *port)
{
@@ -83,7 +53,8 @@ brc_make_request(int op, const char *bridge, const char *port)
goto error;
genlmsg_put(skb, 0, 0, &brc_genl_family, 0, op);
- NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge);
+ if (bridge)
+ NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge);
if (port)
NLA_PUT_STRING(skb, BRC_GENL_A_PORT_NAME, port);
return skb;
@@ -126,26 +97,57 @@ static int brc_add_del_bridge(char __user *uname, int add)
return brc_send_simple_command(request);
}
-static int brc_get_bridges(int __user *uindices, int n)
+static int brc_get_indices(int op, const char *br_name,
+ int __user *uindices, int n)
{
+ struct nlattr *attrs[BRC_GENL_A_MAX + 1];
+ struct sk_buff *request, *reply;
int *indices;
int ret;
+ int len;
+ if (n < 0)
+ return -EINVAL;
if (n >= 2048)
return -ENOMEM;
- indices = kcalloc(n, sizeof(int), GFP_KERNEL);
- if (indices == NULL)
+ request = brc_make_request(op, br_name, NULL);
+ if (!request)
return -ENOMEM;
- n = get_dp_ifindices(indices, n);
+ reply = brc_send_command(request, attrs);
+ ret = PTR_ERR(reply);
+ if (IS_ERR(reply))
+ goto exit;
+
+ ret = -nla_get_u32(attrs[BRC_GENL_A_ERR_CODE]);
+ if (ret < 0)
+ goto exit_free_skb;
+
+ ret = -EINVAL;
+ if (!attrs[BRC_GENL_A_IFINDEXES])
+ goto exit_free_skb;
+
+ len = nla_len(attrs[BRC_GENL_A_IFINDEXES]);
+ indices = nla_data(attrs[BRC_GENL_A_IFINDEXES]);
+ if (len % sizeof(int))
+ goto exit_free_skb;
+ n = min_t(int, n, len / sizeof(int));
ret = copy_to_user(uindices, indices, n * sizeof(int)) ? -EFAULT : n;
- kfree(indices);
+exit_free_skb:
+ kfree_skb(reply);
+exit:
return ret;
}
+/* Called with br_ioctl_mutex. */
+static int brc_get_bridges(int __user *uindices, int n)
+{
+ return brc_get_indices(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)
@@ -238,26 +240,14 @@ brc_get_bridge_info(struct net_device *dev, struct __bridge_info __user *ub)
static int
brc_get_port_list(struct net_device *dev, int __user *uindices, int num)
{
- struct dp_dev *dp_dev = netdev_priv(dev);
- struct datapath *dp = dp_dev->dp;
- int *indices;
-
- if (num < 0)
- return -EINVAL;
- if (num == 0)
- num = 256;
- if (num > DP_MAX_PORTS)
- num = DP_MAX_PORTS;
+ int retval;
- indices = kcalloc(num, sizeof(int), GFP_KERNEL);
- if (indices == NULL)
- return -ENOMEM;
+ rtnl_unlock();
+ retval = brc_get_indices(BRC_GENL_C_GET_PORTS, dev->name,
+ uindices, num);
+ rtnl_lock();
- get_port_ifindices(dp, indices, num);
- if (copy_to_user(uindices, indices, num * sizeof(int)))
- num = -EFAULT;
- kfree(indices);
- return num;
+ return retval;
}
/*