funny ECMP

Ingo Flaschberger if at xip.at
Thu Sep 16 19:38:57 UTC 2010


Hi Qing,

version 4 o patch...
fixed deleting interface loopback routes.

Kind regards,
 	Ingo Flaschberger
-------------- next part --------------
diff -u -r /usr_diff/src/sys/contrib/ipfilter/netinet/ip_pool.c /router/usr/src/sys/contrib/ipfilter/netinet/ip_pool.c
--- /usr_diff/src/sys/contrib/ipfilter/netinet/ip_pool.c	2007-10-18 21:42:38.000000000 +0000
+++ /router/usr/src/sys/contrib/ipfilter/netinet/ip_pool.c	2010-09-11 01:02:31.000000000 +0000
@@ -620,7 +620,7 @@
 
 	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
 	ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
-				   ipo->ipo_head);
+				   ipo->ipo_head, NULL);
 	RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
 
 	ip_pool_node_deref(ipe);
@@ -751,7 +751,7 @@
 	RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
 	while ((n = ipo->ipo_list) != NULL) {
 		ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
-					   ipo->ipo_head);
+					   ipo->ipo_head, NULL);
 
 		*n->ipn_pnext = n->ipn_next;
 		if (n->ipn_next)
@@ -963,7 +963,7 @@
 	struct radix_node_head *rnh = p;
 	struct radix_node *d;
 
-	d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
+	d = rnh->rnh_deladdr(n->rn_key, NULL, rnh, NULL);
 	if (d != NULL) {
 		FreeS(d, max_keylen + 2 * sizeof (*d));
 	}
diff -u -r /usr_diff/src/sys/contrib/pf/net/pf.c /router/usr/src/sys/contrib/pf/net/pf.c
--- /usr_diff/src/sys/contrib/pf/net/pf.c	2010-01-23 00:32:19.000000000 +0000
+++ /router/usr/src/sys/contrib/pf/net/pf.c	2010-08-26 15:12:12.000000000 +0000
@@ -99,9 +99,7 @@
 #include <net/if_types.h>
 #include <net/bpf.h>
 #include <net/route.h>
-#ifndef __FreeBSD__
 #include <net/radix_mpath.h>
-#endif
 
 #include <netinet/in.h>
 #include <netinet/in_var.h>
@@ -6166,9 +6164,9 @@
 			if (kif->pfik_ifp == ifp)
 				ret = 1;
 #ifdef __FreeBSD__ /* MULTIPATH_ROUTING */
-			rn = NULL;
+			rn = rn_mpath_next(rn); /* XXX was before: rn = NULL; */
 #else
-			rn = rn_mpath_next(rn);
+			rn = rn_mpath_next(rn, 0);
 #endif
 		} while (check_mpath == 1 && rn != NULL && ret == 0);
 	} else
diff -u -r /usr_diff/src/sys/contrib/pf/net/pf_table.c /router/usr/src/sys/contrib/pf/net/pf_table.c
--- /usr_diff/src/sys/contrib/pf/net/pf_table.c	2009-08-03 08:13:06.000000000 +0000
+++ /router/usr/src/sys/contrib/pf/net/pf_table.c	2010-08-26 11:50:31.000000000 +0000
@@ -1114,17 +1114,9 @@
 #endif
 	if (KENTRY_NETWORK(ke)) {
 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
-#ifdef __FreeBSD__
-		rn = rn_delete(&ke->pfrke_sa, &mask, head);
-#else
 		rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL);
-#endif
 	} else
-#ifdef __FreeBSD__
-		rn = rn_delete(&ke->pfrke_sa, NULL, head);
-#else
 		rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL);
