[quagga-dev 266] ripd fix to handle interface aliases

sowmini.varadhan at sun.com sowmini.varadhan at sun.com
Mon Sep 29 19:12:04 BST 2003


Hi,

I have a patch to enable ripd to handle interface aliases, so that it
sends out updates on each connected network as per RFC 2453. This
patch has been tested on Solaris 9, and I've also tested for compilation
on linux. I'm attaching the diffs below, but since the patch involves
2 new files (solaris specific), it's probably easier to download 
http://www.cs.utk.edu/~varadhan/quagga/patch.tar.gz to look at the patch.

files affected are:

./zebra/Makefile.am
./zebra/ioctl.h
./zebra/ipforward_solaris.c
./zebra/ioctl_solaris.c           << new file
./zebra/if_ioctl_solaris.c        << new file
./lib/if.h
./ripd/ripd.c
./ripd/ripd.h
./ripd/rip_interface.c
./configure.ac

All files can also be viewed at http://www.cs.utk.edu/~varadhan/quagga/

Comments are appreciated!

--Sowmini

-----------------diffs below cut here-----------------------------------

===================================================================
RCS file: configure.ac,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -r1.30 -r1.31
--- /tmp/T0GQaGJo	Mon Sep 29 13:55:39 2003
+++ /tmp/T1HQaGJo	Mon Sep 29 13:55:39 2003
@@ -425,23 +425,43 @@
 if test "$netlink" = yes; then
   AC_MSG_RESULT(netlink)
   IF_METHOD=if_netlink.o
+  IOCTL_METHOD=ioctl.o
 else
   if test "$opsys" = "sol2-6";then
     AC_MSG_RESULT(solaris)
     IF_METHOD=if_ioctl.o
+    IOCTL_METHOD=ioctl.o
   elif test "$opsys" = "openbsd";then
     AC_MSG_RESULT(openbsd)
     IF_METHOD=if_ioctl.o
+    IOCTL_METHOD=ioctl.o
   elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then
     AC_MSG_RESULT(sysctl)
     IF_METHOD=if_sysctl.o
+    IOCTL_METHOD=ioctl.o
     AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST)
   else
+    AC_TRY_RUN([#include <sys/sockio.h>
+main ()
+{
+#ifdef SIOCGLIFNUM
+	exit(1);
+#else 
+	exit(0);
+#endif
+}],
+  [IOCTL_METHOD=ioctl.o
+   IF_METHOD=if_ioctl.o],
+  [IOCTL_METHOD=ioctl_solaris.o
+   IF_METHOD=if_ioctl_solaris.o],
+  [IOCTL_METHOD=ioctl.o
+   IF_METHOD=if_ioctl.o])
+  
     AC_MSG_RESULT(ioctl)
-    IF_METHOD=if_ioctl.o
   fi
 fi
 AC_SUBST(IF_METHOD)
+AC_SUBST(IOCTL_METHOD)
 
 dnl -----------------------
 dnl check proc file system.
@@ -546,6 +566,15 @@
     else
       AC_MSG_RESULT(NRL)
     fi
+dnl ---------
+dnl Solaris check
+dnl ---------
+  elif grep IN6_V4MAPPED_TO_INADDR /usr/include/netinet/in.h >/dev/null 2>&1; then
+    zebra_cv_ipv6=yes
+    AC_DEFINE(HAVE_IPV6,1,NRL IPv6)
+    AC_DEFINE(SOLARIS_IPV6,1,Solaris IPv6)
+    RIPNGD="ripngd"
+    OSPF6D="ospf6d"
 dnl ----------
 dnl Linux IPv6
 dnl ----------
===================================================================
RCS file: if.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- /tmp/T00xaiKo	Mon Sep 29 13:55:50 2003
+++ /tmp/T11xaiKo	Mon Sep 29 13:55:50 2003
@@ -81,6 +81,11 @@
   /* Interface index. */
   unsigned int ifindex;
 
