Commit ba0dc5f6 authored by Johannes Berg's avatar Johannes Berg Committed by David S. Miller

netlink: allow sending extended ACK with cookie on success

Now that we have extended error reporting and a new message format for
netlink ACK messages, also extend this to be able to return arbitrary
cookie data on success.

This will allow, for example, nl80211 to not send an extra message for
cookies identifying newly created objects, but return those directly
in the ACK message.

The cookie data size is currently limited to 20 bytes (since Jamal
talked about using SHA1 for identifiers.)

Thanks to Jamal Hadi Salim for bringing up this idea during the
discussions.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Reviewed-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7ab606d1
...@@ -62,15 +62,22 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg) ...@@ -62,15 +62,22 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
return __netlink_kernel_create(net, unit, THIS_MODULE, cfg); return __netlink_kernel_create(net, unit, THIS_MODULE, cfg);
} }
/* this can be increased when necessary - don't expose to userland */
#define NETLINK_MAX_COOKIE_LEN 20
/** /**
* struct netlink_ext_ack - netlink extended ACK report struct * struct netlink_ext_ack - netlink extended ACK report struct
* @_msg: message string to report - don't access directly, use * @_msg: message string to report - don't access directly, use
* %NL_SET_ERR_MSG * %NL_SET_ERR_MSG
* @bad_attr: attribute with error * @bad_attr: attribute with error
* @cookie: cookie data to return to userspace (for success)
* @cookie_len: actual cookie data length
*/ */
struct netlink_ext_ack { struct netlink_ext_ack {
const char *_msg; const char *_msg;
const struct nlattr *bad_attr; const struct nlattr *bad_attr;
u8 cookie[NETLINK_MAX_COOKIE_LEN];
u8 cookie_len;
}; };
/* Always use this macro, this allows later putting the /* Always use this macro, this allows later putting the
......
...@@ -122,6 +122,9 @@ struct nlmsgerr { ...@@ -122,6 +122,9 @@ struct nlmsgerr {
* @NLMSGERR_ATTR_MSG: error message string (string) * @NLMSGERR_ATTR_MSG: error message string (string)
* @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
* message, counting from the beginning of the header (u32) * message, counting from the beginning of the header (u32)
* @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
* be used - in the success case - to identify a created
* object or operation or similar (binary)
* @__NLMSGERR_ATTR_MAX: number of attributes * @__NLMSGERR_ATTR_MAX: number of attributes
* @NLMSGERR_ATTR_MAX: highest attribute number * @NLMSGERR_ATTR_MAX: highest attribute number
*/ */
...@@ -129,6 +132,7 @@ enum nlmsgerr_attrs { ...@@ -129,6 +132,7 @@ enum nlmsgerr_attrs {
NLMSGERR_ATTR_UNUSED, NLMSGERR_ATTR_UNUSED,
NLMSGERR_ATTR_MSG, NLMSGERR_ATTR_MSG,
NLMSGERR_ATTR_OFFS, NLMSGERR_ATTR_OFFS,
NLMSGERR_ATTR_COOKIE,
__NLMSGERR_ATTR_MAX, __NLMSGERR_ATTR_MAX,
NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
......
...@@ -2311,6 +2311,10 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err, ...@@ -2311,6 +2311,10 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
} }
} else { } else {
flags |= NLM_F_CAPPED; flags |= NLM_F_CAPPED;
if (nlk->flags & NETLINK_F_EXT_ACK &&
extack && extack->cookie_len)
tlvlen += nla_total_size(extack->cookie_len);
} }
if (tlvlen) if (tlvlen)
...@@ -2337,17 +2341,24 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err, ...@@ -2337,17 +2341,24 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
errmsg->error = err; errmsg->error = err;
memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh)); memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
if (err && nlk->flags & NETLINK_F_EXT_ACK && extack) { if (nlk->flags & NETLINK_F_EXT_ACK && extack) {
if (extack->_msg) if (err) {
WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG, if (extack->_msg)
extack->_msg)); WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
if (extack->bad_attr && extack->_msg));
!WARN_ON((u8 *)extack->bad_attr < in_skb->data || if (extack->bad_attr &&
(u8 *)extack->bad_attr >= in_skb->data + !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
in_skb->len)) (u8 *)extack->bad_attr >= in_skb->data +
WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS, in_skb->len))
(u8 *)extack->bad_attr - WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
in_skb->data)); (u8 *)extack->bad_attr -
in_skb->data));
} else {
if (extack->cookie_len)
WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
extack->cookie_len,
extack->cookie));
}
} }
nlmsg_end(skb, rep); nlmsg_end(skb, rep);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment