OS-5815: lxbrand should support MCAST_JOIN_GROUP

Details

Issue Type:Bug
Priority:4 - Normal
Status:Resolved
Created at:2016-11-23T19:15:13.000Z
Updated at:2019-08-11T17:28:24.198Z

People

Created by:Michael Zeller
Reported by:Michael Zeller

Resolution

Fixed: A fix for this issue is checked into the tree and tested.
(Resolution Date: 2017-11-01T18:57:31.000Z)

Fix Versions

2017-11-09 Edge (Release Date: 2017-11-09)

Labels

lxbrand

Description

Testing a linux application that relies on bonjour (mDNS) for local discovery of a device on a non fabric network results in the following"

[pid 37229] setsockopt(9, SOL_IPV6, 0x2a /* IPV6_??? */, "\1\0\0\0\0\0\0\0\n\0\0\0\0\0\0\0\377\2\0\0\0\0\0\0\0\0\0\0\0\0\0\373"..., 136) = -1 ENOPROTOOPT (Protocol not available)
[pid 37229] setsockopt(4, SOL_IP, 0x2a /* IP_??? */, "\2\0\0\0\0\0\0\0\2\0\0\0\340\0\0\373\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 136) = -1 ENOPROTOOPT (Protocol not available)
[pid 37229] setsockopt(9, SOL_IPV6, 0x2a /* IPV6_??? */, "\2\0\0\0\0\0\0\0\n\0\0\0\0\0\0\0\377\2\0\0\0\0\0\0\0\0\0\0\0\0\0\373"..., 136) = -1 ENOPROTOOPT (Protocol not available)
[pid 37229] write(2, "2016/11/23 18:48:26 [SYS] Bonjou"..., 1122016/11/23 18:48:26 [SYS] Bonjour failed to register service: Failed to join multicast group on all interfaces!

The definitions for that block of sockopts is noted in the Linux source:

/*
 * Multicast:
 * Following socket options are shared between IPv4 and IPv6.
 *
 * MCAST_JOIN_GROUP     42
 * MCAST_BLOCK_SOURCE       43
 * MCAST_UNBLOCK_SOURCE     44
 * MCAST_LEAVE_GROUP        45
 * MCAST_JOIN_SOURCE_GROUP  46
 * MCAST_LEAVE_SOURCE_GROUP 47
 * MCAST_MSFILTER       48
 */

lxbrand currently reports ENOPROTOOPT for MCAST_JOIN_GROUP

Comments

Comment by Michael Zeller
Created at 2017-10-20T22:51:53.000Z
Updated at 2019-08-11T17:28:24.192Z

For testing I am using this C program I hacked together that mimics the golang program that I originally used to discover this issue.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int mcast_join4() {
        int sockfd;
        struct sockaddr_in addr;
        struct sockaddr_in mcast;
        int on = 1;
        uint32_t interface = 1;
        struct group_req gr;

        if ((sockfd = socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP)) < 0) {
                perror("cannot create socket");
                exit(EXIT_FAILURE);
        }

        printf("socketfd: %d\n", sockfd);

        if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
                perror("cannot set SO_BROADCAST");
                exit(EXIT_FAILURE);
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
                perror("cannot set SO_REUSEADDR");
                exit(EXIT_FAILURE);
        }

        printf("set socket options successfully\n");

        /* setup sockaddr for bind */
        memset(&addr, 0, sizeof (addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(5353);

        if (bind(sockfd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
                perror("cannot bind");
                exit(EXIT_FAILURE);
        }

        printf("bind successful\n");

        /* setup sockaddr for group_req */
        memset(&mcast, 0, sizeof (mcast));
        mcast.sin_family = AF_INET;
        mcast.sin_port = htons(0);
        inet_pton(AF_INET, "224.0.0.251", &mcast.sin_addr);

        memset(&gr, 0, sizeof (gr));
        gr.gr_interface = interface;
        bcopy(&mcast, &gr.gr_group, sizeof (mcast));

        if (setsockopt(sockfd, SOL_IP, MCAST_JOIN_GROUP, &gr, sizeof (gr)) < 0) {
                perror("failed to set MCAST_JOIN_GROUP");
                exit(EXIT_FAILURE);
        }

        printf("MCAST_JOIN_GROUP successful\n");

        if (setsockopt(sockfd, SOL_IP, MCAST_LEAVE_GROUP, &gr, sizeof (gr)) < 0) {
                perror("failed to set MCAST_LEAVE_GROUP");
                exit(EXIT_FAILURE);
        }

        printf("MCAST_LEAVE_GROUP successful\n");
        return 0;
}

int mcast_join6() {
        int sockfd;
        struct sockaddr_in6 addr;
        struct sockaddr_in6 mcast;
        int on = 1;
        uint32_t interface = 1;
        struct group_req gr;

        if ((sockfd = socket(PF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP)) < 0) {
                perror("cannot create socket");
                exit(EXIT_FAILURE);
        }

        printf("socketfd: %d\n", sockfd);

        if (setsockopt(sockfd, SOL_IPV6, IPV6_V6ONLY, &on, sizeof (on)) < 0) {
                perror("cannot set IPV6_V6ONLY");
                exit(EXIT_FAILURE);
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
                perror("cannot set SO_BROADCAST");
                exit(EXIT_FAILURE);
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
                perror("cannot set SO_BROADCAST");
                exit(EXIT_FAILURE);
        }

        printf("set socket options successfully\n");

        /* setup sockaddr for bind */
        memset(&addr, 0, sizeof (addr));
        addr.sin6_family = AF_INET6;
        addr.sin6_port = htons(5353);
        addr.sin6_flowinfo = 0;
        addr.sin6_scope_id = 0;
        inet_pton(AF_INET6, "::", &addr.sin6_addr);

        if (bind(sockfd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
                perror("cannot bind");
                exit(EXIT_FAILURE);
        }

        printf("bind successful\n");

        /* setup sockaddr for group_req */
        memset(&mcast, 0, sizeof (mcast));
        mcast.sin6_family = AF_INET6;
        mcast.sin6_port = htons(0);
        mcast.sin6_flowinfo = 0;
        mcast.sin6_scope_id = 0;
        inet_pton(AF_INET6, "ff02::fb", &mcast.sin6_addr);

        memset(&gr, 0, sizeof (gr));
        gr.gr_interface = interface;
        bcopy(&mcast, &gr.gr_group, sizeof (mcast));

        if (setsockopt(sockfd, SOL_IPV6, MCAST_JOIN_GROUP, &gr, sizeof (gr)) < 0) {
                perror("failed to set MCAST_JOIN_GROUP");
                exit(EXIT_FAILURE);
        }

        printf("MCAST_JOIN_GROUP successful\n");

        if (setsockopt(sockfd, SOL_IPV6, MCAST_LEAVE_GROUP, &gr, sizeof (gr)) < 0) {
                perror("failed to set MCAST_LEAVE_GROUP");
                exit(EXIT_FAILURE);
        }

        printf("MCAST_LEAVE_GROUP successful\n");
        return 0;
}

int main()
{
        printf("================== ipv4 ================\n");
        mcast_join4();
        printf("================== ipv6 ================\n");
        mcast_join6();
}

When running this in a 64-bit lx image it produces the following output.

root@b1547157-80ee-e2dc-c00b-f37a537b50b3:~/src/mcast# gcc -m64 main.c && ./a.out
================== ipv4 ================
socketfd: 3
set socket options successfully
bind successful
MCAST_JOIN_GROUP successful
MCAST_LEAVE_GROUP successful
================== ipv6 ================
socketfd: 4
set socket options successfully
bind successful
MCAST_JOIN_GROUP successful
MCAST_LEAVE_GROUP successful


root@b1547157-80ee-e2dc-c00b-f37a537b50b3:~/src/mcast# gcc -m32 main.c && ./a.out
================== ipv4 ================
socketfd: 3
set socket options successfully
bind successful
MCAST_JOIN_GROUP successful
MCAST_LEAVE_GROUP successful
================== ipv6 ================
socketfd: 4
set socket options successfully
bind successful
MCAST_JOIN_GROUP successful
MCAST_LEAVE_GROUP successful

====================== 32-bit image ======================

[root@headnode (coal) ~]# sdc-imgadm get 2b949baa-b5e7-11e7-ab3c-633666f5d2c0
{
  "v": 2,
  "uuid": "2b949baa-b5e7-11e7-ab3c-633666f5d2c0",
  "owner": "930896af-bf8c-48d4-885c-6573a94b1853",
  "name": "ubuntu-14.04-32-bit",
  "version": "20171020",
  "state": "active",
  "disabled": false,
  "public": false,
  "published_at": "2017-10-20T22:36:53Z",
  "type": "lx-dataset",
  "os": "linux",
  "files": [
    {
      "sha1": "b065fdd3c73a4ee6b7176ee436d7a40afe2963fa",
      "size": 127486409,
      "compression": "gzip"
    }
  ],
  "description": "Container-native Ubuntu Ubuntu 14.04 32-bit image. Built to run on containers with bare metal speed, while offering all the services of a typical unix host.",
  "homepage": "https://docs.joyent.com/images/container-native-linux",
  "requirements": {
    "networks": [
      {
        "name": "net0",
        "description": "public"
      }
    ],
    "min_platform": {
      "7.0": "20160317T000105Z"
    },
    "brand": "lx"
  },
  "tags": {
    "role": "os",
    "kernel_version": "3.13.0"
  }
}

And the results

root@7d497419-bbe5-47ce-ba48-b1a07fceb210:~/src/mcast# vim mcast.c
root@7d497419-bbe5-47ce-ba48-b1a07fceb210:~/src/mcast# gcc mcast.c
root@7d497419-bbe5-47ce-ba48-b1a07fceb210:~/src/mcast# strace -f -e setsockopt ./a.out
================== ipv4 ================
socketfd: 3
setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
set socket options successfully
bind successful
setsockopt(3, SOL_IP, 0x2a /* IP_??? */, "\1\0\0\0\2\0\0\0\340\0\0\373\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 132) = 0
MCAST_JOIN_GROUP successful
setsockopt(3, SOL_IP, 0x2d /* IP_??? */, "\1\0\0\0\2\0\0\0\340\0\0\373\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 132) = 0
MCAST_LEAVE_GROUP successful
================== ipv6 ================
socketfd: 4
setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0
setsockopt(4, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
set socket options successfully
bind successful
setsockopt(4, SOL_IPV6, 0x2a /* IPV6_??? */, "\1\0\0\0\n\0\0\0\0\0\0\0\377\2\0\0\0\0\0\0\0\0\0\0\0\0\0\373\0\0\0\0"..., 132) = 0
MCAST_JOIN_GROUP successful
setsockopt(4, SOL_IPV6, 0x2d /* IPV6_??? */, "\1\0\0\0\n\0\0\0\0\0\0\0\377\2\0\0\0\0\0\0\0\0\0\0\0\0\0\373\0\0\0\0"..., 132) = 0
MCAST_LEAVE_GROUP successful
+++ exited with 0 +++

Comment by Michael Zeller
Created at 2017-10-27T21:56:39.000Z

@accountid:6256367456e5a8006dd98083 @accountid:624b27045f63fd0069b53cd6 when you get a chance, let me know if there are any other tests that I should run against this patch.


Comment by Dan McDonald
Created at 2017-10-28T19:09:46.000Z
Updated at 2017-12-14T17:01:32.169Z

Did you re-attempt the golang binary that kicked this whole mess off?


Comment by Michael Zeller
Created at 2017-10-28T19:26:01.000Z

Yep the go binary is working. Im running a PI with these changes at home so I can run that software.


Comment by Former user
Created at 2017-11-01T18:48:07.000Z

illumos-joyent commit 9bd39d2 (branch master, by Mike Zeller)

OS-5815 lxbrand should support MCAST_JOIN_GROUP
Reviewed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Approved by: Dan McDonald <danmcd@joyent.com>