+#ifdef SUNOS_5
+  /* Interface family */
+  sa_family_t af;
+#endif /* SUNOS_5 */
+
   /* Zebra internal interface status */
   u_char status;
 #define ZEBRA_INTERFACE_ACTIVE     (1 << 0)
@@ -94,7 +99,10 @@
   int metric;
 
   /* Interface MTU. */
-  int mtu;
+  int mtu;  /* ipv4 mtu */
+#ifdef SOLARIS_IPV6
+  int mtu6; /* ipv6 mtu */
+#endif
 
   /* Hardware address. */
 #ifdef HAVE_SOCKADDR_DL
===================================================================
RCS file: rip_interface.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- /tmp/T0ZzaWKo	Mon Sep 29 13:56:02 2003
+++ /tmp/T10zaWKo	Mon Sep 29 13:56:02 2003
@@ -137,68 +137,73 @@
 }
 
 void
-rip_interface_multicast_set (int sock, struct interface *ifp)
+rip_interface_multicast_set (int sock, struct connected *connected, 
+                             int if_pointopoint)
 {
   int ret;
-  listnode node;
   struct servent *sp;
   struct sockaddr_in from;
+  struct in_addr addr;
+  int ifindex = 0;
+  struct prefix_ipv4 *p;
 
-  for (node = listhead (ifp->connected); node; nextnode (node))
-    {
-      struct prefix_ipv4 *p;
-      struct connected *connected;
-      struct in_addr addr;
+  if (if_pointopoint)
+    p = (struct prefix_ipv4 *) connected->destination;
+  else
+    p = (struct prefix_ipv4 *) connected->address;
 
-      connected = getdata (node);
-      p = (struct prefix_ipv4 *) connected->address;
+  addr = p->prefix;
 
-      if (p->family == AF_INET)
-	{
-	  addr = p->prefix;
+#ifdef SUNOS_5
+  /*
+   * Note that we intentionally reset IP_XMIT_IF to zero if
+   * we're doing multicast.  The kernel ignores IP_MULTICAST_IF
+   * if IP_XMIT_IF is set, and we can't deal with alias source
+   * addresses without it.
+   */
+  setsockopt(sock, IPPROTO_IP, IP_XMIT_IF, &ifindex, sizeof(ifindex)) ;
+#endif
 
-	  if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
-					 addr, 0, ifp->ifindex) < 0) 
-	    {
-	      zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock);
-	      return;
-	    }
+  if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
+				 addr, 0, 0) < 0) 
+    {
+      zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock);
+      return;
+    }
 
-	  /* Bind myself. */
-	  memset (&from, 0, sizeof (struct sockaddr_in));
+  /* Bind myself. */
+  memset (&from, 0, sizeof (struct sockaddr_in));
 
-	  /* Set RIP port. */
-	  sp = getservbyname ("router", "udp");
-	  if (sp) 
-	    from.sin_port = sp->s_port;
-	  else 
-	    from.sin_port = htons (RIP_PORT_DEFAULT);
+  /* Set RIP port. */
+  sp = getservbyname ("router", "udp");
+  if (sp) 
+    from.sin_port = sp->s_port;
+  else 
+    from.sin_port = htons (RIP_PORT_DEFAULT);
 
-	  /* Address shoud be any address. */
-	  from.sin_family = AF_INET;
-	  from.sin_addr = addr;
+  /* Address shoud be any address. */
+  from.sin_family = AF_INET;
+  addr = ((struct prefix_ipv4 *) connected->address)->prefix;
+  from.sin_addr = addr;
 #ifdef HAVE_SIN_LEN
-	  from.sin_len = sizeof (struct sockaddr_in);
+  from.sin_len = sizeof (struct sockaddr_in);
 #endif /* HAVE_SIN_LEN */
 
-    if (ripd_privs.change (ZPRIVS_RAISE))
-      zlog_err ("rip_interface_multicast_set: could not raise privs");
+  if (ripd_privs.change (ZPRIVS_RAISE))
+    zlog_err ("rip_interface_multicast_set: could not raise privs");
       