-#endif
 	splx(s);
 
 	if (rn == NULL) {
diff -u -r /usr_diff/src/sys/net/radix.c /router/usr/src/sys/net/radix.c
--- /usr_diff/src/sys/net/radix.c	2010-04-02 05:02:50.000000000 +0000
+++ /router/usr/src/sys/net/radix.c	2010-09-11 01:13:34.000000000 +0000
@@ -614,7 +614,7 @@
 	struct radix_node treenodes[2];
 {
 	caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
-	register struct radix_node *t, *x = 0, *tt;
+	register struct radix_node *t, *x = 0, *xx = 0, *tt;
 	struct radix_node *saved_tt, *top = head->rnh_treetop;
 	short b = 0, b_leaf = 0;
 	int keyduplicated;
@@ -723,12 +723,19 @@
 		x = t->rn_right;
 	/* Promote general routes from below */
 	if (x->rn_bit < 0) {
-	    for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
+	    for (mp = &t->rn_mklist; x; xx = x, x = x->rn_dupedkey) {
+		if (xx && xx->rn_mklist && xx->rn_mask == x->rn_mask &&
+				x->rn_mklist == 0) {
+			/* multipath route, bump refcount on first mklist */
+			x->rn_mklist = xx->rn_mklist;
+			x->rn_mklist->rm_refs++;
+		}
 		if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) {
 			*mp = m = rn_new_radix_mask(x, 0);
 			if (m)
 				mp = &m->rm_mklist;
 		}
+	    }
 	} else if (x->rn_mklist) {
 		/*
 		 * Skip over masks whose index is > that of new node
@@ -760,11 +767,30 @@
 			break;
 		if (m->rm_flags & RNF_NORMAL) {
 			mmask = m->rm_leaf->rn_mask;
-			if (tt->rn_flags & RNF_NORMAL) {
-#if !defined(RADIX_MPATH)
-			    log(LOG_ERR,
-			        "Non-unique normal route, mask not entered\n");
+                        if (keyduplicated) {
+				if (m->rm_leaf->rn_parent == tt)
+					/* new route is bettter */
+					m->rm_leaf = tt;
+#ifdef DIAGNOSTIC
+				else {
+					for (t = m->rm_leaf; t;
+						t = t->rn_dupedkey) {
+							break;
+					}
+					if (t == NULL) {
+						log(LOG_ERR, "Non-unique "
+							"normal route on dupedkey, "
+							"mask not entered\n");
+						return tt;
+					}
+				}
 #endif
+				m->rm_refs++;
+				tt->rn_mklist = m;
+				return tt;
+			 } else if (tt->rn_flags & RNF_NORMAL) {
+				log(LOG_ERR, "Non-unique normal route,"
+					" mask not entered\n");
 				return tt;
 			}
 		} else
@@ -783,9 +809,10 @@
 }
 
 struct radix_node *
-rn_delete(v_arg, netmask_arg, head)
+rn_delete(v_arg, netmask_arg, head, rn)
 	void *v_arg, *netmask_arg;
 	struct radix_node_head *head;
+	struct radix_node *rn;
 {
 	register struct radix_node *t, *p, *x, *tt;
 	struct radix_mask *m, *saved_m, **mp;
@@ -815,13 +842,38 @@
 			if ((tt = tt->rn_dupedkey) == 0)
 				return (0);
 	}
