[CRIU] [PATCH 2/2] netlink: Diag core and basic socket info dumping (v2)

Pavel Emelyanov xemul at parallels.com
Thu Mar 14 10:26:38 EDT 2013


> +static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
> +			struct netlink_diag_req *req,
> +			u32 portid, u32 seq, u32 flags, int sk_ino)
> +{
> +	struct nlmsghdr *nlh;
> +	struct netlink_diag_msg *rep;
> +	struct netlink_sock *nlk = nlk_sk(sk);
> +
> +	nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
> +			flags);
> +	if (!nlh)
> +		return -EMSGSIZE;
> +
> +	rep = nlmsg_data(nlh);
> +	rep->ndiag_family	= AF_NETLINK;
> +	rep->ndiag_type		= sk->sk_type;
> +	rep->ndiag_protocol	= sk->sk_protocol;
> +	rep->ndiag_state	= sk->sk_state;
> +
> +	rep->ndiag_ino		= sk_ino;
> +	rep->ndiag_portid	= nlk->portid;
> +	rep->ndiag_groups	= nlk->groups ? (u32)nlk->groups[0] : 0;

Why do we need this duplication?

> +	rep->ndiag_ngroups	= nlk->ngroups;

This can be found out from RTA_PAYLOAD of NETLINK_DIAG_GROUPS.

> +	rep->ndiag_dst_portid	= nlk->dst_portid;
> +	rep->ndiag_dst_group	= nlk->dst_group;
> +	sock_diag_save_cookie(sk, rep->ndiag_cookie);
> +
> +	if ((req->ndiag_show & NDIAG_SHOW_GROUPS) &&
> +	    sk_diag_dump_groups(sk, skb))
> +		goto out_nlmsg_trim;
> +
> +	if ((req->ndiag_show & NDIAG_SHOW_MEMINFO) &&
> +	    sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO))
> +		goto out_nlmsg_trim;
> +
> +	return nlmsg_end(skb, nlh);
> +
> +out_nlmsg_trim:
> +	nlmsg_cancel(skb, nlh);
> +	return -EMSGSIZE;
> +}
> +
> +static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	int num = 0, s_num = cb->args[0];
> +	struct net *net = sock_net(skb->sk);
> +	struct netlink_diag_req *req;
> +	struct sock *sk;
> +	struct hlist_node *node;
> +	int i, j;
> +
> +	req = nlmsg_data(cb->nlh);
> +
> +	/* Make it possible to support protocol filtering later */
> +	if (req->sdiag_protocol)
> +		return -EINVAL;
> +
> +	read_lock(&nl_table_lock);
> +	for (i = 0; i < MAX_LINKS; i++) {
> +		struct nl_portid_hash *hash = &nl_table[i].hash;
> +
> +		for (j = 0; j <= hash->mask; j++) {
> +			sk_for_each(sk, node, &hash->table[j]) {
> +				if (!net_eq(sock_net(sk), net))
> +					continue;
> +				if (req->sdiag_protocol != 0 &&
> +				    sk->sk_protocol != req->sdiag_protocol)
> +					continue;

This was obviously not tested at all due to above check.

> +
> +				if (num < s_num)
> +					goto next;
> +
> +				if (sk_diag_fill(sk, skb, req,
> +						 NETLINK_CB(cb->skb).portid,
> +						 cb->nlh->nlmsg_seq,
> +						 NLM_F_MULTI,
> +						 sock_i_ino(sk)) < 0)
> +					goto done;
> +next:
> +				num++;
> +			}
> +		}
> +	}
> +done:
> +	read_unlock(&nl_table_lock);
> +	cb->args[0] = num;
> +
> +	return 0;
> +}
> +
> +static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
> +{
> +	int hdrlen = sizeof(struct netlink_diag_req);
> +	struct net *net = sock_net(skb->sk);
> +
> +	if (nlmsg_len(h) < hdrlen)
> +		return -EINVAL;
> +
> +	if (h->nlmsg_flags & NLM_F_DUMP) {
> +		struct netlink_dump_control c = {
> +			.dump = netlink_diag_dump,
> +		};
> +		return netlink_dump_start(net->diag_nlsk, skb, h, &c);
> +	} else
> +		return -EOPNOTSUPP;
> +}
> +
> +static const struct sock_diag_handler netlink_diag_handler = {
> +	.family = AF_NETLINK,
> +	.dump = netlink_diag_handler_dump,
> +};
> +
> +static int __init netlink_diag_init(void)
> +{
> +	return sock_diag_register(&netlink_diag_handler);
> +}
> +
> +static void __exit netlink_diag_exit(void)
> +{
> +	sock_diag_unregister(&netlink_diag_handler);
> +}
> +
> +module_init(netlink_diag_init);
> +module_exit(netlink_diag_exit);
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 1 /* AF_LOCAL */);
> 




More information about the CRIU mailing list