[Olsr-dev] FreeBSD and multiple interfaces on the same subnet

John Hay (spam-protected)
Sat Sep 29 13:53:45 CEST 2007


Hi,

This patch do two things. The first is to make it possible to run more
than one interface in the same IPv6 subnet on FreeBSD. I had kernel mods
to FreeBSD to achieve the same, but it had other negative side effects
and it looks like that is going to take a long time to sort out.

The second part is to catch the case where a route already exist in the
kernel routing table. Delete that route and then retry the add.

John
-- 
John Hay -- (spam-protected) / (spam-protected)


--- src/bsd/kernel_routes.c.orig	2007-09-06 09:55:25.000000000 +0200
+++ src/bsd/kernel_routes.c	2007-09-19 09:42:30.000000000 +0200
@@ -223,6 +223,14 @@
   {
     memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr));
 
+    memset(&sin6.sin6_addr.s6_addr, 0, 8);
+    sin6.sin6_addr.s6_addr[0] = 0xfe;
+    sin6.sin6_addr.s6_addr[1] = 0x80;
+    sin6.sin6_scope_id = nexthop->iif_index;
+#ifdef __KAME__
+    *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
+    sin6.sin6_scope_id = 0;
+#endif
     memcpy(walker, &sin6, sizeof (sin6));
     walker += step;
   }
@@ -231,19 +239,19 @@
 
   else
   {
-    // Sven-Ola: This looks really ugly (please compar to IPv4 above)
-    struct interface* iface = if_ifwithindex(nexthop->iif_index);
-    if (NULL == iface)
-    {
-      fprintf(stderr, "interface %s not found\n", if_ifwithindex_name(nexthop->iif_index));
-      return -1;
-    }
-    memcpy(&sin6.sin6_addr.s6_addr, &iface->int6_addr.sin6_addr.s6_addr,
-      sizeof(struct in6_addr));
+    memcpy(&sin6.sin6_addr.s6_addr,  &rt->rt_dst.prefix.v6, sizeof(struct in6_addr));
+    memset(&sin6.sin6_addr.s6_addr, 0, 8);
+    sin6.sin6_addr.s6_addr[0] = 0xfe;
+    sin6.sin6_addr.s6_addr[1] = 0x80;
+    sin6.sin6_scope_id = nexthop->iif_index;
+#ifdef __KAME__
+    *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id);
+    sin6.sin6_scope_id = 0;
+#endif
 
     memcpy(walker, &sin6, sizeof (sin6));
     walker += step;
-    rtm->rtm_flags |= RTF_LLINFO;
+    rtm->rtm_flags |= RTF_GATEWAY;
   }
 
   if ((rtm->rtm_flags & RTF_HOST) == 0)
@@ -254,22 +262,41 @@
     rtm->rtm_addrs |= RTA_NETMASK;
   }
 
-  if ((rtm->rtm_flags & RTF_GATEWAY) != 0)
-  {
-    strcpy(&sdl.sdl_data[0], if_ifwithindex_name(nexthop->iif_index));
-    sdl.sdl_nlen = (u_char)strlen((char*)&sdl.sdl_data[0]);
-    memcpy(walker, &sdl, sizeof (sdl));
-    walker += step_dl;
-    rtm->rtm_addrs |= RTA_IFP;
-  }
-
   rtm->rtm_msglen = (unsigned short)(walker - buff);
 
   len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
-
-  if (len < rtm->rtm_msglen)
+  if (len < 0 && !(errno == EEXIST || errno == ESRCH))
     fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno));
 
+  /* If we get an EEXIST error while adding, delete and retry. */
+  if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) {
+    struct rt_msghdr *drtm;
+    unsigned char dbuff[512];
+
+    memset(dbuff, 0, sizeof (dbuff));
+    drtm = (struct rt_msghdr *)dbuff;
+    drtm->rtm_version = RTM_VERSION;
+    drtm->rtm_type = RTM_DELETE;
+    drtm->rtm_addrs = RTA_DST;
+    drtm->rtm_index = 0;
+    drtm->rtm_flags = olsr_rt_flags(rt);
+    drtm->rtm_seq = ++seq;
+
+    walker = dbuff + sizeof (struct rt_msghdr);
+    memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6,
+	sizeof(struct in6_addr));
+    memcpy(walker, &sin6, sizeof (sin6));
+    walker += step;
+    drtm->rtm_msglen = (unsigned short)(walker - dbuff);
+    len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen);
+    if (len < 0)
+      fprintf(stderr, "cannot delete route: %s\n", strerror(errno));
+    rtm->rtm_seq = ++seq;
+    len = write(olsr_cnf->rts, buff, rtm->rtm_msglen);
+    if (len < 0)
+      fprintf(stderr, "still cannot add route: %s\n", strerror(errno));
+  }
+
   return 0;
 }
 




More information about the Olsr-dev mailing list