-	  ret = bind (sock, (struct sockaddr *) & from, 
-		      sizeof (struct sockaddr_in));
-	  if (ret < 0)
-	    {
-	      zlog_warn ("Can't bind socket: %s", strerror (errno));
-	      return;
-	    }
+  bind (sock, NULL, 0); /* unbind any previous association */
+  ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in));
+  if (ret < 0)
+    {
+      zlog_warn ("Can't bind socket: %s", strerror (errno));
+    }
 
-    if (ripd_privs.change (ZPRIVS_LOWER))
-        zlog_err ("rip_interface_multicast_set: could not lower privs");
+  if (ripd_privs.change (ZPRIVS_LOWER))
+    zlog_err ("rip_interface_multicast_set: could not lower privs");
 
-	  return;
+  return;
 
-	}
-    }
 }
 
 /* Send RIP request packet to specified interface. */
===================================================================
RCS file: ripd.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- /tmp/T0hoayLo	Mon Sep 29 13:56:14 2003
+++ /tmp/T1ioayLo	Mon Sep 29 13:56:14 2003
@@ -60,7 +60,8 @@
 void rip_event (enum rip_event, int);
 
 void rip_output_process (struct interface *, struct prefix *,
-			 struct sockaddr_in *, int, u_char);
+			 struct sockaddr_in *, int, u_char, 
+                         struct prefix_ipv4 *);
 
 /* RIP output routes type. */
 enum
@@ -1238,7 +1239,6 @@
 {
   int ret;
   struct sockaddr_in sin;
-  int sock;
 
   /* Make destination address. */
   memset (&sin, 0, sizeof (struct sockaddr_in));
@@ -1250,39 +1250,29 @@
   /* When destination is specified, use it's port and address. */
   if (to)
     {
-      sock = rip->sock;
-
       sin.sin_port = to->sin_port;
       sin.sin_addr = to->sin_addr;
     }
   else
     {
-      sock = socket (AF_INET, SOCK_DGRAM, 0);
-      
-      sockopt_broadcast (sock);
-      sockopt_reuseaddr (sock);
-      sockopt_reuseport (sock);
 
       sin.sin_port = htons (RIP_PORT_DEFAULT);
       sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
 
-      /* Set multicast interface. */
-      rip_interface_multicast_set (sock, ifp);
+      /* caller has set multicast interface */
+
     }
 
-  ret = sendto (sock, buf, size, 0, (struct sockaddr *)&sin,
+  ret = sendto (rip->sock, buf, size, 0, (struct sockaddr *)&sin,
 		sizeof (struct sockaddr_in));
 
   if (IS_RIP_DEBUG_EVENT)
-      zlog_info ("SEND to socket %d port %d addr %s",
-                 sock, ntohs (sin.sin_port), inet_ntoa(sin.sin_addr));
+      zlog_info ("SEND to  %s.%d", inet_ntoa(sin.sin_addr), 
+                  ntohs (sin.sin_port));
 
   if (ret < 0)
     zlog_warn ("can't send packet : %s", strerror (errno));
 
-  if (! to)
-    close (sock);
-
   return ret;
 }
 
@@ -1454,8 +1444,19 @@
       ntohs (rte->family) == 0 &&
       ntohl (rte->metric) == RIP_METRIC_INFINITY)
     {	
+      struct prefix_ipv4 saddr;
+
+      /* saddr will be used for determining which routes to split-horizon.
+         Since the source address we'll pick will be on the same subnet as the
+         destination, for the purpose of split-horizoning, we'll
+         pretend that "from" is our source address.  */
+      saddr.family = AF_INET;
+      saddr.prefixlen = IPV4_MAX_BITLEN;
+      saddr.prefix = from->sin_addr;
+
       /* All route with split horizon */
-      rip_output_process (ifp, NULL, from, rip_all_route, packet->version);
+      rip_output_process (ifp, NULL, from, rip_all_route, packet->version, 
+                          &saddr);
     }
   else
     {
@@ -1979,7 +1980,8 @@
 /* Send update to the ifp or spcified neighbor. */
 void
 rip_output_process (struct interface *ifp, struct prefix *ifaddr,
-		    struct sockaddr_in *to, int route_type, u_char version)
+		    struct sockaddr_in *to, int route_type, u_char version,
+                    struct prefix_ipv4 *saddr)
 {
   int ret;
   struct stream *s;
@@ -2118,7 +2120,7 @@
 	    /* We perform split horizon for RIP and connected route. */
 	    if ((rinfo->type == ZEBRA_ROUTE_RIP ||
 		 rinfo->type == ZEBRA_ROUTE_CONNECT) &&
-		rinfo->ifindex == ifp->ifindex)
+                 prefix_match((struct prefix *)p, (struct prefix *)saddr))
 	      continue;
 	  }
 
