mirror of
https://github.com/openvswitch/ovs
synced 2025-10-27 15:18:06 +00:00
brcompat: Refactor infrastructure for communication with ovs-brcompatd.
In an upcoming change, brcompat will need to receive bulk data from ovs-brcompatd. The existing brcompat infrastructure for receiving data only supports returning an error code, so this commit adds the ability to receive an arbitrary sk_buff and updates the existing users to handle it.
This commit is contained in:
@@ -40,10 +40,11 @@ static DEFINE_MUTEX(brc_serial);
|
|||||||
/* Userspace communication. */
|
/* Userspace communication. */
|
||||||
static DEFINE_SPINLOCK(brc_lock); /* Ensure atomic access to these vars. */
|
static DEFINE_SPINLOCK(brc_lock); /* Ensure atomic access to these vars. */
|
||||||
static DECLARE_COMPLETION(brc_done); /* Userspace signaled operation done? */
|
static DECLARE_COMPLETION(brc_done); /* Userspace signaled operation done? */
|
||||||
static int brc_err; /* Error code from userspace. */
|
static struct sk_buff *brc_reply; /* Reply from userspace. */
|
||||||
static u32 brc_seq; /* Sequence number for current op. */
|
static u32 brc_seq; /* Sequence number for current op. */
|
||||||
|
|
||||||
static int brc_send_command(const char *bridge, const char *port, int 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
|
static int
|
||||||
get_dp_ifindices(int *indices, int num)
|
get_dp_ifindices(int *indices, int num)
|
||||||
@@ -75,16 +76,55 @@ get_port_ifindices(struct datapath *dp, int *ifindices, int num)
|
|||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct sk_buff *
|
||||||
|
brc_make_request(int op, const char *bridge, const char *port)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||||
|
if (!skb)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
genlmsg_put(skb, 0, 0, &brc_genl_family, 0, op);
|
||||||
|
NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge);
|
||||||
|
if (port)
|
||||||
|
NLA_PUT_STRING(skb, BRC_GENL_A_PORT_NAME, port);
|
||||||
|
return skb;
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
kfree_skb(skb);
|
||||||
|
error:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brc_send_simple_command(struct sk_buff *request)
|
||||||
|
{
|
||||||
|
struct nlattr *attrs[BRC_GENL_A_MAX + 1];
|
||||||
|
struct sk_buff *reply;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
reply = brc_send_command(request, attrs);
|
||||||
|
if (IS_ERR(reply))
|
||||||
|
return PTR_ERR(reply);
|
||||||
|
|
||||||
|
error = nla_get_u32(attrs[BRC_GENL_A_ERR_CODE]);
|
||||||
|
kfree_skb(reply);
|
||||||
|
return -error;
|
||||||
|
}
|
||||||
|
|
||||||
static int brc_add_del_bridge(char __user *uname, int add)
|
static int brc_add_del_bridge(char __user *uname, int add)
|
||||||
{
|
{
|
||||||
|
struct sk_buff *request;
|
||||||
char name[IFNAMSIZ];
|
char name[IFNAMSIZ];
|
||||||
|
|
||||||
if (copy_from_user(name, uname, IFNAMSIZ))
|
if (copy_from_user(name, uname, IFNAMSIZ))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
name[IFNAMSIZ - 1] = 0;
|
name[IFNAMSIZ - 1] = 0;
|
||||||
return brc_send_command(name, NULL,
|
request = brc_make_request(add ? BRC_GENL_C_DP_ADD : BRC_GENL_C_DP_DEL,
|
||||||
add ? BRC_GENL_C_DP_ADD : BRC_GENL_C_DP_DEL);
|
name, NULL);
|
||||||
|
if (!request)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return brc_send_simple_command(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brc_get_bridges(int __user *uindices, int n)
|
static int brc_get_bridges(int __user *uindices, int n)
|
||||||
@@ -154,8 +194,8 @@ brc_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg)
|
|||||||
static int
|
static int
|
||||||
brc_add_del_port(struct net_device *dev, int port_ifindex, int add)
|
brc_add_del_port(struct net_device *dev, int port_ifindex, int add)
|
||||||
{
|
{
|
||||||
|
struct sk_buff *request;
|
||||||
struct net_device *port;
|
struct net_device *port;
|
||||||
char dev_name[IFNAMSIZ], port_name[IFNAMSIZ];
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
port = __dev_get_by_index(&init_net, port_ifindex);
|
port = __dev_get_by_index(&init_net, port_ifindex);
|
||||||
@@ -163,13 +203,14 @@ brc_add_del_port(struct net_device *dev, int port_ifindex, int add)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Save name of dev and port because there's a race between the
|
/* Save name of dev and port because there's a race between the
|
||||||
* rtnl_unlock() and the brc_send_command(). */
|
* rtnl_unlock() and the brc_send_simple_command(). */
|
||||||
strcpy(dev_name, dev->name);
|
request = brc_make_request(add ? BRC_GENL_C_PORT_ADD : BRC_GENL_C_PORT_DEL,
|
||||||
strcpy(port_name, port->name);
|
dev->name, port->name);
|
||||||
|
if (!request)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
err = brc_send_command(dev_name, port_name,
|
err = brc_send_simple_command(request);
|
||||||
add ? BRC_GENL_C_PORT_ADD : BRC_GENL_C_PORT_DEL);
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@@ -330,12 +371,22 @@ brc_genl_dp_result(struct sk_buff *skb, struct genl_info *info)
|
|||||||
if (!info->attrs[BRC_GENL_A_ERR_CODE])
|
if (!info->attrs[BRC_GENL_A_ERR_CODE])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
skb = skb_clone(skb, GFP_KERNEL);
|
||||||
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_irqsave(&brc_lock, flags);
|
spin_lock_irqsave(&brc_lock, flags);
|
||||||
if (brc_seq == info->snd_seq) {
|
if (brc_seq == info->snd_seq) {
|
||||||
brc_err = nla_get_u32(info->attrs[BRC_GENL_A_ERR_CODE]);
|
brc_seq++;
|
||||||
|
|
||||||
|
if (brc_reply)
|
||||||
|
kfree_skb(brc_reply);
|
||||||
|
brc_reply = skb;
|
||||||
|
|
||||||
complete(&brc_done);
|
complete(&brc_done);
|
||||||
err = 0;
|
err = 0;
|
||||||
} else {
|
} else {
|
||||||
|
kfree_skb(skb);
|
||||||
err = -ESTALE;
|
err = -ESTALE;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&brc_lock, flags);
|
spin_unlock_irqrestore(&brc_lock, flags);
|
||||||
@@ -359,11 +410,10 @@ static struct genl_ops brc_genl_ops_set_proc = {
|
|||||||
.dumpit = NULL
|
.dumpit = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static int brc_send_command(const char *bridge, const char *port, int op)
|
static struct sk_buff *brc_send_command(struct sk_buff *request, struct nlattr **attrs)
|
||||||
{
|
{
|
||||||
unsigned long int flags;
|
unsigned long int flags;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *reply;
|
||||||
void *data;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
mutex_lock(&brc_serial);
|
mutex_lock(&brc_serial);
|
||||||
@@ -371,41 +421,41 @@ static int brc_send_command(const char *bridge, const char *port, int op)
|
|||||||
/* Increment sequence number first, so that we ignore any replies
|
/* Increment sequence number first, so that we ignore any replies
|
||||||
* to stale requests. */
|
* to stale requests. */
|
||||||
spin_lock_irqsave(&brc_lock, flags);
|
spin_lock_irqsave(&brc_lock, flags);
|
||||||
brc_seq++;
|
nlmsg_hdr(request)->nlmsg_seq = ++brc_seq;
|
||||||
INIT_COMPLETION(brc_done);
|
INIT_COMPLETION(brc_done);
|
||||||
spin_unlock_irqrestore(&brc_lock, flags);
|
spin_unlock_irqrestore(&brc_lock, flags);
|
||||||
|
|
||||||
/* Compose message. */
|
nlmsg_end(request, nlmsg_hdr(request));
|
||||||
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
|
||||||
error = -ENOMEM;
|
|
||||||
if (skb == NULL)
|
|
||||||
goto exit_unlock;
|
|
||||||
data = genlmsg_put(skb, 0, brc_seq, &brc_genl_family, 0, op);
|
|
||||||
|
|
||||||
NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge);
|
|
||||||
if (port)
|
|
||||||
NLA_PUT_STRING(skb, BRC_GENL_A_PORT_NAME, port);
|
|
||||||
|
|
||||||
genlmsg_end(skb, data);
|
|
||||||
|
|
||||||
/* Send message. */
|
/* Send message. */
|
||||||
error = genlmsg_multicast(skb, 0, brc_mc_group.id, GFP_KERNEL);
|
error = genlmsg_multicast(request, 0, brc_mc_group.id, GFP_KERNEL);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto exit_unlock;
|
goto error;
|
||||||
|
|
||||||
/* Wait for reply. */
|
/* Wait for reply. */
|
||||||
error = -ETIMEDOUT;
|
error = -ETIMEDOUT;
|
||||||
if (!wait_for_completion_timeout(&brc_done, BRC_TIMEOUT))
|
if (!wait_for_completion_timeout(&brc_done, BRC_TIMEOUT))
|
||||||
goto exit_unlock;
|
goto error;
|
||||||
|
|
||||||
error = -brc_err;
|
/* Grab reply. */
|
||||||
goto exit_unlock;
|
spin_lock_irqsave(&brc_lock, flags);
|
||||||
|
reply = brc_reply;
|
||||||
|
brc_reply = NULL;
|
||||||
|
spin_unlock_irqrestore(&brc_lock, flags);
|
||||||
|
|
||||||
nla_put_failure:
|
|
||||||
kfree_skb(skb);
|
|
||||||
exit_unlock:
|
|
||||||
mutex_unlock(&brc_serial);
|
mutex_unlock(&brc_serial);
|
||||||
return error;
|
|
||||||
|
/* Re-parse message. Can't fail, since it parsed correctly once
|
||||||
|
* already. */
|
||||||
|
error = nlmsg_parse(nlmsg_hdr(reply), GENL_HDRLEN,
|
||||||
|
attrs, BRC_GENL_A_MAX, brc_genl_policy);
|
||||||
|
WARN_ON(error);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
|
||||||
|
error:
|
||||||
|
mutex_unlock(&brc_serial);
|
||||||
|
return ERR_PTR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int brc_add_dp(struct datapath *dp)
|
int brc_add_dp(struct datapath *dp)
|
||||||
|
|||||||
Reference in New Issue
Block a user