Hello list,

I resent to ports since I think this list is more readen than ports-bugs.

I use quagga since a while on openbsd on plenty of openbsd boxes.
I planned to move on openospfd(or bird) but it definitively lack
some feature (like good filtering, or redistribution), so I will
keep it for now.

Recently I upgrade some of them to 5.2 and quagga-0.99.20.1p0.

Since OSPF is broken, at least multicast support which was the
default.

A trace of the ospfd daemon in debug show :

2012/12/30 17:59:30.86 OSPF: make_hello: options: 2, int: vr0:192.168.0.9
2012/12/30 17:59:30.86 OSPF: can't setsockopt IP_MULTICAST_IF(fd 6, addr 192.168.0.9, ifindex 1): Can't assign requested address

It seems that quagga cannot send multicast packet.
Tcpdump confirm that.

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.

Regards,

--
Raphael Mazelier
$OpenBSD$
--- ospfd/ospf_network.c.orig   Mon Dec 31 17:04:47 2012
+++ ospfd/ospf_network.c        Tue Jan  1 14:24:02 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,13 +151,68 @@ 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",
              top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno));
 
   return ret;
+}
+
+int
+setsockopt_multicast_ipv4(int sock, 
+            int optname, 
+            struct in_addr if_addr /* required */,
+            unsigned int mcast_addr,
+            unsigned int ifindex /* optional: if non-zero, may be
+                          used instead of if_addr */)
+{
+  struct in_addr m;
+  struct ip_mreq mreq;
+  int ret;
+
+  m = if_addr;
+
+  switch (optname)
+    {
+    case IP_MULTICAST_IF:
+      return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m)); 
+      break;
+
+    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;
+    }
+
 }
 
 int

Reply via email to