On 2013/01/03 00:27, Stuart Henderson wrote:
> On 2013/01/01 18:26, Raphael Mazelier wrote:
> > I resent to ports since I think this list is more readen than ports-bugs.
> 
> Will take a look, thanks.
> 
> > I wrote a first 'naive' patch wich work, at least for me. (attached)
> > I was difficult to make a clean patch because quagga broke/change
> > their multicast api in lib/sockopt.c, removing (struct iface *iface)
> > parameter from their functions, and using (struct ip_mreq mreq) seems
> > not working. So I just reuse the old code and paste it directly in
> > opsf_network.c. Hope that more experimented people could make a
> > better patch and send it upstream.
> 
> This affects RIP too - I prefer to add a patch to the quagga port
> which reverts their relevant commits for now.
> 
> A nicer fix would be to support the RFC3678 API in the kernel.
> 

Can you give this a spin please?

Diff below, or there's a tar of the whole quagga/ port directory
attached if you have trouble applying it.

Index: Makefile
===================================================================
RCS file: /cvs/ports/net/quagga/Makefile,v
retrieving revision 1.31
diff -u -p -r1.31 Makefile
--- Makefile    8 Dec 2012 18:42:43 -0000       1.31
+++ Makefile    3 Jan 2013 00:48:29 -0000
@@ -3,7 +3,7 @@
 COMMENT=       multi-threaded routing daemon
 
 DISTNAME=      quagga-0.99.21
-REVISION=      0
+REVISION=      1
 SHARED_LIBS=   ospf            0.0 \
                ospfapiclient   0.0 \
                zebra           0.0