+#ifdef RADIX_MPATH
+	if (rn) {
+		while (tt != rn)
+			if ((tt = tt->rn_dupedkey) == 0)
+				return (0);
+	}
+#endif
+	
 	if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
 		goto on1;
 	if (tt->rn_flags & RNF_NORMAL) {
-		if (m->rm_leaf != tt || m->rm_refs > 0) {
+		if (m->rm_leaf != tt && m->rm_refs == 0) {
 			log(LOG_ERR, "rn_delete: inconsistent annotation\n");
 			return 0;  /* dangling ref could cause disaster */
 		}
+		if (m->rm_leaf != tt) {
+			if (--m->rm_refs >= 0)
+				goto on1;
+                }
+		/* tt is currently the head of the possible multipath chain */
+		if (m->rm_refs > 0) {
+			if (tt->rn_dupedkey == NULL ||
+			    tt->rn_dupedkey->rn_mklist != m) {
+				log(LOG_ERR, "rn_delete: inconsistent "
+				    "dupedkey list\n");
+				return (0);
+			}
+			m->rm_leaf = tt->rn_dupedkey;
+			--m->rm_refs;
+			goto on1;
+		}
+		/* else tt is last and only route */
 	} else {
 		if (m->rm_mask != tt->rn_mask) {
 			log(LOG_ERR, "rn_delete: inconsistent annotation\n");
@@ -869,21 +921,17 @@
 		 */
 		if (tt == saved_tt) {
 			/* remove from head of chain */
-			x = dupedkey; x->rn_parent = t;
+			x = dupedkey; 
+			x->rn_parent = t;
 			if (t->rn_left == tt)
 				t->rn_left = x;
 			else
 				t->rn_right = x;
 		} else {
-			/* find node in front of tt on the chain */
-			for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
-				p = p->rn_dupedkey;
-			if (p) {
-				p->rn_dupedkey = tt->rn_dupedkey;
-				if (tt->rn_dupedkey)		/* parent */
-					tt->rn_dupedkey->rn_parent = p;
-								/* parent */
-			} else log(LOG_ERR, "rn_delete: couldn't find us\n");
+			x = saved_tt;
+			t->rn_dupedkey = tt->rn_dupedkey;
+			if (tt->rn_dupedkey)
+				tt->rn_dupedkey->rn_parent = t;
 		}
 		t = tt + 1;
 		if  (t->rn_flags & RNF_ACTIVE) {
@@ -931,14 +979,21 @@
 				if (m == x->rn_mklist) {
 					struct radix_mask *mm = m->rm_mklist;
 					x->rn_mklist = 0;
-					if (--(m->rm_refs) < 0)
+					if (--(m->rm_refs) < 0) {
 						MKFree(m);
+					} else if (m->rm_flags & RNF_NORMAL) {
+						/*
+						 * don't progress because this
+						 * a multipath route. Next
+						 * route will use the same m.
+						 */
+						mm = m;
+					}
 					m = mm;
 				}
 			if (m)
 				log(LOG_ERR,
-				    "rn_delete: Orphaned Mask %p at %p\n",
-				    m, x);
+				    "rn_delete: Orphaned Mask %p at %p\n", m, x);
 		}
 	}
 	/*
@@ -990,11 +1045,8 @@
 	 * rn_search_m is sort-of-open-coded here. We cannot use the
 	 * function because we need to keep track of the last node seen.
 	 */
-	/* printf("about to search\n"); */
 	for (rn = h->rnh_treetop; rn->rn_bit >= 0; ) {
 		last = rn;
-		/* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n",
-		       rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */
 		if (!(rn->rn_bmask & xm[rn->rn_offset])) {
 			break;
 		}
@@ -1004,7 +1056,6 @@
 			rn = rn->rn_left;
 		}
 	}
