From cistron.nl!miquels Wed Aug  9 12:47:42 1995
Return-Path: <miquels@cistron.nl>
Received: from troy.cistron.nl by iiit.swan.ac.uk  with smtp
	(Linux Smail3.1.28.1 #8) id m0sg9bo-00013hC; Wed, 9 Aug 95 12:47 BST
Received: from picard.cistron.nl by troy.cistron.nl (8.7.Beta.9) with ESMTP id NAA23179; Wed, 9 Aug 1995 13:40:07 +0200 (MET DST)
Received: by picard.cistron.nl (8.7.Beta.10) id NAA04697; Wed, 9 Aug 1995 13:40:06 +0200
Date: Wed, 9 Aug 1995 13:40:06 +0200
From: Miquel van Smoorenburg <miquels@cistron.nl>
Message-Id: <199508091140.NAA04697@picard.cistron.nl>
To: iialan@iifeak.swan.ac.uk
Subject: Re: Metric patches
Status: RO

You wrote:

> Date: Tue, 8 Aug 95 09:23 BST
> From: iialan@iifeak.swan.ac.uk (Alan Cox)
> To: miquels@cistron.nl
> Subject: Metric patches
>
> I've managed to eat your metric patches, can you send me another copy ?

:) Sure, here is a patch relative to 1.3.15. I've also attached diffs
for the "route.c" from net-tools-1.3.6BETA3 that I got from
ftp.linux.org.uk just this morning, I hope that's recent enough.

I've changed the kernel metric type (in route.h) to signed short instead
of unsigned, since internally the metric can be -1 (which means
"not set").

Follows:
o route-diffs-1.3.15
o route.c.dif


diff -u --recursive linux-1.3.15/include/net/route.h linux/include/net/route.h
--- linux-1.3.15/include/net/route.h	Fri Jul  7 13:56:49 1995
+++ linux/include/net/route.h	Wed Aug  9 12:20:41 1995
@@ -33,7 +33,7 @@
 	unsigned long		rt_mask;
 	unsigned long		rt_gateway;
 	unsigned short		rt_flags;
-	unsigned short		rt_metric;
+	short			rt_metric;
 	unsigned int		rt_refcnt;
 	unsigned long		rt_use;
 	unsigned short		rt_mss;
@@ -45,7 +45,7 @@
 
 extern void		ip_rt_flush(struct device *dev);
 extern void		ip_rt_add(short flags, unsigned long addr, unsigned long mask,
-			       unsigned long gw, struct device *dev, unsigned short mss, unsigned long window, unsigned short irtt, unsigned char metric);
+			       unsigned long gw, struct device *dev, unsigned short mss, unsigned long window, unsigned short irtt, short metric);
 extern struct rtable	*ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr);
 extern struct rtable 	*ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr);
 extern int		rt_get_info(char * buffer, char **start, off_t offset, int length);
diff -u --recursive linux-1.3.15/net/ipv4/route.c linux/net/ipv4/route.c
--- linux-1.3.15/net/ipv4/route.c	Mon Jul 17 22:40:06 1995
+++ linux/net/ipv4/route.c	Wed Aug  9 13:36:52 1995
@@ -73,9 +73,11 @@
 
 /*
  *	Remove a routing table entry.
+ *	Should we return a status value here ?
  */
 
