@ -19,10 +19,7 @@
# include <net/pkt_sched.h>
# include <net/inet_ecn.h>
# include <net/red.h>
# include <linux/ip.h>
# include <net/ip.h>
# include <linux/ipv6.h>
# include <net/ipv6.h>
# include <net/flow_keys.h>
/*
CHOKe stateless AQM for fair bandwidth allocation
@ -142,92 +139,10 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx)
- - sch - > q . qlen ;
}
/*
* Compare flow of two packets
* Returns true only if source and destination address and port match .
* false for special cases
*/
static bool choke_match_flow ( struct sk_buff * skb1 ,
struct sk_buff * skb2 )
{
int off1 , off2 , poff ;
const u32 * ports1 , * ports2 ;
u32 _ports1 , _ports2 ;
u8 ip_proto ;
__u32 hash1 ;
if ( skb1 - > protocol ! = skb2 - > protocol )
return false ;
/* Use rxhash value as quick check */
hash1 = skb_get_rxhash ( skb1 ) ;
if ( ! hash1 | | hash1 ! = skb_get_rxhash ( skb2 ) )
return false ;
/* Probably match, but be sure to avoid hash collisions */
off1 = skb_network_offset ( skb1 ) ;
off2 = skb_network_offset ( skb2 ) ;
switch ( skb1 - > protocol ) {
case __constant_htons ( ETH_P_IP ) : {
const struct iphdr * ip1 , * ip2 ;
struct iphdr _ip1 , _ip2 ;
ip1 = skb_header_pointer ( skb1 , off1 , sizeof ( _ip1 ) , & _ip1 ) ;
ip2 = skb_header_pointer ( skb2 , off2 , sizeof ( _ip2 ) , & _ip2 ) ;
if ( ! ip1 | | ! ip2 )
return false ;
ip_proto = ip1 - > protocol ;
if ( ip_proto ! = ip2 - > protocol | |
ip1 - > saddr ! = ip2 - > saddr | | ip1 - > daddr ! = ip2 - > daddr )
return false ;
if ( ip_is_fragment ( ip1 ) | ip_is_fragment ( ip2 ) )
ip_proto = 0 ;
off1 + = ip1 - > ihl * 4 ;
off2 + = ip2 - > ihl * 4 ;
break ;
}
case __constant_htons ( ETH_P_IPV6 ) : {
const struct ipv6hdr * ip1 , * ip2 ;
struct ipv6hdr _ip1 , _ip2 ;
ip1 = skb_header_pointer ( skb1 , off1 , sizeof ( _ip1 ) , & _ip1 ) ;
ip2 = skb_header_pointer ( skb2 , off2 , sizeof ( _ip2 ) , & _ip2 ) ;
if ( ! ip1 | | ! ip2 )
return false ;
ip_proto = ip1 - > nexthdr ;
if ( ip_proto ! = ip2 - > nexthdr | |
ipv6_addr_cmp ( & ip1 - > saddr , & ip2 - > saddr ) | |
ipv6_addr_cmp ( & ip1 - > daddr , & ip2 - > daddr ) )
return false ;
off1 + = 40 ;
off2 + = 40 ;
}
default : /* Maybe compare MAC header here? */
return false ;
}
poff = proto_ports_offset ( ip_proto ) ;
if ( poff < 0 )
return true ;
off1 + = poff ;
off2 + = poff ;
ports1 = skb_header_pointer ( skb1 , off1 , sizeof ( _ports1 ) , & _ports1 ) ;
ports2 = skb_header_pointer ( skb2 , off2 , sizeof ( _ports2 ) , & _ports2 ) ;
if ( ! ports1 | | ! ports2 )
return false ;
return * ports1 = = * ports2 ;
}
struct choke_skb_cb {
u16 classid ;
u16 classid ;
u8 keys_valid ;
struct flow_keys keys ;
} ;
static inline struct choke_skb_cb * choke_skb_cb ( const struct sk_buff * skb )
@ -247,6 +162,32 @@ static u16 choke_get_classid(const struct sk_buff *skb)
return choke_skb_cb ( skb ) - > classid ;
}
/*
* Compare flow of two packets
* Returns true only if source and destination address and port match .
* false for special cases
*/
static bool choke_match_flow ( struct sk_buff * skb1 ,
struct sk_buff * skb2 )
{
if ( skb1 - > protocol ! = skb2 - > protocol )
return false ;
if ( ! choke_skb_cb ( skb1 ) - > keys_valid ) {
choke_skb_cb ( skb1 ) - > keys_valid = 1 ;
skb_flow_dissect ( skb1 , & choke_skb_cb ( skb1 ) - > keys ) ;
}
if ( ! choke_skb_cb ( skb2 ) - > keys_valid ) {
choke_skb_cb ( skb2 ) - > keys_valid = 1 ;
skb_flow_dissect ( skb2 , & choke_skb_cb ( skb2 ) - > keys ) ;
}
return ! memcmp ( & choke_skb_cb ( skb1 ) - > keys ,
& choke_skb_cb ( skb2 ) - > keys ,
sizeof ( struct flow_keys ) ) ;
}
/*
* Classify flow using either :
* 1. pre - existing classification result in skb
@ -333,6 +274,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch)
goto other_drop ; /* Packet was eaten by filter */
}
choke_skb_cb ( skb ) - > keys_valid = 0 ;
/* Compute average queue usage (see RED) */
p - > qavg = red_calc_qavg ( p , sch - > q . qlen ) ;
if ( red_is_idling ( p ) )