[CRIU] Re: [PATCH 6/7] sockets: Restore unbound inet sockets
Pavel Emelyanov
xemul at parallels.com
Tue May 15 16:56:24 EDT 2012
On 05/12/2012 07:47 PM, Cyrill Gorcunov wrote:
>
> Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
> ---
> sk-inet.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
> sockets.c | 10 +++-
> 2 files changed, 174 insertions(+), 12 deletions(-)
>
> +static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p)
> +{
> + struct inet_sk_desc *sk = xzalloc(sizeof(*sk));
> + union {
> + struct sockaddr_in v4;
> + struct sockaddr_in6 v6;
> + } addr;
> + socklen_t len;
> + int ret = 0;
> +
> + if (!sk)
> + goto err;
> +
> +#define __CR_GET_SOPT(lfd, n, v) \
> + ({ \
> + len = sizeof(*v); \
> + int __r = getsockopt(lfd, SOL_SOCKET, n, v, &len); \
> + if (__r) \
> + pr_perror("getsockopt failed on %d", p->fd); \
> + __r; \
> + })
Use do_dump_opt from sockets.c file. They do this error reporting and
also check option length to be correct.
> + sk->sd.ino = p->stat.st_ino;
> + sk->state = TCP_CLOSE;
> +
> + /*
> + * The restored application will pass backlog explicitly
> + * on a listen call (if needed) so put some sane value here.
> + */
> + sk->wqlen = 16;
> +
> + ret |= __CR_GET_SOPT(lfd, SO_DOMAIN, &sk->sd.family);
> + ret |= __CR_GET_SOPT(lfd, SO_TYPE, &sk->type);
> + ret |= __CR_GET_SOPT(lfd, SO_PROTOCOL, &sk->proto);
> + if (ret)
> + goto err;
> +
> +#undef __CR_GET_SOPT
> +
> +
> + switch (sk->sd.family) {
> + case AF_INET:
> + case AF_INET6:
> + break;
> + default:
> + pr_err("Unsupported socket family %d on %d\n",
> + sk->sd.family, p->fd);
> + goto err;
> + }
> +
> + switch (sk->type) {
> + case SOCK_DGRAM:
> + case SOCK_STREAM:
> + break;
> + default:
> + pr_err("Unsupported socket type %d on %d\n",
> + sk->type, p->fd);
> + goto err;
> + }
This check is done in generic inet socket dump
> + switch (sk->proto) {
> + case IPPROTO_IP:
> + case IPPROTO_TCP:
> + case IPPROTO_UDP:
> + case IPPROTO_UDPLITE:
> + break;
> + default:
> + pr_err("Unsupported socket proto %d on %d\n",
> + sk->proto, p->fd);
> + goto err;
> + }
So is this.
> + if (sk->sd.family == AF_INET) {
> + len = sizeof(addr.v4);
> + ret = getsockname(lfd, (struct sockaddr *)&addr.v4, &len);
This requires an explanation. If a socket has a name, this means it's bound,
but in this case it should have been reported via netlink.
> + if (ret) {
> + if (errno != ENOTCONN) {
> + pr_perror("getsockname failed on %d", p->fd);
> + goto err;
> + }
> + } else {
> + sk->src_port = addr.v4.sin_port;
> + memcpy(sk->src_addr, &addr.v4.sin_addr.s_addr, sizeof(addr.v4.sin_addr.s_addr));
> + }
> +
> + len = sizeof(addr.v4);
> + ret = getpeername(lfd, (struct sockaddr *)&addr.v4, &len);
Same here -- connected sockets are hashed and are reported via netlink. Aren't they?
> + if (ret) {
> + if (errno != ENOTCONN) {
> + pr_perror("getpeername failed on %d", p->fd);
> + goto err;
> + }
> + } else {
> + sk->dst_port = addr.v4.sin_port;
> + memcpy(sk->dst_addr, &addr.v4.sin_addr.s_addr, sizeof(addr.v4.sin_addr.s_addr));
> + }
> + } else if (sk->sd.family == AF_INET6) {
> + len = sizeof(addr.v6);
> + ret = getsockname(lfd, (struct sockaddr *)&addr.v6, &len);
> + if (ret) {
> + if (errno != ENOTCONN) {
> + pr_perror("getsockname failed on %d", p->fd);
> + goto err;
> + }
> + } else {
> + sk->src_port = addr.v6.sin6_port;
> + memcpy(sk->src_addr, &addr.v6.sin6_addr.s6_addr, sizeof(addr.v6.sin6_addr.s6_addr));
> + }
> +
> + len = sizeof(addr.v6);
> + ret = getpeername(lfd, (struct sockaddr *)&addr.v6, &len);
> + if (ret) {
> + if (errno != ENOTCONN) {
> + pr_perror("getpeername failed on %d", p->fd);
> + goto err;
> + }
> + } else {
> + sk->dst_port = addr.v6.sin6_port;
> + memcpy(sk->dst_addr, &addr.v6.sin6_addr.s6_addr, sizeof(addr.v6.sin6_addr.s6_addr));
> + }
> + } else
> + BUG_ON(1);
> +
> + return sk;
> +err:
> + xfree(sk);
> + return NULL;
> +}
> +
More information about the CRIU
mailing list