-static void rt_del(unsigned long dst, char *devname)
+static void rt_del(unsigned long dst, unsigned long mask,
+		char *devname, unsigned long gtw, short rt_flags, short metric)
 {
 	struct rtable *r, **rp;
 	unsigned long flags;
@@ -91,9 +93,16 @@
 	cli();
 	while((r = *rp) != NULL) 
 	{
-		/* Make sure both the destination and the device match */
-		if ( r->rt_dst != dst ||
-		(devname != NULL && strcmp((r->rt_dev)->name,devname) != 0) )
+		/*
+		 *	Make sure the destination and netmask match.
+		 *	metric, gateway and device are also checked
+		 *	if they were specified.
+		 */
+		if (r->rt_dst != dst ||
+		    (mask && r->rt_mask != mask) ||
+		    (gtw && r->rt_gateway != gtw) ||
+		    (metric >= 0 && r->rt_metric != metric) ||
+		    (devname && strcmp((r->rt_dev)->name,devname) != 0) )
 		{
 			rp = &r->rt_next;
 			continue;
@@ -211,11 +220,13 @@
  */
  
 void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
-	unsigned long gw, struct device *dev, unsigned short mtu, unsigned long window, unsigned short irtt, unsigned char metric)
+	unsigned long gw, struct device *dev, unsigned short mtu,
+	unsigned long window, unsigned short irtt, short metric)
 {
 	struct rtable *r, *rt;
 	struct rtable **rp;
 	unsigned long cpuflags;
+	int duplicate = 0;
 
 	/*
 	 *	A host is a unique machine and has no network bits.
@@ -320,6 +331,12 @@
 			rp = &r->rt_next;
 			continue;
 		}
+		if (r->rt_metric != metric && r->rt_gateway != gw)
+		{
+			duplicate = 1;
+			rp = &r->rt_next;
+			continue;
+		}
 		*rp = r->rt_next;
 		if (rt_loopback == r)
 			rt_loopback = NULL;
@@ -332,8 +349,22 @@
 	 
 	rp = &rt_base;
 	while ((r = *rp) != NULL) {
-		if ((r->rt_mask & mask) != mask)
+		/*
+		 * When adding a duplicate route, add it before
+		 * the route with a higher metric.
+		 */
+		if (duplicate &&
+		    r->rt_dst == dst &&
+		    r->rt_mask == mask &&
+		    r->rt_metric > metric)
 			break;
+		else
+		/*
+		 * Otherwise, just add it before the
+		 * route with a higher generality.
+		 */
+			if ((r->rt_mask & mask) != mask)
+				break;
 		rp = &r->rt_next;
 	}
 	rt->rt_next = r;
@@ -381,7 +412,7 @@
 	char * devname;
 	struct device * dev = NULL;
 	unsigned long flags, daddr, mask, gw;
-	unsigned char metric;
+	short metric;
 
 	/*
 	 *	If a device is specified find it.
@@ -489,17 +520,26 @@
 static int rt_kill(struct rtentry *r)
 {
 	struct sockaddr_in *trg;
+	struct sockaddr_in *msk;
+	struct sockaddr_in *gtw;
 	char *devname;
 	int err;
 
 	trg = (struct sockaddr_in *) &r->rt_dst;
+	msk = (struct sockaddr_in *) &r->rt_genmask;
+	gtw = (struct sockaddr_in *) &r->rt_gateway;
 	if ((devname = r->rt_dev) != NULL) 
 	{
 		err = getname(devname, &devname);
 		if (err)
 			return err;
 	}
-	rt_del(trg->sin_addr.s_addr, devname);
+	/*
+	 * metric can become negative here if it wasn't filled in
+	 * but that's a fortunate accident; we really use that in rt_del.
+	 */
+	rt_del(trg->sin_addr.s_addr, msk->sin_addr.s_addr, devname,
+		gtw->sin_addr.s_addr, r->rt_flags, r->rt_metric - 1);
 	if ( devname != NULL )
 		putname(devname);
 	return 0;
============================================================================
--- route.c.orig	Wed Jul  5 23:12:22 1995
+++ route.c	Wed Aug  9 12:41:41 1995
@@ -5,14 +5,16 @@
  * Usage:       route [-nv] [ {add|del} [{-net|-host}] target
  *                    [ gw ] [ netmask ] [ metric ] [ device ] [reject]]
  *
- * Version:     NetTools-1.1.51	28/09/94
- *  	derived from '@(#)route.c     1.70    01/04/94' by Fred N. van Kempen.
+ * Version:     NetTools-1.3.6   09-Aug-1995
+ *  			(derived from '@(#)route.c     1.70    01/04/94'
+ *			by Fred N. van Kempen.)
  *
  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  *              Modified for Net-2Debugged by Johannes Stille,
  *                      <johannes@titan.os.open.de>
  *		Changes by Linus Torvalds
  *		Further changes by Alan Cox to add the new mtu/window stuff
+ *		Changes by Miquel van Smoorenburg to rt_add and rt_del
  */
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -32,12 +34,12 @@
 #include "config.h"
 #include "net-locale.h"
 
-char           *Version = "@(#) route 1.1.51 (28/09/94)";
+char           *Version = "@(#) route 1.3.6 (09-Aug-1995)";
 
 /* Pathnames of the PROCfs files used by NET. */
 #define _PATH_PROCNET_ROUTE	"/proc/net/route"
 
-#ifdef SIOCADDRTOLD
+#if defined (SIOCADDRTOLD) || defined (RTF_IRTT)
 #define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
 #define full_mask(x) (x)
 #else
@@ -270,7 +272,7 @@
 }
 
 /* Add a routing table entry. */