@@ -2247,7 +2249,8 @@
 
 /* Send RIP packet to the interface. */
 void
-rip_update_interface (struct interface *ifp, u_char version, int route_type)
+rip_update_interface (struct interface *ifp, u_char version, int route_type,
+                      struct prefix_ipv4 *saddr)
 {
   struct prefix_ipv4 *p;
   struct connected *connected;
@@ -2260,7 +2263,8 @@
       if (IS_RIP_DEBUG_EVENT)
 	zlog_info ("multicast announce on %s ", ifp->name);
 
-      rip_output_process (ifp, NULL, NULL, route_type, rip->version_send);
+      rip_output_process (ifp, NULL, NULL, route_type, rip->version_send, 
+                          saddr);
       return;
     }
 
@@ -2288,7 +2292,7 @@
 			   inet_ntoa (to.sin_addr), ifp->name);
 
 	      rip_output_process (ifp, connected->address, &to, route_type,
-				 rip->version_send);
+				 rip->version_send, saddr);
 	    }
 	}
     }
@@ -2298,7 +2302,7 @@
 void
 rip_update_process (int route_type)
 {
-  listnode node;
+  listnode node, ifnode;
   struct interface *ifp;
   struct rip_interface *ri;
   struct route_node *rp;
@@ -2336,16 +2340,31 @@
 			   ifp->ifindex);
 	    }
 
-	  /* If there is no version configuration in the interface,
-             use rip's version setting. */
-	  {
+          /* send update on each connected network */
+	  for (ifnode = listhead (ifp->connected); ifnode; nextnode (ifnode))
+	    {
+	      struct prefix_ipv4 *ifaddr;
+              struct connected *connected;
+          
+
+	      /* If there is no version configuration in the interface,
+                 use rip's version setting. */
 	      int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
 			   rip->version_send : ri->ri_send);
+
+      	      connected = getdata (ifnode);
+              ifaddr = (struct prefix_ipv4 *) connected->address;
+
+	      if (ifaddr->family != AF_INET)
+		continue;
+
+	      rip_interface_multicast_set(rip->sock, connected,
+					  if_is_pointopoint(ifp));
 	      if (vsend & RIPv1)
-		rip_update_interface (ifp, RIPv1, route_type);
+		rip_update_interface (ifp, RIPv1, route_type, ifaddr);
 	      if (vsend & RIPv2)
-		rip_update_interface (ifp, RIPv2, route_type);
-	  }
+		rip_update_interface (ifp, RIPv2, route_type, ifaddr);
+	    }
 	}
     }
 
@@ -2369,7 +2388,7 @@
 	to.sin_port = htons (RIP_PORT_DEFAULT);
 
 	/* RIP version is rip's configuration. */
-	rip_output_process (ifp, NULL, &to, route_type, rip->version_send);
+	rip_output_process (ifp, NULL, &to, route_type, rip->version_send, p);
       }
 }
 
