forked from Minki/linux
netlink: add support for ext_ack missing attributes
There is currently no way to report via extack in a structured way that an attribute is missing. This leads to families resorting to string messages. Add a pair of attributes - @offset and @type for machine-readable way of reporting missing attributes. The @offset points to the nest which should have contained the attribute, @type is the expected nla_type. The offset will be skipped if the attribute is missing at the message level rather than inside a nest. User space should be able to figure out which attribute enum (AKA attribute space AKA attribute set) the nest pointed to by @offset is using. Reviewed-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
0c95cea24f
commit
690252f19f
@ -359,8 +359,8 @@ compatibility this feature has to be explicitly enabled by setting
|
||||
the ``NETLINK_EXT_ACK`` setsockopt() to ``1``.
|
||||
|
||||
Types of extended ack attributes are defined in enum nlmsgerr_attrs.
|
||||
The two most commonly used attributes are ``NLMSGERR_ATTR_MSG``
|
||||
and ``NLMSGERR_ATTR_OFFS``.
|
||||
The most commonly used attributes are ``NLMSGERR_ATTR_MSG``,
|
||||
``NLMSGERR_ATTR_OFFS`` and ``NLMSGERR_ATTR_MISS_*``.
|
||||
|
||||
``NLMSGERR_ATTR_MSG`` carries a message in English describing
|
||||
the encountered problem. These messages are far more detailed
|
||||
@ -368,6 +368,9 @@ than what can be expressed thru standard UNIX error codes.
|
||||
|
||||
``NLMSGERR_ATTR_OFFS`` points to the attribute which caused the problem.
|
||||
|
||||
``NLMSGERR_ATTR_MISS_TYPE`` and ``NLMSGERR_ATTR_MISS_NEST``
|
||||
inform about a missing attribute.
|
||||
|
||||
Extended ACKs can be reported on errors as well as in case of success.
|
||||
The latter should be treated as a warning.
|
||||
|
||||
|
@ -71,6 +71,8 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
|
||||
* %NL_SET_ERR_MSG
|
||||
* @bad_attr: attribute with error
|
||||
* @policy: policy for a bad attribute
|
||||
* @miss_type: attribute type which was missing
|
||||
* @miss_nest: nest missing an attribute (%NULL if missing top level attr)
|
||||
* @cookie: cookie data to return to userspace (for success)
|
||||
* @cookie_len: actual cookie data length
|
||||
*/
|
||||
@ -78,6 +80,8 @@ struct netlink_ext_ack {
|
||||
const char *_msg;
|
||||
const struct nlattr *bad_attr;
|
||||
const struct nla_policy *policy;
|
||||
const struct nlattr *miss_nest;
|
||||
u16 miss_type;
|
||||
u8 cookie[NETLINK_MAX_COOKIE_LEN];
|
||||
u8 cookie_len;
|
||||
};
|
||||
@ -126,6 +130,15 @@ struct netlink_ext_ack {
|
||||
#define NL_SET_ERR_MSG_ATTR(extack, attr, msg) \
|
||||
NL_SET_ERR_MSG_ATTR_POL(extack, attr, NULL, msg)
|
||||
|
||||
#define NL_SET_ERR_ATTR_MISS(extack, nest, type) do { \
|
||||
struct netlink_ext_ack *__extack = (extack); \
|
||||
\
|
||||
if (__extack) { \
|
||||
__extack->miss_nest = (nest); \
|
||||
__extack->miss_type = (type); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline void nl_set_extack_cookie_u64(struct netlink_ext_ack *extack,
|
||||
u64 cookie)
|
||||
{
|
||||
|
@ -140,6 +140,10 @@ struct nlmsgerr {
|
||||
* be used - in the success case - to identify a created
|
||||
* object or operation or similar (binary)
|
||||
* @NLMSGERR_ATTR_POLICY: policy for a rejected attribute
|
||||
* @NLMSGERR_ATTR_MISS_TYPE: type of a missing required attribute,
|
||||
* %NLMSGERR_ATTR_MISS_NEST will not be present if the attribute was
|
||||
* missing at the message level
|
||||
* @NLMSGERR_ATTR_MISS_NEST: offset of the nest where attribute was missing
|
||||
* @__NLMSGERR_ATTR_MAX: number of attributes
|
||||
* @NLMSGERR_ATTR_MAX: highest attribute number
|
||||
*/
|
||||
@ -149,6 +153,8 @@ enum nlmsgerr_attrs {
|
||||
NLMSGERR_ATTR_OFFS,
|
||||
NLMSGERR_ATTR_COOKIE,
|
||||
NLMSGERR_ATTR_POLICY,
|
||||
NLMSGERR_ATTR_MISS_TYPE,
|
||||
NLMSGERR_ATTR_MISS_NEST,
|
||||
|
||||
__NLMSGERR_ATTR_MAX,
|
||||
NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
|
||||
|
@ -2423,6 +2423,10 @@ netlink_ack_tlv_len(struct netlink_sock *nlk, int err,
|
||||
tlvlen += nla_total_size(sizeof(u32));
|
||||
if (extack->policy)
|
||||
tlvlen += netlink_policy_dump_attr_size_estimate(extack->policy);
|
||||
if (extack->miss_type)
|
||||
tlvlen += nla_total_size(sizeof(u32));
|
||||
if (extack->miss_nest)
|
||||
tlvlen += nla_total_size(sizeof(u32));
|
||||
|
||||
return tlvlen;
|
||||
}
|
||||
@ -2449,6 +2453,14 @@ netlink_ack_tlv_fill(struct sk_buff *in_skb, struct sk_buff *skb,
|
||||
if (extack->policy)
|
||||
netlink_policy_dump_write_attr(skb, extack->policy,
|
||||
NLMSGERR_ATTR_POLICY);
|
||||
if (extack->miss_type)
|
||||
WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_TYPE,
|
||||
extack->miss_type));
|
||||
if (extack->miss_nest &&
|
||||
!WARN_ON((u8 *)extack->miss_nest < in_skb->data ||
|
||||
(u8 *)extack->miss_nest > in_skb->data + in_skb->len))
|
||||
WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_NEST,
|
||||
(u8 *)extack->miss_nest - (u8 *)nlh));
|
||||
}
|
||||
|
||||
void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
|
||||
|
Loading…
Reference in New Issue
Block a user