diff -r -U2 linux-source-2.6.23-dsc/include/linux/rtnetlink.h linux-source-2.6.23-dsc-dsad/include/linux/rtnetlink.h --- linux-source-2.6.23-dsc/include/linux/rtnetlink.h 2007-10-09 16:31:38.000000000 -0400 +++ linux-source-2.6.23-dsc-dsad/include/linux/rtnetlink.h 2007-12-06 20:23:25.000000000 -0500 @@ -294,4 +294,5 @@ #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ #define RTNH_F_ONLINK 4 /* Gateway is forced on link */ +#define RTNH_F_DSAD 8 /* Dynamic PBR (weight = source realm) */ /* Macros to handle hexthops */ diff -r -U2 linux-source-2.6.23-dsc/include/net/ip_fib.h linux-source-2.6.23-dsc-dsad/include/net/ip_fib.h --- linux-source-2.6.23-dsc/include/net/ip_fib.h 2007-10-09 16:31:38.000000000 -0400 +++ linux-source-2.6.23-dsc-dsad/include/net/ip_fib.h 2007-12-06 20:23:25.000000000 -0500 @@ -202,5 +202,6 @@ extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, struct net_device *dev, __be32 *spec_dst, u32 *itag); -extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res); +extern void fib_select_multipath(const struct flowi *flp, + struct fib_result *res, u32 itag); struct rtentry; diff -r -U2 linux-source-2.6.23-dsc/net/ipv4/fib_semantics.c linux-source-2.6.23-dsc-dsad/net/ipv4/fib_semantics.c --- linux-source-2.6.23-dsc/net/ipv4/fib_semantics.c 2007-10-09 16:31:38.000000000 -0400 +++ linux-source-2.6.23-dsc-dsad/net/ipv4/fib_semantics.c 2007-12-07 14:36:10.000000000 -0500 @@ -1164,5 +1164,6 @@ */ -void fib_select_multipath(const struct flowi *flp, struct fib_result *res) +void fib_select_multipath(const struct flowi *flp, struct fib_result *res, + u32 itag) { struct fib_info *fi = res->fi; @@ -1170,8 +1171,20 @@ spin_lock_bh(&fib_multipath_lock); + change_nexthops(fi) { + if (net_ratelimit()) + printk(KERN_CRIT "DSAD Considering %x %x\n",nh->nh_weight,itag); + if ((nh->nh_flags & RTNH_F_DSAD) && + (((u32)nh->nh_weight - 1) == (itag >> 16))) { + res->nh_sel = nhsel; + spin_unlock_bh(&fib_multipath_lock); + if (net_ratelimit()) + printk(KERN_CRIT "Chose a DSAD multiroute\n"); + return; + } + } endfor_nexthops(fi); if (fi->fib_power <= 0) { int power = 0; change_nexthops(fi) { - if (!(nh->nh_flags&RTNH_F_DEAD)) { + if (!(nh->nh_flags&(RTNH_F_DEAD|RTNH_F_DSAD))) { power += nh->nh_weight; nh->nh_power = nh->nh_weight; @@ -1195,5 +1208,5 @@ change_nexthops(fi) { - if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) { + if (!(nh->nh_flags&(RTNH_F_DEAD|RTNH_F_DSAD)) && nh->nh_power) { if ((w -= nh->nh_power) <= 0) { nh->nh_power--; diff -r -U2 linux-source-2.6.23-dsc/net/ipv4/route.c linux-source-2.6.23-dsc-dsad/net/ipv4/route.c --- linux-source-2.6.23-dsc/net/ipv4/route.c 2007-10-09 16:31:38.000000000 -0400 +++ linux-source-2.6.23-dsc-dsad/net/ipv4/route.c 2007-12-06 20:24:45.000000000 -0500 @@ -1622,19 +1622,20 @@ } -static inline int __mkroute_input(struct sk_buff *skb, - struct fib_result* res, - struct in_device *in_dev, - __be32 daddr, __be32 saddr, u32 tos, - struct rtable **result) +static inline int ip_mkroute_input(struct sk_buff *skb, + struct fib_result* res, + const struct flowi *fl, + struct in_device *in_dev, + __be32 daddr, __be32 saddr, u32 tos) { - - struct rtable *rth; - int err; + struct rtable* rth = NULL; struct in_device *out_dev; unsigned flags = 0; __be32 spec_dst; u32 itag; + int err; + unsigned hash; - /* get a working reference to the output device */ + /* get a working reference to a potential output device */ + res->nh_sel = 0; /* needed? */ out_dev = in_dev_get(FIB_RES_DEV(*res)); if (out_dev == NULL) { @@ -1645,7 +1646,8 @@ } - + /* Do not check each. spec_dest entirely source dep (I hope.) */ err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res), in_dev->dev, &spec_dst, &itag); + if (err < 0) { ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, @@ -1659,4 +1661,19 @@ flags |= RTCF_DIRECTSRC; +#ifdef CONFIG_IP_ROUTE_MULTIPATH + if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0) + fib_select_multipath(fl, res, itag); +#endif + + /* Get reference to actual output device */ + in_dev_put(out_dev); + out_dev = in_dev_get(FIB_RES_DEV(*res)); + if (out_dev == NULL) { + if (net_ratelimit()) + printk(KERN_CRIT "Bug in ip_route_input" \ + "_slow(). Please, report\n"); + return -EINVAL; + } + if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) && (IN_DEV_SHARED_MEDIA(out_dev) || @@ -1708,36 +1725,13 @@ rth->rt_flags = flags; - - *result = rth; err = 0; - cleanup: - /* release the working reference to the output device */ - in_dev_put(out_dev); - return err; -} - -static inline int ip_mkroute_input(struct sk_buff *skb, - struct fib_result* res, - const struct flowi *fl, - struct in_device *in_dev, - __be32 daddr, __be32 saddr, u32 tos) -{ - struct rtable* rth = NULL; - int err; - unsigned hash; - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0) - fib_select_multipath(fl, res); -#endif - - /* create a routing cache entry */ - err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth); - if (err) - return err; /* put it into the cache */ hash = rt_hash(daddr, saddr, fl->iif); return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); + cleanup: + /* release the working reference to the output device */ + in_dev_put(out_dev); + return err; } @@ -2305,5 +2299,5 @@ #ifdef CONFIG_IP_ROUTE_MULTIPATH if (res.fi->fib_nhs > 1 && fl.oif == 0) - fib_select_multipath(&fl, &res); + fib_select_multipath(&fl, &res, 0); else #endif