-int rt_add(char **args)
+int rt_add(char **args, int delete)
 {
 	struct rtentry rt;
 	char target[128], gateway[128] = "NONE", netmask[128] = "default";
@@ -323,7 +325,7 @@
 			if (!*args || !isdigit(**args))
 				usage();
 			metric = atoi(*args);
-#ifdef SIOCADDRTOLD
+#if defined (SIOCADDRTOLD) || defined (RTF_IRTT)
 			rt.rt_metric = metric + 1;
 #else
 			if (opt_v)
@@ -433,39 +435,22 @@
 			return -1;
 		}
 	}
-	/* Tell the kernel to accept this route. */
-	if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
-		fprintf(stderr, "SIOCADDRT: %s\n", strerror(errno));
-		return (-1);
-	}
-	return (0);
-}
-
-
-/* Delete a routing table entry. */
-int rt_del(char **args)
-{
-	char target[128];
-	struct sockaddr trg;
-	struct rtentry rt;
-
-	if (!args[0] || args[1])
-		usage();
 
-	strcpy(target, *args);
+	/* Fill out netmask if still unset */
+	if (!delete && rt.rt_flags & RTF_HOST)
+		mask_in_addr(rt) = 0xffffffff;
 
-	if (resolve(target, &trg) < 0) {
-		reserror(target);
-		return (-1);
-	}
-	/* Clean out the RTREQ structure. */
-	memset((char *) &rt, 0, sizeof(struct rtentry));
-	memcpy((char *) &rt.rt_dst, (char *) &trg, sizeof(struct sockaddr));
-
-	/* Tell the kernel to delete this route. */
-	if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
-		fprintf(stderr, "SIOCDELRT: %s\n", strerror(errno));
-		return (-1);
+	/* Tell the kernel to accept this route. */
+	if (delete) {
+		if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
+			fprintf(stderr, "SIOCDELRT: %s\n", strerror(errno));
+			return (-1);
+		}
+	} else {
+		if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
+			fprintf(stderr, "SIOCADDRT: %s\n", strerror(errno));
+			return (-1);
+		}
 	}
 	return (0);
 }
@@ -509,7 +494,8 @@
 		exit(0);
 	}
 	/* Fetch the command. */
-	if (strcmp(*argv, "add") && strcmp(*argv, "del"))
+	if (strcmp(*argv, "add") && strcmp(*argv, "del") &&
+			strcmp(*argv, "delete"))
 		usage();
 
 	/* Create a socket to the INET kernel. */
@@ -520,9 +506,9 @@
 	}
 	/* See what we have to do here. */
 	if (!strcmp(*argv, "add"))
-		i = rt_add(++argv);
+		i = rt_add(++argv, 0);
 	else
-		i = rt_del(++argv);
+		i = rt_add(++argv, 1);
 
 	/* Close the socket. */
 	(void) close(skfd);
===========================================================================

Mike.
--
Miquel van Smoorenburg, miquels@cistron.nl      Cistron Internet Services
Mail info@cistron.nl               An independent Dutch Internet Provider
for more information           <A Href = "http://www.cistron.nl/">CIS</A>
   +31-1720-19445 (Voice) 30979 (Fax) 42580 (Data) - Alphen a/d Rijn