@@ -2549,6 +2568,7 @@
 {
   struct rte *rte;
   struct rip_packet rip_packet;
+  listnode node;
 
   memset (&rip_packet, 0, sizeof (rip_packet));
 
@@ -2557,7 +2577,25 @@
   rte = rip_packet.rte;
   rte->metric = htonl (RIP_METRIC_INFINITY);
 
-  return rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet), to, ifp);
+  /* send request on each connected network */
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      struct prefix_ipv4 *p;
+      struct connected *connected;
+
+      connected = getdata (node);
+      p = (struct prefix_ipv4 *) connected->address;
+
+      if (p->family != AF_INET)
+        continue;
+
+      rip_interface_multicast_set(rip->sock, connected,
+				  if_is_pointopoint(ifp));
+      if (rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet), 
+                            to, ifp) != sizeof (rip_packet))
+        return -1;
+    }
+  return sizeof (rip_packet);
 }
 
 int
===================================================================
RCS file: ripd.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- /tmp/T0YUa4Lo	Mon Sep 29 13:56:20 2003
+++ /tmp/T1ZUa4Lo	Mon Sep 29 13:56:20 2003
@@ -383,7 +383,7 @@
 void rip_redistribute_withdraw (int);
 void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char);
 void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t);
-void rip_interface_multicast_set (int, struct interface *);
+void rip_interface_multicast_set (int, struct connected *, int);
 void rip_distribute_update_interface (struct interface *);
 void rip_if_rmap_update_interface (struct interface *);
 
===================================================================
RCS file: Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- /tmp/T0AxaGMo	Mon Sep 29 13:56:27 2003
+++ /tmp/T1BxaGMo	Mon Sep 29 13:56:27 2003
@@ -14,14 +14,15 @@
 rtread_method = @RTREAD_METHOD@
 kernel_method = @KERNEL_METHOD@
 other_method = @OTHER_METHOD@
+ioctl_method = @IOCTL_METHOD@
 
 otherobj = $(ipforward) $(if_method) $(if_proc) $(rt_method) \
-	$(rtread_method) $(kernel_method) $(other_method)
+	$(rtread_method) $(kernel_method) $(other_method) $(ioctl_method)
 
 sbin_PROGRAMS = zebra
 
 zebra_SOURCES = \
-	zserv.c main.c interface.c connected.c ioctl.c zebra_rib.c \
+	zserv.c main.c interface.c connected.c zebra_rib.c \
 	redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c
 
 noinst_HEADERS = \
===================================================================
RCS file: ioctl.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.2
diff -u -r1.1.1.1 -r1.1.1.2
--- /tmp/T09PaaNo	Mon Sep 29 13:56:44 2003
+++ /tmp/T1.PaaNo	Mon Sep 29 13:56:44 2003
@@ -40,7 +40,15 @@
 #ifdef HAVE_IPV6
 int if_prefix_add_ipv6 (struct interface *, struct connected *);
 int if_prefix_delete_ipv6 (struct interface *, struct connected *);
-
+int if_ioctl_ipv6(u_long, caddr_t);
 #endif /* HAVE_IPV6 */
 
+#ifdef SOLARIS_IPV6
+struct connected *if_lookup_linklocal( struct interface *);
+
+#define AF_IOCTL(af, request, buffer) \
+        ((af) == AF_INET? if_ioctl(request, buffer) : \
+                          if_ioctl_ipv6(request, buffer))
+#endif /* SOLARIS_IPV6 */
+
 #endif /* _ZEBRA_IOCTL_H */
===================================================================
RCS file: ipforward_solaris.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- /tmp/T0_saGNo	Mon Sep 29 13:56:55 2003
+++ /tmp/T1ataGNo	Mon Sep 29 13:56:55 2003
@@ -144,7 +144,7 @@
 #ifdef HAVE_IPV6
 int ipforward_ipv6()
 {
-  return solaris_nd_get("ip6_fowarding");
+  return solaris_nd_get("ip6_forwarding");
 }
 int
 ipforward_ipv6_on ()






More information about the Quagga-dev mailing list