mirror of
https://github.com/openvswitch/ovs
synced 2025-10-25 15:07:05 +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. */
|
||||
static DEFINE_SPINLOCK(brc_lock); /* Ensure atomic access to these vars. */
|
||||
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 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
|
||||
get_dp_ifindices(int *indices, int num)
|
||||
@@ -75,16 +76,55 @@ get_port_ifindices(struct datapath *dp, int *ifindices, int num)
|
||||
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)
|
||||
{
|
||||
struct sk_buff *request;
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
if (copy_from_user(name, uname, IFNAMSIZ))
|
||||
return -EFAULT;
|
||||
|
||||
name[IFNAMSIZ - 1] = 0;
|
||||
return brc_send_command(name, NULL,
|
||||
add ? BRC_GENL_C_DP_ADD : BRC_GENL_C_DP_DEL);
|
||||
request = brc_make_request(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)
|
||||
@@ -154,8 +194,8 @@ brc_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg)
|
||||
static int
|
||||
brc_add_del_port(struct net_device *dev, int port_ifindex, int add)
|
||||
{
|
||||
struct sk_buff *request;
|
||||
struct net_device *port;
|
||||
char dev_name[IFNAMSIZ], port_name[IFNAMSIZ];
|
||||
int err;
|
||||
|
||||
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;
|
||||
|
||||
/* Save name of dev and port because there's a race between the
|
||||
* rtnl_unlock() and the brc_send_command(). */
|
||||
strcpy(dev_name, dev->name);
|
||||
strcpy(port_name, port->name);
|
||||
* rtnl_unlock() and the brc_send_simple_command(). */
|
||||
request = brc_make_request(add ? BRC_GENL_C_PORT_ADD : BRC_GENL_C_PORT_DEL,
|
||||
dev->name, port->name);
|
||||
if (!request)
|
||||
return -ENOMEM;
|
||||
|
||||
rtnl_unlock();
|
||||
err = brc_send_command(dev_name, port_name,
|
||||
add ? BRC_GENL_C_PORT_ADD : BRC_GENL_C_PORT_DEL);
|
||||
err = brc_send_simple_command(request);
|
||||
rtnl_lock();
|
||||
|
||||
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])
|
||||
return -EINVAL;
|
||||
|
||||
skb = skb_clone(skb, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&brc_lock, flags);
|
||||
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);
|
||||
err = 0;
|
||||
} else {
|
||||
kfree_skb(skb);
|
||||
err = -ESTALE;
|
||||
}
|
||||
spin_unlock_irqrestore(&brc_lock, flags);
|
||||
@@ -359,11 +410,10 @@ static struct genl_ops brc_genl_ops_set_proc = {
|
||||
.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;
|
||||
struct sk_buff *skb;
|
||||
void *data;
|
||||
struct sk_buff *reply;
|
||||
int error;
|
||||
|
||||
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
|
||||
* to stale requests. */
|
||||
spin_lock_irqsave(&brc_lock, flags);
|
||||
brc_seq++;
|
||||
nlmsg_hdr(request)->nlmsg_seq = ++brc_seq;
|
||||
INIT_COMPLETION(brc_done);
|
||||
spin_unlock_irqrestore(&brc_lock, flags);
|
||||
|
||||
/* Compose message. */
|
||||
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);
|
||||
nlmsg_end(request, nlmsg_hdr(request));
|
||||
|
||||
/* 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)
|
||||
goto exit_unlock;
|
||||
goto error;
|
||||
|
||||
/* Wait for reply. */
|
||||
error = -ETIMEDOUT;
|
||||
if (!wait_for_completion_timeout(&brc_done, BRC_TIMEOUT))
|
||||
goto exit_unlock;
|
||||
goto error;
|
||||
|
||||
error = -brc_err;
|
||||
goto exit_unlock;
|
||||
/* Grab reply. */
|
||||
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);
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user