diff -ruN l.backup/include/linux/netfilter/nf_conntrack_common.h l.new/include/linux/netfilter/nf_conntrack_common.h --- l.backup/include/linux/netfilter/nf_conntrack_common.h 2008-01-17 14:44:40.000000000 +0200 +++ l.new/include/linux/netfilter/nf_conntrack_common.h 2008-01-19 12:44:38.000000000 +0200 @@ -73,6 +73,14 @@ /* Connection has fixed timeout. */ IPS_FIXED_TIMEOUT_BIT = 10, IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), + + /* Retransmit bit. */ + IPS_RETRANSMIT_BIT = 11, + IPS_RETRANSMIT = (1 << IPS_RETRANSMIT_BIT), + + /* Not-Retransmit bit. */ + IPS_NOT_RETRANSMIT_BIT = 12, + IPS_NOT_RETRANSMIT = (1 << IPS_NOT_RETRANSMIT_BIT), }; /* Connection tracking event bits */ diff -ruN l.backup/include/linux/skbuff.h l.new/include/linux/skbuff.h --- l.backup/include/linux/skbuff.h 2008-01-15 19:29:21.000000000 +0200 +++ l.new/include/linux/skbuff.h 2008-01-19 14:40:51.000000000 +0200 @@ -288,6 +288,10 @@ fclone:2, ipvs_property:1, nf_trace:1; +#ifdef CONFIG_NF_CONNTRACK_RETRANS + __u8 retransmit:2; + __u8 _round:1; +#endif __be16 protocol; void (*destructor)(struct sk_buff *skb); diff -ruN l.backup/net/netfilter/Kconfig l.new/net/netfilter/Kconfig --- l.backup/net/netfilter/Kconfig 2007-10-09 23:31:38.000000000 +0300 +++ l.new/net/netfilter/Kconfig 2008-01-19 12:33:49.000000000 +0200 @@ -65,6 +65,13 @@ of packets, but this mark value is kept in the conntrack session instead of the individual packets. +config NF_CONNTRACK_RETRANS + bool "Retransmission tracking (for Precise Software Pacer)" + depends on NF_CONNTRACK + help + If this option is enabled, the connection tracking code + will track "retransmitted" flag for sch_psp. + config NF_CONNTRACK_SECMARK bool 'Connection tracking security mark support' depends on NF_CONNTRACK && NETWORK_SECMARK diff -ruN l.backup/net/netfilter/nf_conntrack_core.c l.new/net/netfilter/nf_conntrack_core.c --- l.backup/net/netfilter/nf_conntrack_core.c 2007-10-09 23:31:38.000000000 +0300 +++ l.new/net/netfilter/nf_conntrack_core.c 2008-01-19 12:46:47.000000000 +0200 @@ -590,6 +590,10 @@ struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; +#ifdef CONFIG_NF_CONNTRACK_RETRANS + skb->retransmit=0; +#endif + if (!nf_ct_get_tuple(skb, skb_network_offset(skb), dataoff, l3num, protonum, &tuple, l3proto, l4proto)) { @@ -628,6 +632,16 @@ } *set_reply = 0; } +#ifdef CONFIG_NF_CONNTRACK_RETRANS + if(test_bit(IPS_NOT_RETRANSMIT_BIT, &ct->status)){ + clear_bit(IPS_NOT_RETRANSMIT_BIT, &ct->status); + skb->retransmit=2; + } + if(test_bit(IPS_RETRANSMIT_BIT, &ct->status)){ + clear_bit(IPS_RETRANSMIT_BIT, &ct->status); + skb->retransmit=1; + } +#endif skb->nfct = &ct->ct_general; skb->nfctinfo = *ctinfo; return ct; diff -ruN l.backup/net/netfilter/nf_conntrack_proto_gre.c l.new/net/netfilter/nf_conntrack_proto_gre.c --- l.backup/net/netfilter/nf_conntrack_proto_gre.c 2007-10-09 23:31:38.000000000 +0300 +++ l.new/net/netfilter/nf_conntrack_proto_gre.c 2008-01-19 12:43:52.000000000 +0200 @@ -98,9 +98,14 @@ if (*kmp) { /* check whether it's a retransmission */ list_for_each_entry(km, &gre_keymap_list, list) { - if (gre_key_cmpfn(km, t) && km == *kmp) + if (gre_key_cmpfn(km, t) && km == *kmp) { +#ifdef CONFIG_NF_CONNTRACK_RETRANS + set_bit(IPS_RETRANSMIT_BIT, &ct->status); +#endif return 0; + } } + set_bit(IPS_NOT_RETRANSMIT_BIT, &ct->status); pr_debug("trying to override keymap_%s for ct %p\n", dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); return -EEXIST; diff -ruN l.backup/net/netfilter/nf_conntrack_proto_tcp.c l.new/net/netfilter/nf_conntrack_proto_tcp.c --- l.backup/net/netfilter/nf_conntrack_proto_tcp.c 2008-01-15 19:29:21.000000000 +0200 +++ l.new/net/netfilter/nf_conntrack_proto_tcp.c 2008-01-19 12:53:13.000000000 +0200 @@ -651,6 +651,26 @@ /* * Check retransmissions. */ +#ifdef CONFIG_NF_CONNTRACK_RETRANS + if (state->last_dir == dir + && state->last_seq == seq + && state->last_ack == ack + && state->last_end == end + && state->last_win == win) { + set_bit(IPS_RETRANSMIT_BIT, &ct->status); + if (index == TCP_ACK_SET) state->retrans++; + }else { + set_bit(IPS_NOT_RETRANSMIT_BIT, &ct->status); + if (index == TCP_ACK_SET) { + state->last_dir = dir; + state->last_seq = seq; + state->last_ack = ack; + state->last_end = end; + state->last_win = win; + state->retrans = 0; + } + } +#else if (index == TCP_ACK_SET) { if (state->last_dir == dir && state->last_seq == seq @@ -667,6 +687,7 @@ state->retrans = 0; } } +#endif res = 1; } else { res = 0; @@ -830,6 +851,23 @@ new_state = tcp_conntracks[dir][index][old_state]; tuple = &conntrack->tuplehash[dir].tuple; +#ifdef CONFIG_NF_CONNTRACK_RETRANS + if(new_state == old_state){ + switch (new_state) { + case TCP_CONNTRACK_SYN_SENT: + case TCP_CONNTRACK_LAST_ACK: + case TCP_CONNTRACK_TIME_WAIT: + case TCP_CONNTRACK_SYN_RECV:{ + set_bit(IPS_RETRANSMIT_BIT, &conntrack->status); + break; + } + default: + set_bit(IPS_NOT_RETRANSMIT_BIT, &conntrack->status); + break; + } + }else set_bit(IPS_NOT_RETRANSMIT_BIT, &conntrack->status); +#endif + switch (new_state) { case TCP_CONNTRACK_SYN_SENT: if (old_state < TCP_CONNTRACK_TIME_WAIT)