-	/* printf("done searching\n"); */
 
 	/*
 	 * Two cases: either we stepped off the end of our mask,
@@ -1015,8 +1066,6 @@
 	rn = last;
 	lastb = rn->rn_bit;
 
-	/* printf("rn %p, lastb %d\n", rn, lastb);*/
-
 	/*
 	 * This gets complicated because we may delete the node
 	 * while applying the function f to it, so we need to calculate
@@ -1026,7 +1075,6 @@
 		rn = rn->rn_left;
 
 	while (!stopping) {
-		/* printf("node %p (%d)\n", rn, rn->rn_bit); */
 		base = rn;
 		/* If at right child go back up, otherwise, go right */
 		while (rn->rn_parent->rn_right == rn
@@ -1036,7 +1084,6 @@
 			/* if went up beyond last, stop */
 			if (rn->rn_bit <= lastb) {
 				stopping = 1;
-				/* printf("up too far\n"); */
 				/*
 				 * XXX we should jump to the 'Process leaves'
 				 * part, because the values of 'rn' and 'next'
@@ -1062,7 +1109,6 @@
 		/* Process leaves */
 		while ((rn = base) != 0) {
 			base = rn->rn_dupedkey;
-			/* printf("leaf %p\n", rn); */
 			if (!(rn->rn_flags & RNF_ROOT)
 			    && (error = (*f)(rn, w)))
 				return (error);
@@ -1070,7 +1116,6 @@
 		rn = next;
 
 		if (rn->rn_flags & RNF_ROOT) {
-			/* printf("root, stopping"); */
 			stopping = 1;
 		}
 
diff -u -r /usr_diff/src/sys/net/radix.h /router/usr/src/sys/net/radix.h
--- /usr_diff/src/sys/net/radix.h	2010-03-23 09:58:59.000000000 +0000
+++ /router/usr/src/sys/net/radix.h	2010-09-10 20:15:46.000000000 +0000
@@ -114,7 +114,7 @@
 		(void *v, void *mask,
 		     struct radix_node_head *head, struct radix_node nodes[]);
 	struct	radix_node *(*rnh_deladdr)	/* remove based on sockaddr */
-		(void *v, void *mask, struct radix_node_head *head);
+		(void *v, void *mask, struct radix_node_head *head, struct radix_node *rn);
 	struct	radix_node *(*rnh_delpkt)	/* remove based on packet hdr */
 		(void *v, void *mask, struct radix_node_head *head);
 	struct	radix_node *(*rnh_matchaddr)	/* locate based on sockaddr */
@@ -168,7 +168,7 @@
 	 *rn_addmask(void *, int, int),
 	 *rn_addroute (void *, void *, struct radix_node_head *,
 			struct radix_node [2]),
-	 *rn_delete(void *, void *, struct radix_node_head *),
+	 *rn_delete(void *, void *, struct radix_node_head *, struct radix_node *),
 	 *rn_lookup (void *v_arg, void *m_arg,
 		        struct radix_node_head *head),
 	 *rn_match(void *, struct radix_node_head *);
diff -u -r /usr_diff/src/sys/net/radix_mpath.c /router/usr/src/sys/net/radix_mpath.c
--- /usr_diff/src/sys/net/radix_mpath.c	2010-04-02 05:02:50.000000000 +0000
+++ /router/usr/src/sys/net/radix_mpath.c	2010-09-16 19:24:45.000000000 +0000
@@ -112,46 +112,14 @@
 		 * we need to compare the interface address because
 		 * rt_gateway is a special sockadd_dl structure
 		 */
-		if (rt->rt_gateway->sa_family == AF_LINK) {
-			if (!memcmp(rt->rt_ifa->ifa_addr, gate, gate->sa_len))
+		if (rt->rt_gateway->sa_len == gate->sa_len &&
+			!memcmp(rt->rt_gateway, gate, gate->sa_len))
 				break;
-		} else {
-			if (rt->rt_gateway->sa_len == gate->sa_len &&
-			    !memcmp(rt->rt_gateway, gate, gate->sa_len))
-				break;
-		}
 	} while ((rn = rn_mpath_next(rn)) != NULL);
 
 	return (struct rtentry *)rn;
 }
 
-/* 
- * go through the chain and unlink "rt" from the list
- * the caller will free "rt"
- */
-int
-rt_mpath_deldup(struct rtentry *headrt, struct rtentry *rt)
-{
-        struct radix_node *t, *tt;
-
-        if (!headrt || !rt)
-            return (0);
-        t = (struct radix_node *)headrt;
-        tt = rn_mpath_next(t);
-        while (tt) {
-            if (tt == (struct radix_node *)rt) {
-                t->rn_dupedkey = tt->rn_dupedkey;
-                tt->rn_dupedkey = NULL;
-    	        tt->rn_flags &= ~RNF_ACTIVE;
-	        tt[1].rn_flags &= ~RNF_ACTIVE;
-                return (1);
-            }
-            t = tt;
-            tt = rn_mpath_next((struct radix_node *)t);
-        }
-        return (0);
-}
-
 /*
  * check if we have the same key/mask/gateway on the table already.
  */
@@ -262,9 +230,10 @@
 rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum)
 {
 	struct radix_node *rn0, *rn;
-	u_int32_t n;
+	u_int32_t n = 0;
 	struct rtentry *rt;
 	int64_t weight;
+	int64_t lowest_weight;
 
 	/*
 	 * XXX we don't attempt to lookup cached route again; what should
@@ -272,7 +241,7 @@
 	 */
 	if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)
 	    && RT_LINK_IS_UP(ro->ro_rt->rt_ifp))
-		return;				 
+		return;
 	ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, 0, fibnum);
 
 	/* if the route does not exist or it is not multipath, don't care */
@@ -285,20 +254,34 @@
 
 	/* beyond here, we use rn as the master copy */
 	rn0 = rn = (struct radix_node *)ro->ro_rt;
