Dear Li,

attached latest version of ecmp patch.

Kind regards,
        Ingo Flaschberger
diff -r -u /usr_diff/src/sys/contrib/ipfilter/netinet/ip_pool.c 
/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
+++ /usr/src/sys/contrib/ipfilter/netinet/ip_pool.c     2010-09-06 
11:22:39.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 -r -u /usr_diff/src/sys/contrib/pf/net/pf.c 
/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
+++ /usr/src/sys/contrib/pf/net/pf.c    2010-09-06 11:22:39.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 -r -u /usr_diff/src/sys/contrib/pf/net/pf_table.c 
/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
+++ /usr/src/sys/contrib/pf/net/pf_table.c      2010-09-06 11:22:39.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 -r -u /usr_diff/src/sys/net/radix.c /usr/src/sys/net/radix.c
--- /usr_diff/src/sys/net/radix.c       2010-04-02 05:02:50.000000000 +0000
+++ /usr/src/sys/net/radix.c    2010-09-11 01:39:40.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 -r -u /usr_diff/src/sys/net/radix.h /usr/src/sys/net/radix.h
--- /usr_diff/src/sys/net/radix.h       2010-03-23 09:58:59.000000000 +0000
+++ /usr/src/sys/net/radix.h    2010-09-06 11:22:39.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 -r -u /usr_diff/src/sys/net/radix_mpath.c /usr/src/sys/net/radix_mpath.c
--- /usr_diff/src/sys/net/radix_mpath.c 2010-04-02 05:02:50.000000000 +0000
+++ /usr/src/sys/net/radix_mpath.c      2010-09-06 11:22:39.000000000 +0000
@@ -125,33 +125,6 @@
        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 +235,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 +246,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 +259,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 -r -u /usr_diff/src/sys/net/route.c /usr/src/sys/net/route.c
--- /usr_diff/src/sys/net/route.c       2010-06-18 03:31:33.000000000 +0000
+++ /usr/src/sys/net/route.c    2010-09-06 11:22:39.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 -r -u /usr_diff/src/sys/netinet/in.c /usr/src/sys/netinet/in.c
--- /usr_diff/src/sys/netinet/in.c      2010-09-07 13:10:46.000000000 +0000
+++ /usr/src/sys/netinet/in.c   2010-09-11 02:20:58.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 -r -u /usr_diff/src/sys/netinet/ipfw/ip_fw_table.c 
/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
+++ /usr/src/sys/netinet/ipfw/ip_fw_table.c     2010-09-06 11:22:39.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 -r -u /usr_diff/src/sys/netinet/raw_ip.c /usr/src/sys/netinet/raw_ip.c
--- /usr_diff/src/sys/netinet/raw_ip.c  2010-08-27 18:50:12.000000000 +0000
+++ /usr/src/sys/netinet/raw_ip.c       2010-09-11 02:37:26.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;
        }
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"

Reply via email to