]> git.puffer.fish Git - matthieu/frr.git/commitdiff
Added RIPv1 patch - bug fixes and improved/more interoperable classful
authorpaul <paul>
Fri, 13 Dec 2002 20:50:29 +0000 (20:50 +0000)
committerpaul <paul>
Fri, 13 Dec 2002 20:50:29 +0000 (20:50 +0000)
subnet handling

lib/if.c
lib/if.h
ripd/ripd.c

index bbf22ab1fa71aeacf29264a12a3f4e0c346c3643..0934e40d941a2a4067ed4839e32c416dcdafd374 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -553,6 +553,65 @@ connected_delete_by_prefix (struct interface *ifp, struct prefix *p)
   return NULL;
 }
 
+/* Find the IPv4 address on our side that will be used when packets
+   are sent to dst. */
+struct connected *
+connected_lookup_address (struct interface *ifp, struct in_addr dst)
+{
+  struct prefix addr;
+  struct prefix best;
+  listnode cnode;
+  struct prefix *p;
+  struct connected *c;
+  struct connected *match;
+
+  /* Zero structures - get rid of rubbish from stack */
+  memset(&addr, 0, sizeof(addr));
+  memset(&best, 0, sizeof(best));
+
+  addr.family = AF_INET;
+  addr.u.prefix4 = dst;
+  addr.prefixlen = IPV4_MAX_BITLEN;
+
+  match = NULL;
+
+  for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+    {
+      c = getdata (cnode);
+
+      if (if_is_pointopoint (ifp))
+       {
+         p = c->address;
+
+         if (p && p->family == AF_INET)
+           {
+#ifdef OLD_RIB  /* PTP  links are conventionally identified 
+                   by the address of the far end - MAG */
+             if (IPV4_ADDR_SAME (&p->u.prefix4, &dst))
+               return c;
+#endif
+             p = c->destination;
+             if (p && IPV4_ADDR_SAME (&p->u.prefix4, &dst))
+               return c;
+           }
+       }
+      else
+       {
+         p = c->address;
+
+         if (p->family == AF_INET)
+           {
+             if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen)
+               {
+                 best = *p;
+                 match = c;
+               }
+           }
+       }
+    }
+  return match;
+}
+
 /* Check the connected information is PtP style or not.  */
 int
 ifc_pointopoint (struct connected *ifc)
index 3896d187cd6f045333ed8a6908d90eafed7c476d..55337fc4f53b2f005217c4444b1796bbe5b505ba 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -202,6 +202,7 @@ struct connected *connected_new ();
 void connected_free (struct connected *);
 void connected_add (struct interface *, struct connected *);
 struct connected  *connected_delete_by_prefix (struct interface *, struct prefix *);
+struct connected  *connected_lookup_address (struct interface *, struct in_addr);
 int ifc_pointopoint (struct connected *);
 
 #ifndef HAVE_IF_NAMETOINDEX
index c017fe56436a5cecb015847ed82c71eca2cff450..3c55479d7ea5eff8cf6043ef7c3e640c6ad3ab63 100644 (file)
@@ -55,8 +55,8 @@ long rip_global_queries = 0;
 /* Prototypes. */
 void rip_event (enum rip_event, int);
 
-void rip_output_process (struct interface *, struct sockaddr_in *, 
-                        int, u_char);
+void rip_output_process (struct interface *, struct prefix *,
+                        struct sockaddr_in *, int, u_char);
 
 /* RIP output routes type. */
 enum