-	n = rn_mpath_count(rn0);
-
+	
+	/* find lowest weight route */
+	for ( rt = (struct rtentry *)rn, weight = rt->rt_rmx.rmx_weight; rn != NULL; rn = rn_mpath_next( rn)) {
+		/* XXX check if route is up? */
+		rt = (struct rtentry *)rn;
+		if(rt->rt_flags & RTF_UP) { 
+			if (weight > rt->rt_rmx.rmx_weight) {
+				weight = rt->rt_rmx.rmx_weight;
+				n = 1;
+			} else if (weight == rt->rt_rmx.rmx_weight)
+				n++;
+		}
+	}
+	lowest_weight = weight;
+	
+	/* select now one of the lowest weight routes */
 	/* gw selection by Modulo-N Hash (RFC2991) XXX need improvement? */
 	hash += hashjitter;
 	hash %= n;
-	for (weight = abs((int32_t)hash), rt = ro->ro_rt;
-	     weight >= rt->rt_rmx.rmx_weight && rn; 
-	     weight -= rt->rt_rmx.rmx_weight) {
-		
-		/* stay within the multipath routes */
-		if (rn->rn_dupedkey && rn->rn_mask != rn->rn_dupedkey->rn_mask)
-			break;
-		rn = rn->rn_dupedkey;
+	for ( rn = rn0, n = 0; rn != NULL; rn = rn_mpath_next( rn)) {
 		rt = (struct rtentry *)rn;
+		if(rt->rt_flags & RTF_UP) { 
+			if ( rt->rt_rmx.rmx_weight == lowest_weight) {
+				if (n == hash)
+					break;
+				n++;
+			}
+		}
 	}
 	/* XXX try filling rt_gwroute and avoid unreachable gw  */
 
diff -u -r /usr_diff/src/sys/net/route.c /router/usr/src/sys/net/route.c
--- /usr_diff/src/sys/net/route.c	2010-06-18 03:31:33.000000000 +0000
+++ /router/usr/src/sys/net/route.c	2010-09-16 19:12:18.000000000 +0000
@@ -875,7 +875,7 @@
 	 * Remove the item from the tree; it should be there,
 	 * but when callers invoke us blindly it may not (sigh).
 	 */
-	rn = rnh->rnh_deladdr(rt_key(rt), rt_mask(rt), rnh);
+	rn = rnh->rnh_deladdr(rt_key(rt), rt_mask(rt), rnh, NULL);
 	if (rn == NULL) {
 		error = ESRCH;
 		goto bad;
@@ -913,112 +913,6 @@
 	return (error);
 }
 
-#ifdef RADIX_MPATH
-static int
-rn_mpath_update(int req, struct rt_addrinfo *info,
-    struct radix_node_head *rnh, struct rtentry **ret_nrt)
-{
-	/*
-	 * if we got multipath routes, we require users to specify
-	 * a matching RTAX_GATEWAY.
-	 */
-	struct rtentry *rt, *rto = NULL;
-	register struct radix_node *rn;
-	int error = 0;
-
-	rn = rnh->rnh_matchaddr(dst, rnh);
-	if (rn == NULL)
-		return (ESRCH);
-	rto = rt = RNTORT(rn);
-	rt = rt_mpath_matchgate(rt, gateway);
-	if (rt == NULL)
-		return (ESRCH);
-	/*
-	 * this is the first entry in the chain
-	 */
-	if (rto == rt) {
-		rn = rn_mpath_next((struct radix_node *)rt);
-		/*
-		 * there is another entry, now it's active
-		 */
-		if (rn) {
-			rto = RNTORT(rn);
-			RT_LOCK(rto);
-			rto->rt_flags |= RTF_UP;
-			RT_UNLOCK(rto);
-		} else if (rt->rt_flags & RTF_GATEWAY) {
-			/*
-			 * For gateway routes, we need to 
-			 * make sure that we we are deleting
-			 * the correct gateway. 
-			 * rt_mpath_matchgate() does not 
-			 * check the case when there is only
-			 * one route in the chain.  
-			 */
-			if (gateway &&
-			    (rt->rt_gateway->sa_len != gateway->sa_len ||
-				memcmp(rt->rt_gateway, gateway, gateway->sa_len)))
-				error = ESRCH;
-			else {
-				/*
-				 * remove from tree before returning it
-				 * to the caller
-				 */
-				rn = rnh->rnh_deladdr(dst, netmask, rnh);
-				KASSERT(rt == RNTORT(rn), ("radix node disappeared"));
-				goto gwdelete;
-			}
-			
-		}
-		/*
-		 * use the normal delete code to remove
-		 * the first entry
-		 */
-		if (req != RTM_DELETE) 
-			goto nondelete;
-
-		error = ENOENT;
-		goto done;
-	}
-		
-	/*
-	 * if the entry is 2nd and on up
-	 */
-	if ((req == RTM_DELETE) && !rt_mpath_deldup(rto, rt))
-		panic ("rtrequest1: rt_mpath_deldup");
-gwdelete:
-	RT_LOCK(rt);
-	RT_ADDREF(rt);
-	if (req == RTM_DELETE) {
-		rt->rt_flags &= ~RTF_UP;
-		/*
-		 * One more rtentry floating around that is not
-		 * linked to the routing table. rttrash will be decremented
-		 * when RTFREE(rt) is eventually called.
-		 */
-		V_rttrash++;
-	}
-	
-nondelete:
-	if (req != RTM_DELETE)
-		panic("unrecognized request %d", req);
-	
-
-	/*
-	 * If the caller wants it, then it can have it,
-	 * but it's up to it to free the rtentry as we won't be
-	 * doing it.
-	 */
-	if (ret_nrt) {
-		*ret_nrt = rt;
-		RT_UNLOCK(rt);
-	} else
-		RTFREE_LOCKED(rt);
-done:
-	return (error);
-}
-#endif
-
 int
 rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
 				u_int fibnum)