Index: patches/patch-lib_sockopt_c
===================================================================
RCS file: patches/patch-lib_sockopt_c
diff -N patches/patch-lib_sockopt_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_sockopt_c 3 Jan 2013 00:48:29 -0000
@@ -0,0 +1,237 @@
+$OpenBSD$
+
+Revert 69bf3a39; does not work on at least (Open/Net)BSD.
+This can be put back if we get RFC3678 support.
+
+--- lib/sockopt.c.orig Thu Jan  3 00:29:56 2013
++++ lib/sockopt.c      Thu Jan  3 00:29:45 2013
+@@ -197,7 +197,7 @@ setsockopt_ipv6_tclass(int sock, int tclass)
+ 
+ /*
+  * Process multicast socket options for IPv4 in an OS-dependent manner.
+- * Supported options are IP_{ADD,DROP}_MEMBERSHIP.
++ * Supported options are IP_MULTICAST_IF and IP_{ADD,DROP}_MEMBERSHIP.
+  *
+  * Many operating systems have a limit on the number of groups that
+  * can be joined per socket (where each group and local address
+@@ -217,133 +217,121 @@ setsockopt_ipv6_tclass(int sock, int tclass)
+  * allow leaves, or implicitly leave all groups joined to down interfaces.
+  */
+ int
+-setsockopt_ipv4_multicast(int sock,
++setsockopt_multicast_ipv4(int sock, 
+                       int optname, 
++                      struct in_addr if_addr /* required */,
+                       unsigned int mcast_addr,
+-                      unsigned int ifindex)
++                      unsigned int ifindex /* optional: if non-zero, may be
++                                                used instead of if_addr */)
+ {
+-#ifdef HAVE_RFC3678
+-  struct group_req gr;
+-  struct sockaddr_in *si;
+-  int ret;
+-  memset (&gr, 0, sizeof(gr));
+-  si = (struct sockaddr_in *)&gr.gr_group;
+-  gr.gr_interface = ifindex;
+-  si->sin_family = AF_INET;
+-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+-  si->sin_len = sizeof(struct sockaddr_in);
+-#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+-  si->sin_addr.s_addr = mcast_addr;
+-  ret = setsockopt(sock, IPPROTO_IP, (optname == IP_ADD_MEMBERSHIP) ? 
+-    MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
+-  if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
+-    {
+-      setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, 
sizeof(gr));
+-      ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, 
sizeof(gr));
+-    }
+-  return ret;
+ 
+-#elif defined(HAVE_STRUCT_IP_MREQN_IMR_IFINDEX) && !defined(__FreeBSD__)
++#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
++  /* This is better because it uses ifindex directly */
+   struct ip_mreqn mreqn;
+   int ret;
+   
+-  assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
+-  memset (&mreqn, 0, sizeof(mreqn));
+-
+-  mreqn.imr_multiaddr.s_addr = mcast_addr;
+-  mreqn.imr_ifindex = ifindex;
+-  
+-  ret = setsockopt(sock, IPPROTO_IP, optname,
+-                   (void *)&mreqn, sizeof(mreqn));
+-  if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
++  switch (optname)
+     {
+-      /* see above: handle possible problem when interface comes back up */
+-      char buf[1][INET_ADDRSTRLEN];
+-      zlog_info("setsockopt_ipv4_multicast attempting to drop and "
+-                "re-add (fd %d, mcast %s, ifindex %u)",
+-                sock,
+-                inet_ntop(AF_INET, &mreqn.imr_multiaddr,
+-                          buf[0], sizeof(buf[0])), ifindex);
+-      setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+-                 (void *)&mreqn, sizeof(mreqn));
+-      ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+-                       (void *)&mreqn, sizeof(mreqn));
++    case IP_MULTICAST_IF:
++    case IP_ADD_MEMBERSHIP:
++    case IP_DROP_MEMBERSHIP:
++      memset (&mreqn, 0, sizeof(mreqn));
++
++      if (mcast_addr)
++      mreqn.imr_multiaddr.s_addr = mcast_addr;
++      
++      if (ifindex)
++      mreqn.imr_ifindex = ifindex;
++      else
++      mreqn.imr_address = if_addr;
++      
++      ret = setsockopt(sock, IPPROTO_IP, optname,
++                     (void *)&mreqn, sizeof(mreqn));
++      if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == 
EADDRINUSE))
++        {
++        /* see above: handle possible problem when interface comes back up */
++        char buf[2][INET_ADDRSTRLEN];
++        zlog_info("setsockopt_multicast_ipv4 attempting to drop and "
++                  "re-add (fd %d, ifaddr %s, mcast %s, ifindex %u)",
++                  sock,
++                  inet_ntop(AF_INET, &if_addr, buf[0], sizeof(buf[0])),
++                  inet_ntop(AF_INET, &mreqn.imr_multiaddr,
++                            buf[1], sizeof(buf[1])), ifindex);
++        setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
++                   (void *)&mreqn, sizeof(mreqn));
++        ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
++                         (void *)&mreqn, sizeof(mreqn));
++        }
++      return ret;
++      break;
++
++    default:
++      /* Can out and give an understandable error */
++      errno = EINVAL;
++      return -1;
++      break;
+     }
+-  return ret;
+ 
+   /* Example defines for another OS, boilerplate off other code in this
+      function, AND handle optname as per other sections for consistency !! */
+   /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
+   /* Add your favourite OS here! */
+ 
+-#elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */ 
++#else /* #if OS_TYPE */ 
+   /* standard BSD API */
+ 
+   struct in_addr m;
+   struct ip_mreq mreq;
+   int ret;
+ 
+-  assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
++#ifdef HAVE_BSD_STRUCT_IP_MREQ_HACK
++  if (ifindex)
++    m.s_addr = htonl(ifindex);
++  else
++#endif
++    m = if_addr;
+ 
+-  m.s_addr = htonl(ifindex);
+-
+-  memset (&mreq, 0, sizeof(mreq));
+-  mreq.imr_multiaddr.s_addr = mcast_addr;
+-  mreq.imr_interface = m;
+-  
+-  ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq));
+-  if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
++  switch (optname)
+     {
+-      /* see above: handle possible problem when interface comes back up */
+-      char buf[1][INET_ADDRSTRLEN];
+-      zlog_info("setsockopt_ipv4_multicast attempting to drop and "
+-                "re-add (fd %d, mcast %s, ifindex %u)",
+-                sock,
+-                inet_ntop(AF_INET, &mreq.imr_multiaddr,
+-                          buf[0], sizeof(buf[0])), ifindex);
+-      setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+-                  (void *)&mreq, sizeof(mreq));
+-      ret = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+-                        (void *)&mreq, sizeof(mreq));
+-    }
+-  return ret;
++    case IP_MULTICAST_IF:
++      return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m)); 
++      break;
+ 
+-#else
+-  #error "Unsupported multicast API"
++    case IP_ADD_MEMBERSHIP:
++    case IP_DROP_MEMBERSHIP:
++      memset (&mreq, 0, sizeof(mreq));
++      mreq.imr_multiaddr.s_addr = mcast_addr;
++      mreq.imr_interface = m;
++      
++      ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, 
sizeof(mreq));
++      if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == 
EADDRINUSE))
++        {
++        /* see above: handle possible problem when interface comes back up */
++        char buf[2][INET_ADDRSTRLEN];
++        zlog_info("setsockopt_multicast_ipv4 attempting to drop and "
++                  "re-add (fd %d, ifaddr %s, mcast %s, ifindex %u)",
++                  sock,
++                  inet_ntop(AF_INET, &if_addr, buf[0], sizeof(buf[0])),
++                  inet_ntop(AF_INET, &mreq.imr_multiaddr,
++                            buf[1], sizeof(buf[1])), ifindex);
++        setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
++                    (void *)&mreq, sizeof(mreq));
++        ret = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
++                          (void *)&mreq, sizeof(mreq));
++        }
++      return ret;
++      break;
++      
++    default:
++      /* Can out and give an understandable error */
++      errno = EINVAL;
++      return -1;
++      break;
++    }
+ #endif /* #if OS_TYPE */
+ 
+ }
+ 
+-/*
+- * Set IP_MULTICAST_IF socket option in an OS-dependent manner.
+- */
+-int
+-setsockopt_ipv4_multicast_if(int sock,
+-                      unsigned int ifindex)
+-{
+-
+-#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
+-  struct ip_mreqn mreqn;
+-  memset (&mreqn, 0, sizeof(mreqn));
+-
+-  mreqn.imr_ifindex = ifindex;
+-  return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, 
sizeof(mreqn));
+-
+-  /* Example defines for another OS, boilerplate off other code in this
+-     function */
+-  /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
+-  /* Add your favourite OS here! */
+-#elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK)
+-  struct in_addr m;
+-
+-  m.s_addr = htonl(ifindex);
+-
+-  return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, 
sizeof(m));
+-#else
+-  #error "Unsupported multicast API"
+-#endif
+-}
+-  
+ static int
+ setsockopt_ipv4_ifindex (int sock, int val)
+ {
Index: patches/patch-lib_sockopt_h
===================================================================
RCS file: patches/patch-lib_sockopt_h
diff -N patches/patch-lib_sockopt_h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_sockopt_h 3 Jan 2013 00:48:29 -0000
@@ -0,0 +1,25 @@
+$OpenBSD$
+
+Revert 69bf3a39; does not work on at least (Open/Net)BSD.
+This can be put back if we get RFC3678 support.
+
+--- lib/sockopt.h.orig Tue Apr 17 14:56:26 2012
++++ lib/sockopt.h      Thu Jan  3 00:24:26 2013
+@@ -83,11 +83,13 @@ extern int setsockopt_ipv6_tclass (int, int);
+   (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \
+                     ? SOPT_SIZE_CMSG_PKTINFO_IPV6())
+ 
+-extern int setsockopt_ipv4_multicast_if(int sock,
+-                                   unsigned int ifindex);
+-extern int setsockopt_ipv4_multicast(int sock, int optname,
++extern int setsockopt_multicast_ipv4(int sock, int optname, 
++                                   struct in_addr if_addr
++                                       /* required: interface to join on */,
+                                      unsigned int mcast_addr,
+-                                   unsigned int ifindex);
++                                   unsigned int ifindex
++                                       /* optional: if non-zero, may be used
++                                              instead of if_addr */);
+ extern int setsockopt_ipv4_tos(int sock, int tos);
+ 
+ /* Ask for, and get, ifindex, by whatever method is supported. */
Index: patches/patch-ospfd_ospf_network_c
===================================================================
RCS file: patches/patch-ospfd_ospf_network_c
diff -N patches/patch-ospfd_ospf_network_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-ospfd_ospf_network_c  3 Jan 2013 00:48:29 -0000
@@ -0,0 +1,61 @@
+$OpenBSD$
+
+Revert 69bf3a39; does not work on at least (Open/Net)BSD.
+This can be put back if we get RFC3678 support.
+
+--- ospfd/ospf_network.c.orig  Tue Apr 17 14:56:26 2012
++++ ospfd/ospf_network.c       Thu Jan  3 00:24:26 2013
+@@ -52,8 +52,8 @@ ospf_if_add_allspfrouters (struct ospf *top, struct pr
+ {
+   int ret;
+   
+-  ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP,
+-                                   htonl (OSPF_ALLSPFROUTERS),
++  ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP,
++                                   p->u.prefix4, htonl (OSPF_ALLSPFROUTERS),
+                                    ifindex);
+   if (ret < 0)
+     zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, "
+@@ -73,8 +73,8 @@ ospf_if_drop_allspfrouters (struct ospf *top, struct p
+ {
+   int ret;
+ 
+-  ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP,
+-                                   htonl (OSPF_ALLSPFROUTERS),
++  ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP,
++                                   p->u.prefix4, htonl (OSPF_ALLSPFROUTERS),
+                                    ifindex);
+   if (ret < 0)
+     zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, "
+@@ -94,8 +94,8 @@ ospf_if_add_alldrouters (struct ospf *top, struct pref
+ {
+   int ret;
+ 
+-  ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP,
+-                                   htonl (OSPF_ALLDROUTERS),
++  ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP,
++                                   p->u.prefix4, htonl (OSPF_ALLDROUTERS),
+                                    ifindex);
+   if (ret < 0)
+     zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, "
+@@ -115,8 +115,8 @@ ospf_if_drop_alldrouters (struct ospf *top, struct pre
+ {
+   int ret;
+ 
+-  ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP,
+-                                   htonl (OSPF_ALLDROUTERS),
++  ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP,
++                                   p->u.prefix4, htonl (OSPF_ALLDROUTERS),
+                                    ifindex);
+   if (ret < 0)
+     zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, "
+@@ -151,7 +151,8 @@ ospf_if_ipmulticast (struct ospf *top, struct prefix *
+     zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s",
+              top->fd, safe_strerror (errno));
+ 
+-  ret = setsockopt_ipv4_multicast_if (top->fd, ifindex);
++  ret = setsockopt_multicast_ipv4 (top->fd, IP_MULTICAST_IF,
++                                   p->u.prefix4, 0, ifindex);
+   if (ret < 0)
+     zlog_warn("can't setsockopt IP_MULTICAST_IF(fd %d, addr %s, "
+             "ifindex %u): %s",
Index: patches/patch-ripd_rip_interface_c
===================================================================
RCS file: patches/patch-ripd_rip_interface_c
diff -N patches/patch-ripd_rip_interface_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-ripd_rip_interface_c  3 Jan 2013 00:48:29 -0000
@@ -0,0 +1,51 @@
+$OpenBSD$
+
+Revert 69bf3a39; does not work on at least (Open/Net)BSD.
+This can be put back if we get RFC3678 support.
+
+--- ripd/rip_interface.c.orig  Tue Apr 17 14:56:26 2012
++++ ripd/rip_interface.c       Thu Jan  3 00:24:26 2013
+@@ -78,8 +78,9 @@ ipv4_multicast_join (int sock, 
+ {
+   int ret;
+ 
+-  ret = setsockopt_ipv4_multicast (sock,
++  ret = setsockopt_multicast_ipv4 (sock, 
+                                  IP_ADD_MEMBERSHIP, 
++                                 ifa, 
+                                  group.s_addr, 
+                                  ifindex); 
+ 
+@@ -99,8 +100,9 @@ ipv4_multicast_leave (int sock, 
+ {
+   int ret;
+ 
+-  ret = setsockopt_ipv4_multicast (sock,
++  ret = setsockopt_multicast_ipv4 (sock, 
+                                  IP_DROP_MEMBERSHIP, 
++                                 ifa, 
+                                  group.s_addr, 
+                                  ifindex);
+ 
+@@ -136,13 +138,18 @@ rip_interface_new (void)
+ void
+ rip_interface_multicast_set (int sock, struct connected *connected)
+ {
++  struct in_addr addr;
++  
+   assert (connected != NULL);
+   
+-  if (setsockopt_ipv4_multicast_if (sock, connected->ifp->ifindex) < 0)
++  addr = CONNECTED_ID(connected)->u.prefix4;
++
++  if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, addr, 0, 
++                                 connected->ifp->ifindex) < 0) 
+     {
+       zlog_warn ("Can't setsockopt IP_MULTICAST_IF on fd %d to "
+-               "ifindex %d for interface %s",
+-               sock, connected->ifp->ifindex,
++               "source address %s for interface %s",
++               sock, inet_ntoa(addr),
+                connected->ifp->name);
+     }
+   

Attachment: quagga.tgz
Description: application/tar-gz

Reply via email to