@@ -955,7 +955,14 @@ rip_response_process (struct rip_packet *packet, int size,
 {
   caddr_t lim;
   struct rte *rte;
+  struct prefix_ipv4 ifaddr;
+  struct prefix_ipv4 ifaddrclass;
+  struct connected *c;
+  int subnetted;
       
+  /* We don't know yet. */
+  subnetted = -1;
+
   /* The Response must be ignored if it is not from the RIP
      port. (RFC2453 - Sec. 3.9.2)*/
   if (ntohs (from->sin_port) != RIP_PORT_DEFAULT) 
@@ -1108,23 +1115,51 @@ rip_response_process (struct rip_packet *packet, int size,
        {
          u_int32_t destination;
 
-         destination = ntohl (rte->prefix.s_addr);
-
-         if (destination & 0xff) 
+         if (subnetted == -1)
            {
-             masklen2ip (32, &rte->mask);
+             c = connected_lookup_address (ifp, from->sin_addr);
+             if (c != NULL)
+               {
+                 memcpy (&ifaddr, c->address, sizeof (struct prefix_ipv4));
+                 memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
+                 apply_classful_mask_ipv4 (&ifaddrclass);
+                 subnetted = 0;
+                 if (ifaddr.prefixlen > ifaddrclass.prefixlen)
+                   subnetted = 1;
+               }
            }
-         else if ((destination & 0xff00) || IN_CLASSC (destination)) 
-           {
+
+         destination = ntohl (rte->prefix.s_addr);
+
+         if (IN_CLASSA (destination))
+             masklen2ip (8, &rte->mask);
+         else if (IN_CLASSB (destination))
+             masklen2ip (16, &rte->mask);
+         else if (IN_CLASSC (destination))
              masklen2ip (24, &rte->mask);
+
+         if (subnetted == 1)
+           masklen2ip (ifaddrclass.prefixlen,
+                       (struct in_addr *) &destination);
+         if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
+             ifaddrclass.prefix.s_addr))
+           {
+             masklen2ip (ifaddr.prefixlen, &rte->mask);
+             if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
+               masklen2ip (32, &rte->mask);
+             if (IS_RIP_DEBUG_EVENT)
+               zlog_info ("Subnetted route %s", inet_ntoa (rte->prefix));
            }
-         else if ((destination & 0xff0000) || IN_CLASSB (destination)) 
+         else
            {
-             masklen2ip (16, &rte->mask);
+             if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
+               continue;
            }
-         else 
+
+         if (IS_RIP_DEBUG_EVENT)
            {
-             masklen2ip (8, &rte->mask);
+             zlog_info ("Resultant route %s", inet_ntoa (rte->prefix));
+             zlog_info ("Resultant mask %s", inet_ntoa (rte->mask));
            }
        }
 
@@ -1353,7 +1388,7 @@ rip_request_process (struct rip_packet *packet, int size,
       ntohl (rte->metric) == RIP_METRIC_INFINITY)
     {  
       /* All route with split horizon */
-      rip_output_process (ifp, from, rip_all_route, packet->version);
+      rip_output_process (ifp, NULL, from, rip_all_route, packet->version);
     }
   else
     {
@@ -1884,8 +1919,8 @@ rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
 
 /* Send update to the ifp or spcified neighbor. */
 void
-rip_output_process (struct interface *ifp, struct sockaddr_in *to,
-                   int route_type, u_char version)
+rip_output_process (struct interface *ifp, struct prefix *ifaddr,
+                   struct sockaddr_in *to, int route_type, u_char version)
 {
   int ret;
   struct stream *s;
@@ -1894,8 +1929,11 @@ rip_output_process (struct interface *ifp, struct sockaddr_in *to,
   struct rip_interface *ri;
   struct prefix_ipv4 *p;
   struct prefix_ipv4 classfull;
+  struct prefix_ipv4 ifaddrclass;
+  struct connected *c;
   int num;
   int rtemax;
+  int subnetted;
 
   /* Logging output event. */
   if (IS_RIP_DEBUG_EVENT)
@@ -1946,29 +1984,60 @@ rip_output_process (struct interface *ifp, struct sockaddr_in *to,
          rtemax -=1;
     }
 
+  if (version == RIPv1)
+    {
+      if (ifaddr == NULL)
+       {
+         c = connected_lookup_address (ifp, to->sin_addr);
+         if (c != NULL)
+           ifaddr = c->address;
+       }
+      if (ifaddr == NULL)
+       {
+         zlog_warn ("cannot find source address for packets to neighbor %s",
+                    inet_ntoa (to->sin_addr));
+         return;
+       }
+      memcpy (&ifaddrclass, ifaddr, sizeof (struct prefix_ipv4));
+      apply_classful_mask_ipv4 (&ifaddrclass);
+      subnetted = 0;
+      if (ifaddr->prefixlen > ifaddrclass.prefixlen)
+       subnetted = 1;
+    }
+
   for (rp = route_top (rip->table); rp; rp = route_next (rp))
     if ((rinfo = rp->info) != NULL)
       {
-       /* Some inheritance stuff:                                          */
-       /* Before we process with ipv4 prefix we should mask it             */
-       /* with Classful mask if we send RIPv1 packet.That's because        */
-       /* user could set non-classful mask or we could get it by RIPv2     */
-       /* or other protocol. checked with Cisco's way of life :)           */
+       /* For RIPv1, if we are subnetted, output subnets in our network    */
+       /* that have the same mask as the output "interface". For other     */
+       /* networks, only the classfull version is output.                  */
        
        if (version == RIPv1)
          {
-           memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4));
+           p = (struct prefix_ipv4 *) &rp->p;
 
            if (IS_RIP_DEBUG_PACKET)
-             zlog_info("%s/%d before RIPv1 mask check ",
-                       inet_ntoa (classfull.prefix), classfull.prefixlen);
-
-           apply_classful_mask_ipv4 (&classfull);
-           p = &classfull;
+             zlog_info("RIPv1 mask check, %s/%d considered for output",
+                       inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
 
+           if (subnetted &&
+               prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
+             {
+               if ((ifaddr->prefixlen != rp->p.prefixlen) &&
+                   (rp->p.prefixlen != 32))
+                 continue;
+             }
+           else
+             {
+               memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
+               apply_classful_mask_ipv4(&classfull);
+               if (rp->p.u.prefix4.s_addr != 0 &&
+                   classfull.prefixlen != rp->p.prefixlen)
+                 continue;
+             }
            if (IS_RIP_DEBUG_PACKET)
-             zlog_info("%s/%d after RIPv1 mask check",
-                       inet_ntoa (p->prefix), p->prefixlen);
+             zlog_info("RIPv1 mask check, %s/%d made it through",
+                       inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
          }
        else 
          p = (struct prefix_ipv4 *) &rp->p;
@@ -2109,7 +2178,7 @@ rip_update_interface (struct interface *ifp, u_char version, int route_type)
       if (IS_RIP_DEBUG_EVENT)
        zlog_info ("multicast announce on %s ", ifp->name);
 
-      rip_output_process (ifp, NULL, route_type, version);
+      rip_output_process (ifp, NULL, NULL, route_type, version);
       return;
     }
 
@@ -2136,7 +2205,8 @@ rip_update_interface (struct interface *ifp, u_char version, int route_type)
                           if_is_pointopoint (ifp) ? "unicast" : "broadcast",
                           inet_ntoa (to.sin_addr), ifp->name);
 
-             rip_output_process (ifp, &to, route_type, version);
+             rip_output_process (ifp, connected->address, &to, route_type,
+                                 version);
            }
        }
     }
@@ -2224,7 +2294,7 @@ rip_update_process (int route_type)
        to.sin_port = htons (RIP_PORT_DEFAULT);
 
        /* RIP version is rip's configuration. */
-       rip_output_process (ifp, &to, route_type, rip->version);
+       rip_output_process (ifp, NULL, &to, route_type, rip->version);
       }
 }