@@ -1058,28 +952,30 @@
 
 	switch (req) {
 	case RTM_DELETE:
+	        if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == NULL)
+	                senderr(ESRCH);
+		rt = RNTORT(rn);
 #ifdef RADIX_MPATH
-		if (rn_mpath_capable(rnh)) {
-			error = rn_mpath_update(req, info, rnh, ret_nrt);
-			/*
-			 * "bad" holds true for the success case
-			 * as well
-			 */
-			if (error != ENOENT)
-				goto bad;
-			error = 0;
-		}
+                /*
+                 * if we got multipath routes, we require users to specify
+                 * a matching RTAX_GATEWAY.
+                 */
+                if (rn_mpath_capable(rnh)) {
+                        rt = rt_mpath_matchgate( rt, gateway);
+                        rn = (struct radix_node *)rt;
+                        if (!rt)
+                                senderr(ESRCH);
+                }
 #endif
 		/*
 		 * Remove the item from the tree and return it.
 		 * Complain if it is not there and do no more processing.
 		 */
-		rn = rnh->rnh_deladdr(dst, netmask, rnh);
+		rn = rnh->rnh_deladdr(dst, netmask, rnh, rn);
 		if (rn == NULL)
 			senderr(ESRCH);
 		if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
 			panic ("rtrequest delete");
-		rt = RNTORT(rn);
 		RT_LOCK(rt);
 		RT_ADDREF(rt);
 		rt->rt_flags &= ~RTF_UP;
@@ -1474,10 +1370,9 @@
 			    RNTORT(rn)->rt_ifa != ifa ||
 			    !sa_equal((struct sockaddr *)rn->rn_key, dst));
 			RADIX_NODE_HEAD_UNLOCK(rnh);
-			if (error) {
+			if (error)
 				/* this is only an error if bad on ALL tables */
 				continue;
-			}
 		}
 		/*
 		 * Do the actual request
diff -u -r /usr_diff/src/sys/netinet/in.c /router/usr/src/sys/netinet/in.c
--- /usr_diff/src/sys/netinet/in.c	2010-09-07 13:10:46.000000000 +0000
+++ /router/usr/src/sys/netinet/in.c	2010-09-16 19:18:46.000000000 +0000
@@ -1374,12 +1374,45 @@
 in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr)
 {
 	struct rtentry *rt;
+#ifdef RADIX_MPATH
+	int64_t weight;
+	struct rtentry *rt0;
+	int32_t found = 0;
+#endif
 
 	KASSERT(l3addr->sa_family == AF_INET,
 	    ("sin_family %d", l3addr->sa_family));
 
 	/* XXX rtalloc1 should take a const param */
 	rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
