Index: linux/include/linux/pkt_sched.h =================================================================== --- linux.orig/include/linux/pkt_sched.h 2006-06-17 18:49:35.000000000 -0700 +++ linux/include/linux/pkt_sched.h 2006-11-16 22:23:10.000000000 -0800 @@ -137,6 +137,9 @@ __u32 limit; /* Maximal packets in queue */ unsigned divisor; /* Hash divisor */ unsigned flows; /* Maximal number of flows */ + unsigned char flags; +#define TC_SFQ_NOPORTS (1) /* ignore src/dst ports in hash */ +#define TC_SFQ_NOSRCIP (2) /* ignore src ip address in hash */ }; /* Index: linux/net/sched/sch_sfq.c =================================================================== --- linux.orig/net/sched/sch_sfq.c 2006-11-16 22:22:40.000000000 -0800 +++ linux/net/sched/sch_sfq.c 2006-11-16 22:23:10.000000000 -0800 @@ -35,6 +35,7 @@ #include #include #include +#include /* Stochastic Fairness Queuing algorithm. @@ -105,10 +106,11 @@ int perturb_period; unsigned quantum; /* Allotment per round: MUST BE >= MTU */ int limit; + unsigned flags; /* Variables */ struct timer_list perturb_timer; - int perturbation; + u32 perturbation; sfq_index tail; /* Index of current slot in round */ sfq_index max_depth; /* Maximal depth */ @@ -120,53 +122,51 @@ struct sfq_head dep[SFQ_DEPTH*2]; /* Linked list of slots, indexed by depth */ }; -static __inline__ unsigned sfq_fold_hash(struct sfq_sched_data *q, u32 h, u32 h1) -{ - int pert = q->perturbation; - - /* Have we any rotation primitives? If not, WHY? */ - h ^= (h1<>(0x1F - pert)); - h ^= h>>10; - return h & 0x3FF; -} - static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) { - u32 h, h2; + u32 h1, h2, h3; + h3 = 0; switch (skb->protocol) { case __constant_htons(ETH_P_IP): { struct iphdr *iph = skb->nh.iph; - h = iph->daddr; - h2 = iph->saddr^iph->protocol; - if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && + h1 = iph->daddr; + h2 = (q->flags & TC_SFQ_NOSRCIP) + ? 0 : (iph->saddr^iph->protocol); + if (!(q->flags & TC_SFQ_NOPORTS) && + !(iph->frag_off&htons(IP_MF|IP_OFFSET)) && (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_SCTP || iph->protocol == IPPROTO_DCCP || iph->protocol == IPPROTO_ESP)) - h2 ^= *(((u32*)iph) + iph->ihl); + h3 ^= *(((u32*)iph) + iph->ihl); break; } case __constant_htons(ETH_P_IPV6): { struct ipv6hdr *iph = skb->nh.ipv6h; - h = iph->daddr.s6_addr32[3]; - h2 = iph->saddr.s6_addr32[3]^iph->nexthdr; - if (iph->nexthdr == IPPROTO_TCP || + h1 = iph->daddr.s6_addr32[3]; + h2 = (q->flags & TC_SFQ_NOSRCIP) + ? 0 : (iph->saddr.s6_addr32[3]^iph->nexthdr); + if (!(q->flags & TC_SFQ_NOPORTS) && + (iph->nexthdr == IPPROTO_TCP || iph->nexthdr == IPPROTO_UDP || iph->nexthdr == IPPROTO_SCTP || iph->nexthdr == IPPROTO_DCCP || - iph->nexthdr == IPPROTO_ESP) - h2 ^= *(u32*)&iph[1]; + iph->nexthdr == IPPROTO_ESP)) + h3 ^= *(u32*)&iph[1]; break; } default: - h = (u32)(unsigned long)skb->dst^skb->protocol; - h2 = (u32)(unsigned long)skb->sk; + h1 = (u32)(unsigned long)skb->dst; + h2 = (q->flags & TC_SFQ_NOSRCIP) + ? 0 : (u32)(unsigned long)skb->sk; + h3 = skb->protocol; } - return sfq_fold_hash(q, h, h2); + return jhash_3words(h1, h2, h3, q->perturbation) + & (SFQ_HASH_DIVISOR-1); } static inline void sfq_link(struct sfq_sched_data *q, sfq_index x) @@ -381,7 +381,7 @@ struct Qdisc *sch = (struct Qdisc*)arg; struct sfq_sched_data *q = qdisc_priv(sch); - q->perturbation = net_random()&0x1F; + q->perturbation = net_random(); if (q->perturb_period) { q->perturb_timer.expires = jiffies + q->perturb_period; @@ -394,7 +394,8 @@ struct sfq_sched_data *q = qdisc_priv(sch); struct tc_sfq_qopt *ctl = RTA_DATA(opt); - if (opt->rta_len < RTA_LENGTH(sizeof(*ctl))) + /* support older tc_sfq_qopt without a flags field */ + if (opt->rta_len < RTA_LENGTH(offsetof(struct tc_sfq_qopt, flags))) return -EINVAL; sch_tree_lock(sch); @@ -411,6 +412,14 @@ q->perturb_timer.expires = jiffies + q->perturb_period; add_timer(&q->perturb_timer); } + + /* must check if flags field is present */ + if (opt->rta_len >= RTA_LENGTH(sizeof(struct tc_sfq_qopt))) { + q->flags = ctl->flags; + } + else { + q->flags = 0; + } sch_tree_unlock(sch); return 0; } @@ -465,6 +474,7 @@ opt.limit = q->limit; opt.divisor = SFQ_HASH_DIVISOR; opt.flows = q->limit; + opt.flags = q->flags; RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);