From: Ben Pfaff Date: Wed, 15 Jul 2009 19:40:16 +0000 (-0700) Subject: brcompat: Refactor infrastructure for communication with ovs-brcompatd. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e5307f55aa89b7ade27cb4bf92223c3b9c099eef;p=openvswitch 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. --- diff --git a/datapath/brcompat.c b/datapath/brcompat.c index 47805bc6..d945e4e6 100644 --- a/datapath/brcompat.c +++ b/datapath/brcompat.c @@ -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)