+
+#ifdef RADIX_MPATH
+	rt0 = rt;
+        if ((rt != NULL) && ( rn_mpath_next((struct radix_node *)rt) != NULL)) {
+		/* check if there are other, matching routes */
+		/* find lowest weight route */
+		for ( weight = rt->rt_rmx.rmx_weight; rt != NULL; rt = (struct rtentry *)rn_mpath_next( (struct radix_node *)rt)) {
+			if(rt->rt_flags & RTF_UP) {
+				if (weight > rt->rt_rmx.rmx_weight)
+					weight = rt->rt_rmx.rmx_weight;
+			}
+		}
+
+		/* find now one non gateway route with lowest weight */
+		for ( rt = rt0; rt != NULL; rt = (struct rtentry *)rn_mpath_next( (struct radix_node *)rt)) {
+			if(rt->rt_flags & RTF_UP) {
+				if ((weight == rt->rt_rmx.rmx_weight) && !(rt->rt_flags & RTF_GATEWAY)) {
+					found = 1;
+					break;
+				}
+			}
+		}
+		if (found == 0)
+			rt = NULL;
+	}
+	
+#endif	
+
 	if (rt == NULL || (!(flags & LLE_PUB) &&
 			   ((rt->rt_flags & RTF_GATEWAY) || 
 			    (rt->rt_ifp != ifp)))) {
@@ -1387,11 +1420,21 @@
 		log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
 		    inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
 #endif
+#ifdef RADIX_MPATH
+		if (rt0 != NULL)
+			RTFREE_LOCKED(rt0);
+#else
 		if (rt != NULL)
 			RTFREE_LOCKED(rt);
+#endif
 		return (EINVAL);
 	}
+#ifdef RADIX_MPATH
+	RTFREE_LOCKED(rt0);
+#else
 	RTFREE_LOCKED(rt);
+#endif
+
 	return 0;
 }
 
@@ -1424,7 +1467,7 @@
 	if (lle == NULL) {
 #ifdef DIAGNOSTIC
 		if (flags & LLE_DELETE)
-			log(LOG_INFO, "interface address is missing from cache = %p  in delete\n", lle);	
+			log(LOG_INFO, "interface address is missing from cache = %p  in delete\n", lle);
 #endif
 		if (!(flags & LLE_CREATE))
 			return (NULL);
diff -u -r /usr_diff/src/sys/netinet/ipfw/ip_fw_table.c /router/usr/src/sys/netinet/ipfw/ip_fw_table.c
--- /usr_diff/src/sys/netinet/ipfw/ip_fw_table.c	2010-03-23 09:58:59.000000000 +0000
+++ /router/usr/src/sys/netinet/ipfw/ip_fw_table.c	2010-08-26 12:47:27.000000000 +0000
@@ -137,7 +137,7 @@
 	mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
 	sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
 	IPFW_WLOCK(ch);
-	ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh);
+	ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh, NULL);
 	if (ent == NULL) {
 		IPFW_WUNLOCK(ch);
 		return (ESRCH);
@@ -154,7 +154,7 @@
 	struct table_entry *ent;
 
 	ent = (struct table_entry *)
-	    rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
+	    rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh, NULL);
 	if (ent != NULL)
 		free(ent, M_IPFW_TBL);
 	return (0);
diff -u -r /usr_diff/src/sys/netinet/raw_ip.c /router/usr/src/sys/netinet/raw_ip.c
--- /usr_diff/src/sys/netinet/raw_ip.c	2010-08-27 18:50:12.000000000 +0000
+++ /router/usr/src/sys/netinet/raw_ip.c	2010-09-11 02:54:45.000000000 +0000
@@ -755,6 +755,8 @@
 		if (err == 0)
 			ia->ia_flags |= IFA_ROUTE;
 		err = ifa_add_loopback_route((struct ifaddr *)ia, sa);
+		if (err == 0)
+		        ia->ia_flags |= IFA_RTSELF;
 		ifa_free(&ia->ia_ifa);
 		break;
 	}


More information about the freebsd-net mailing list