forked from Minki/linux
tipc: add publication dump to new netlink api
Add TIPC_NL_PUBL_GET command to the new tipc netlink API. This command supports dumping of all publications for a specific socket. Netlink logical layout of request message: -> socket -> reference Netlink logical layout of response message: -> publication -> type -> lower -> upper Signed-off-by: Richard Alpe <richard.alpe@ericsson.com> Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
34b78a127c
commit
1a1a143daf
@ -46,6 +46,7 @@ enum {
|
||||
TIPC_NL_BEARER_GET,
|
||||
TIPC_NL_BEARER_SET,
|
||||
TIPC_NL_SOCK_GET,
|
||||
TIPC_NL_PUBL_GET,
|
||||
|
||||
__TIPC_NL_CMD_MAX,
|
||||
TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
|
||||
@ -56,6 +57,7 @@ enum {
|
||||
TIPC_NLA_UNSPEC,
|
||||
TIPC_NLA_BEARER, /* nest */
|
||||
TIPC_NLA_SOCK, /* nest */
|
||||
TIPC_NLA_PUBL, /* nest */
|
||||
|
||||
__TIPC_NLA_MAX,
|
||||
TIPC_NLA_MAX = __TIPC_NLA_MAX - 1
|
||||
@ -84,6 +86,22 @@ enum {
|
||||
TIPC_NLA_SOCK_MAX = __TIPC_NLA_SOCK_MAX - 1
|
||||
};
|
||||
|
||||
/* Publication info */
|
||||
enum {
|
||||
TIPC_NLA_PUBL_UNSPEC,
|
||||
|
||||
TIPC_NLA_PUBL_TYPE, /* u32 */
|
||||
TIPC_NLA_PUBL_LOWER, /* u32 */
|
||||
TIPC_NLA_PUBL_UPPER, /* u32 */
|
||||
TIPC_NLA_PUBL_SCOPE, /* u32 */
|
||||
TIPC_NLA_PUBL_NODE, /* u32 */
|
||||
TIPC_NLA_PUBL_REF, /* u32 */
|
||||
TIPC_NLA_PUBL_KEY, /* u32 */
|
||||
|
||||
__TIPC_NLA_PUBL_MAX,
|
||||
TIPC_NLA_PUBL_MAX = __TIPC_NLA_PUBL_MAX - 1
|
||||
};
|
||||
|
||||
/* Nest, connection info */
|
||||
enum {
|
||||
TIPC_NLA_CON_UNSPEC,
|
||||
|
@ -74,6 +74,7 @@ static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = {
|
||||
[TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, },
|
||||
[TIPC_NLA_BEARER] = { .type = NLA_NESTED, },
|
||||
[TIPC_NLA_SOCK] = { .type = NLA_NESTED, },
|
||||
[TIPC_NLA_PUBL] = { .type = NLA_NESTED, }
|
||||
};
|
||||
|
||||
/* Legacy ASCII API */
|
||||
@ -130,9 +131,25 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
|
||||
.cmd = TIPC_NL_SOCK_GET,
|
||||
.dumpit = tipc_nl_sk_dump,
|
||||
.policy = tipc_nl_policy,
|
||||
},
|
||||
{
|
||||
.cmd = TIPC_NL_PUBL_GET,
|
||||
.dumpit = tipc_nl_publ_dump,
|
||||
.policy = tipc_nl_policy,
|
||||
}
|
||||
};
|
||||
|
||||
int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr)
|
||||
{
|
||||
u32 maxattr = tipc_genl_v2_family.maxattr;
|
||||
|
||||
*attr = tipc_genl_v2_family.attrbuf;
|
||||
if (!*attr)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return nlmsg_parse(nlh, GENL_HDRLEN, *attr, maxattr, tipc_nl_policy);
|
||||
}
|
||||
|
||||
int tipc_netlink_start(void)
|
||||
{
|
||||
int res;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#define _TIPC_NETLINK_H
|
||||
|
||||
extern struct genl_family tipc_genl_v2_family;
|
||||
int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***buf);
|
||||
|
||||
struct tipc_nl_msg {
|
||||
struct sk_buff *skb;
|
||||
|
@ -121,6 +121,14 @@ static const struct proto_ops msg_ops;
|
||||
static struct proto tipc_proto;
|
||||
static struct proto tipc_proto_kern;
|
||||
|
||||
static const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
|
||||
[TIPC_NLA_SOCK_UNSPEC] = { .type = NLA_UNSPEC },
|
||||
[TIPC_NLA_SOCK_ADDR] = { .type = NLA_U32 },
|
||||
[TIPC_NLA_SOCK_REF] = { .type = NLA_U32 },
|
||||
[TIPC_NLA_SOCK_CON] = { .type = NLA_NESTED },
|
||||
[TIPC_NLA_SOCK_HAS_PUBL] = { .type = NLA_FLAG }
|
||||
};
|
||||
|
||||
/*
|
||||
* Revised TIPC socket locking policy:
|
||||
*
|
||||
@ -2902,3 +2910,130 @@ int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
/* Caller should hold socket lock for the passed tipc socket. */
|
||||
int __tipc_nl_add_sk_publ(struct sk_buff *skb, struct netlink_callback *cb,
|
||||
struct publication *publ)
|
||||
{
|
||||
void *hdr;
|
||||
struct nlattr *attrs;
|
||||
|
||||
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
||||
&tipc_genl_v2_family, NLM_F_MULTI, TIPC_NL_PUBL_GET);
|
||||
if (!hdr)
|
||||
goto msg_cancel;
|
||||
|
||||
attrs = nla_nest_start(skb, TIPC_NLA_PUBL);
|
||||
if (!attrs)
|
||||
goto genlmsg_cancel;
|
||||
|
||||
if (nla_put_u32(skb, TIPC_NLA_PUBL_KEY, publ->key))
|
||||
goto attr_msg_cancel;
|
||||
if (nla_put_u32(skb, TIPC_NLA_PUBL_TYPE, publ->type))
|
||||
goto attr_msg_cancel;
|
||||
if (nla_put_u32(skb, TIPC_NLA_PUBL_LOWER, publ->lower))
|
||||
goto attr_msg_cancel;
|
||||
if (nla_put_u32(skb, TIPC_NLA_PUBL_UPPER, publ->upper))
|
||||
goto attr_msg_cancel;
|
||||
|
||||
nla_nest_end(skb, attrs);
|
||||
genlmsg_end(skb, hdr);
|
||||
|
||||
return 0;
|
||||
|
||||
attr_msg_cancel:
|
||||
nla_nest_cancel(skb, attrs);
|
||||
genlmsg_cancel:
|
||||
genlmsg_cancel(skb, hdr);
|
||||
msg_cancel:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/* Caller should hold socket lock for the passed tipc socket. */
|
||||
int __tipc_nl_list_sk_publ(struct sk_buff *skb, struct netlink_callback *cb,
|
||||
struct tipc_sock *tsk, u32 *last_publ)
|
||||
{
|
||||
int err;
|
||||
struct publication *p;
|
||||
|
||||
if (*last_publ) {
|
||||
list_for_each_entry(p, &tsk->publications, pport_list) {
|
||||
if (p->key == *last_publ)
|
||||
break;
|
||||
}
|
||||
if (p->key != *last_publ) {
|
||||
/* We never set seq or call nl_dump_check_consistent()
|
||||
* this means that setting prev_seq here will cause the
|
||||
* consistence check to fail in the netlink callback
|
||||
* handler. Resulting in the last NLMSG_DONE message
|
||||
* having the NLM_F_DUMP_INTR flag set.
|
||||
*/
|
||||
cb->prev_seq = 1;
|
||||
*last_publ = 0;
|
||||
return -EPIPE;
|
||||
}
|
||||
} else {
|
||||
p = list_first_entry(&tsk->publications, struct publication,
|
||||
pport_list);
|
||||
}
|
||||
|
||||
list_for_each_entry_from(p, &tsk->publications, pport_list) {
|
||||
err = __tipc_nl_add_sk_publ(skb, cb, p);
|
||||
if (err) {
|
||||
*last_publ = p->key;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
*last_publ = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
int err;
|
||||
u32 tsk_ref = cb->args[0];
|
||||
u32 last_publ = cb->args[1];
|
||||
u32 done = cb->args[2];
|
||||
struct tipc_sock *tsk;
|
||||
|
||||
if (!tsk_ref) {
|
||||
struct nlattr **attrs;
|
||||
struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1];
|
||||
|
||||
err = tipc_nlmsg_parse(cb->nlh, &attrs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = nla_parse_nested(sock, TIPC_NLA_SOCK_MAX,
|
||||
attrs[TIPC_NLA_SOCK],
|
||||
tipc_nl_sock_policy);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!sock[TIPC_NLA_SOCK_REF])
|
||||
return -EINVAL;
|
||||
|
||||
tsk_ref = nla_get_u32(sock[TIPC_NLA_SOCK_REF]);
|
||||
}
|
||||
|
||||
if (done)
|
||||
return 0;
|
||||
|
||||
tsk = tipc_sk_get(tsk_ref);
|
||||
if (!tsk)
|
||||
return -EINVAL;
|
||||
|
||||
lock_sock(&tsk->sk);
|
||||
err = __tipc_nl_list_sk_publ(skb, cb, tsk, &last_publ);
|
||||
if (!err)
|
||||
done = 1;
|
||||
release_sock(&tsk->sk);
|
||||
tipc_sk_put(tsk);
|
||||
|
||||
cb->args[0] = tsk_ref;
|
||||
cb->args[1] = last_publ;
|
||||
cb->args[2] = done;
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
@ -49,5 +49,6 @@ void tipc_sk_reinit(void);
|
||||
int tipc_sk_ref_table_init(u32 requested_size, u32 start);
|
||||
void tipc_sk_ref_table_stop(void);
|
||||
int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user