[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