├── .gitignore ├── LICENSE ├── README.md ├── backup ├── L2DCT │ ├── lldct-test.tcl │ ├── lldct.py │ ├── tcp.cc │ └── tcp.h ├── mixedflow │ ├── CDF_dctcp_1.txt │ ├── CDF_dctcp_2.txt │ ├── CDF_dctcp_3.txt │ ├── Karuna │ │ ├── Makefile │ │ ├── flow.c │ │ ├── flow.h │ │ ├── main.c │ │ ├── network.c │ │ ├── network.h │ │ ├── params.c │ │ └── params.h │ ├── MCP │ │ ├── Makefile │ │ ├── flow.c │ │ ├── flow.h │ │ ├── main.c │ │ ├── network.c │ │ ├── network.h │ │ ├── params.c │ │ └── params.h │ ├── dynamic_flow.py │ ├── generator.py │ └── workload │ │ ├── client.c │ │ └── server.c ├── mlfq │ ├── CDF.tcl │ ├── CDF_dctcp.tcl │ ├── mlfq-test.tcl │ ├── mlfq.cc │ ├── mlfq.h │ ├── mlfq.py │ ├── result.py │ ├── result2.py │ ├── result3.py │ ├── run-list-dctcp-mlfq.pl │ ├── run-list-dctcp-pfabric.pl │ ├── run-list-vl2-mlfq.pl │ ├── run-list-vl2-pfabric.pl │ ├── spine_empirical_dctcp.tcl │ ├── spine_empirical_vl2.tcl │ └── tcp-common-opt.tcl └── pias │ ├── dynamic workload │ ├── CDF_dctcp.txt │ ├── CDF_vl2.txt │ ├── Makefile │ ├── client.c │ ├── datamining_5_dctcp_result.txt │ ├── datamining_5_pias_result.txt │ ├── datamining_5_sp_4queue_result.txt │ ├── datamining_5_sp_8queue_result.txt │ ├── datamining_5_sp_result.txt │ ├── datamining_5_trace.txt │ ├── datamining_6_dctcp_result.txt │ ├── datamining_6_pias_result.txt │ ├── datamining_6_sp_4queue_result.txt │ ├── datamining_6_sp_8queue_result.txt │ ├── datamining_6_sp_result.txt │ ├── datamining_6_trace.txt │ ├── datamining_7_dctcp_result.txt │ ├── datamining_7_pias_result.txt │ ├── datamining_7_sp_4queue_result.txt │ ├── datamining_7_sp_8queue_result.txt │ ├── datamining_7_sp_result.txt │ ├── datamining_7_trace.txt │ ├── datamining_8_dctcp_result.txt │ ├── datamining_8_pias_result.txt │ ├── datamining_8_sp_4queue_result.txt │ ├── datamining_8_sp_8queue_result.txt │ ├── datamining_8_sp_result.txt │ ├── datamining_8_trace.txt │ ├── dynamic_flow.py │ ├── generator.py │ ├── host.txt │ ├── memcached_dynamic_flow.py │ ├── result.py │ ├── server.c │ ├── static_flow.py │ ├── trace.py │ ├── websearch_5_dctcp_result.txt │ ├── websearch_5_pias_result.txt │ ├── websearch_5_sp_result.txt │ ├── websearch_5_trace.txt │ ├── websearch_6_dctcp_result.txt │ ├── websearch_6_pias_result.txt │ ├── websearch_6_sp_result.txt │ ├── websearch_6_trace.txt │ ├── websearch_7_dctcp_result.txt │ ├── websearch_7_pias_result.txt │ ├── websearch_7_sp_result.txt │ ├── websearch_7_trace.txt │ ├── websearch_8_dctcp_result.txt │ ├── websearch_8_pias_result.txt │ ├── websearch_8_sp_result.txt │ └── websearch_8_trace.txt │ ├── incast applications │ ├── client.c │ ├── readme.txt │ └── server.c │ ├── memcached │ ├── import.py │ ├── query.c │ ├── query.py │ └── test.py │ ├── pias │ ├── Makefile │ ├── flow.h │ ├── hash.h │ ├── network.h │ ├── pias.c │ └── prio.h │ ├── pias2 │ ├── Makefile │ ├── flow.h │ ├── hash.h │ ├── network.h │ ├── params.h │ ├── pias.c │ └── prio.h │ └── sp │ ├── Makefile │ ├── queue.h │ └── sp.c ├── pias3 ├── Makefile ├── flow.c ├── flow.h ├── main.c ├── network.c ├── network.h ├── params.c └── params.h ├── pias4 ├── Makefile ├── flow.c ├── flow.h ├── jprobe.c ├── jprobe.h ├── main.c ├── netfilter.c ├── netfilter.h ├── network.c ├── network.h ├── params.c └── params.h └── sch_pias ├── Makefile ├── main.c ├── params.c └── params.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Move to 2 | -------------------------------------------------------------------------------- /backup/L2DCT/lldct-test.tcl: -------------------------------------------------------------------------------- 1 | set node [lindex $argv 0] 2 | set data_size [lindex $argv 1] 3 | set enable_lldct [lindex $argv 2] 4 | 5 | set RTT 0.0001 6 | set DCTCP_K 65 7 | #RED or MLFQ 8 | set switchAlg MLFQ 9 | 10 | set tracedir tcp_flow 11 | set simulationTime 1.0 12 | set lineRate 10Gb 13 | 14 | set DCTCP_g 0.0625 15 | set ackRatio 1 16 | set pktSize 1460 17 | 18 | set ns [new Simulator] 19 | 20 | ################# Transport Options #################### 21 | Agent/TCP set ecn_ 1 22 | Agent/TCP set old_ecn_ 1 23 | Agent/TCP set packetSize_ $pktSize 24 | Agent/TCP set window_ 10000 25 | Agent/TCP set windowInit_ 10 26 | Agent/TCP set slow_start_restart_ false 27 | Agent/TCP set windowOption_ 0 28 | Agent/TCP set tcpTick_ 0.001 29 | Agent/TCP set minrto_ 0.001 30 | Agent/TCP set maxrto_ 2 31 | 32 | Agent/TCP/FullTcp set nodelay_ true; #Disable Nagle 33 | Agent/TCP/FullTcp set segsperack_ $ackRatio 34 | Agent/TCP/FullTcp set segsize_ $pktSize 35 | Agent/TCP/FullTcp set spa_thresh_ 0 36 | 37 | if {$ackRatio > 2} { 38 | Agent/TCP/FullTcp set spa_thresh_ [expr ($ackRatio - 1) * $pktSize] 39 | } 40 | 41 | ################ DCTCP Options ######################### 42 | Agent/TCP set ecnhat_ true 43 | Agent/TCPSink set ecnhat_ true 44 | Agent/TCP set ecnhat_g_ $DCTCP_g 45 | 46 | ################ LLDCT Options ######################### 47 | Agent/TCP set lldct_ $enable_lldct; #Enable LLDCT 48 | Agent/TCP set lldct_w_min_ 0.125 49 | Agent/TCP set lldct_w_max_ 2.5 50 | Agent/TCP set lldct_w_c_ 2.5 51 | 52 | ################ Queue Options ######################### 53 | Queue set limit_ 10000 54 | 55 | ################ Random Early Detection ################ 56 | Queue/RED set bytes_ false 57 | Queue/RED set queue_in_bytes_ true 58 | Queue/RED set mean_pktsize_ $pktSize 59 | Queue/RED set setbit_ true 60 | Queue/RED set gentle_ false 61 | Queue/RED set q_weight_ 1.0 62 | Queue/RED set mark_p_ 1.0 63 | Queue/RED set thresh_ $DCTCP_K 64 | Queue/RED set maxthresh_ $DCTCP_K 65 | 66 | ############# Multi-level Feedback Queue ############## 67 | Queue/MLFQ set queue_num_ 1 68 | Queue/MLFQ set thresh_ $DCTCP_K 69 | Queue/MLFQ set dequeue_marking_ 0 70 | Queue/MLFQ set mean_pktsize_ $pktSize 71 | 72 | #################### NS2 Trace ######################## 73 | set mytracefile [open mytracefile.tr w] 74 | $ns trace-all $mytracefile 75 | proc finish {} { 76 | global ns mytracefile 77 | $ns flush-trace 78 | close $mytracefile 79 | exit 0 80 | } 81 | 82 | ##################### Topology ######################### 83 | for {set i 0} {$i < $node} {incr i} { 84 | set n($i) [$ns node] 85 | } 86 | set nqueue [$ns node] 87 | set nclient [$ns node] 88 | 89 | for {set i 0} { $i < $node} {incr i} { 90 | $ns duplex-link $n($i) $nqueue $lineRate [expr $RTT/4] DropTail 91 | $ns duplex-link-op $n($i) $nqueue queuePos 0.25 92 | $ns queue-limit $n($i) $nqueue 10000; #End Host buffer size is very large 93 | $ns queue-limit $nqueue $n($i) 1000 94 | } 95 | 96 | $ns simplex-link $nqueue $nclient $lineRate [expr $RTT/4] $switchAlg 97 | $ns simplex-link $nclient $nqueue $lineRate [expr $RTT/4] DropTail 98 | $ns queue-limit $nqueue $nclient 1000 99 | $ns queue-limit $nclient $nqueue 1000 100 | 101 | ################## Long-live Flows ####################### 102 | for {set i 0} {$i < 2 } {incr i} { 103 | set tcp($i) [new Agent/TCP/FullTcp/Sack] 104 | set sink($i) [new Agent/TCP/FullTcp/Sack] 105 | $sink($i) listen 106 | 107 | $ns attach-agent $n($i) $tcp($i) 108 | $ns attach-agent $nclient $sink($i) 109 | 110 | $tcp($i) set fid_ [expr $i] 111 | $sink($i) set fid_ [expr $i] 112 | 113 | $ns connect $tcp($i) $sink($i) 114 | set ftp($i) [new Application/FTP] 115 | $ftp($i) attach-agent $tcp($i) 116 | $ftp($i) set type_ FTP 117 | $ns at 0.1 "$ftp($i) start" 118 | $ns at $simulationTime "$ftp($i) stop" 119 | } 120 | 121 | ################## Short Flows ####################### 122 | for {set i 2} {$i < $node} {incr i} { 123 | set tcp($i) [new Agent/TCP/FullTcp/Sack] 124 | set sink($i) [new Agent/TCP/FullTcp/Sack] 125 | $sink($i) listen 126 | 127 | $ns attach-agent $n($i) $tcp($i) 128 | $ns attach-agent $nclient $sink($i) 129 | 130 | #Record TCP logs 131 | $tcp($i) attach [open ./$tracedir/$i.tr w] 132 | $tcp($i) set bugFix_ false 133 | $tcp($i) trace cwnd_ 134 | $tcp($i) trace ack_ 135 | $tcp($i) trace ssthresh_ 136 | $tcp($i) trace nrexmit_ 137 | $tcp($i) trace nrexmitpack_ 138 | $tcp($i) trace nrexmitbytes_ 139 | $tcp($i) trace ncwndcuts_ 140 | $tcp($i) trace ncwndcuts1_ 141 | $tcp($i) trace dupacks_ 142 | 143 | $tcp($i) set fid_ [expr $i] 144 | $sink($i) set fid_ [expr $i] 145 | 146 | $ns connect $tcp($i) $sink($i) 147 | set ftp($i) [new Application/FTP] 148 | $ftp($i) attach-agent $tcp($i) 149 | $ftp($i) set type_ FTP 150 | $ns at [expr 0.2+0.002*$i] "$ftp($i) send $data_size" 151 | } 152 | 153 | $ns at $simulationTime "finish" 154 | $ns run 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /backup/L2DCT/lldct.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | 5 | #This function is to print usage of this script 6 | def usage(): 7 | sys.stderr.write('lldct.py [nodes] [data] [enable LLDCT]\n') 8 | 9 | #This function is to calculate FCT for a TCP flow 10 | def fct(file): 11 | fp = open(file) 12 | start='' 13 | end='' 14 | while True: 15 | line=fp.readline() 16 | if not line: 17 | break 18 | if len(start)==0 and not '0.00000' in line and 'cwnd' in line: 19 | start=line 20 | if len(start)>0: 21 | end=line 22 | fp.close() 23 | starttime=start.split()[0] 24 | endtime=end.split()[0] 25 | return float(endtime)-float(starttime) 26 | 27 | if len(sys.argv)==4: 28 | ns_path='/home/wei/ns-allinone-2.34/ns-2.34/ns' 29 | tcl_path='/home/wei/lldct/lldct-test.tcl' 30 | nodes=sys.argv[1] 31 | data=sys.argv[2] 32 | enable=sys.argv[3] 33 | os.system('rm ./tcp_flow -r\n') 34 | os.system('mkdir tcp_flow') 35 | cmd=ns_path+' '+tcl_path+' '+nodes+' '+data+' '+enable 36 | os.system(cmd) 37 | 38 | fcts=0.0 39 | flows=0 40 | #Get FCT results 41 | for file in os.listdir("./tcp_flow"): 42 | fcts=fcts+fct('./tcp_flow/'+file) 43 | flows=flows+1 44 | print fcts/flows 45 | 46 | else: 47 | usage() 48 | -------------------------------------------------------------------------------- /backup/mixedflow/CDF_dctcp_1.txt: -------------------------------------------------------------------------------- 1 | 6 0 2 | 6 0.152 3 | 13 0.212 4 | 19 0.303 5 | 33 0.455 6 | 53 0.515 7 | 133 0.636 8 | 667 0.91 9 | 1333 0.97 10 | 3333 0.97 11 | 6667 1 12 | -------------------------------------------------------------------------------- /backup/mixedflow/CDF_dctcp_2.txt: -------------------------------------------------------------------------------- 1 | 6 0 2 | 6 0.167 3 | 13 0.233 4 | 19 0.4 5 | 33 0.433 6 | 53 0.633 7 | 133 0.667 8 | 667 0.667 9 | 1333 0.8 10 | 3333 0.933 11 | 6667 0.967 12 | 20000 1 -------------------------------------------------------------------------------- /backup/mixedflow/CDF_dctcp_3.txt: -------------------------------------------------------------------------------- 1 | 6 0 2 | 6 0.135 3 | 13 0.162 4 | 19 0.216 5 | 33 0.324 6 | 53 0.459 7 | 133 0.514 8 | 667 0.541 9 | 1333 0.649 10 | 3333 0.811 11 | 6667 0.946 12 | 20000 1 -------------------------------------------------------------------------------- /backup/mixedflow/Karuna/Makefile: -------------------------------------------------------------------------------- 1 | obj-m +=karuna.o 2 | 3 | karuna-y :=params.o flow.o network.o main.o 4 | 5 | all: 6 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 7 | 8 | clean: 9 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 10 | -------------------------------------------------------------------------------- /backup/mixedflow/Karuna/flow.h: -------------------------------------------------------------------------------- 1 | #ifndef __FLOW_H__ 2 | #define __FLOW_H__ 3 | 4 | #include 5 | #include 6 | 7 | /*Define structure of information for a TCP flow 8 | *latest_update_time: the last time when we observe an outgoing packet (from local side to remote side) 9 | *latest_timeout_time: the last time when we observe an TCP timeout 10 | *latest_timeout_seq: the sequence number for last TCP timeout 11 | *latest_seq: the largest (latest) sequence number for outoging traffic 12 | *latest_ack: the largest (latest) ACK number for outoging traffic 13 | *bytes_sent: bytes sent of outgoing traffic 14 | *bytes_total: total size of outgoing traffic 15 | *timeouts: the number of consecutive timeouts experienced by outgoing traffic 16 | *is_size_known: shall we know size of this flow? 17 | *is_deadline_known: shall we know deadline of this flow? 18 | */ 19 | 20 | struct Karuna_Flow_Info 21 | { 22 | ktime_t latest_update_time; 23 | ktime_t latest_timeout_time; 24 | u32 latest_timeout_seq; 25 | u32 latest_seq; 26 | u32 latest_ack; 27 | u32 bytes_sent; 28 | u32 bytes_total; 29 | u16 timeouts; 30 | bool is_size_known; //If is_size_known is 1, it is type 2 31 | bool is_deadline_known; //If is_deadline_known is 1, it's type 1 32 | }; 33 | 34 | //Define structure of a TCP flow 35 | //A TCP Flow is defined by 4-tuple and its related information 36 | struct Karuna_Flow 37 | { 38 | u32 local_ip; //Local IP address 39 | u32 remote_ip; //Remote IP address 40 | u16 local_port; //Local TCP port 41 | u16 remote_port; //Remote TCP port 42 | struct Karuna_Flow_Info info; //Information for this flow 43 | }; 44 | 45 | //Link Node of Flow 46 | struct Karuna_Flow_Node 47 | { 48 | struct Karuna_Flow f; //structure of Flow 49 | struct Karuna_Flow_Node* next; //pointer to next node 50 | }; 51 | 52 | //Link List of Flows 53 | struct Karuna_Flow_List 54 | { 55 | struct Karuna_Flow_Node* head; //pointer to head node of this link list 56 | unsigned int len; //current length of this list (max: QUEUE_SIZE) 57 | }; 58 | 59 | //Hash Table of Flows 60 | struct Karuna_Flow_Table 61 | { 62 | struct Karuna_Flow_List* table; //many FlowList (HASH_RANGE) 63 | unsigned int size; //total number of nodes in this table 64 | spinlock_t tableLock; 65 | }; 66 | 67 | //Print functions 68 | void Karuna_Print_Flow(struct Karuna_Flow* f, int type); 69 | void Karuna_Print_Node(struct Karuna_Flow_Node* fn); 70 | void Karuna_Print_List(struct Karuna_Flow_List* fl); 71 | void Karuna_Print_Table(struct Karuna_Flow_Table* ft); 72 | 73 | static inline unsigned int Karuna_Hash(struct Karuna_Flow* f); 74 | static inline bool Karuna_Equal(struct Karuna_Flow* f1,struct Karuna_Flow* f2); 75 | 76 | //Initialization functions 77 | void Karuna_Init_Info(struct Karuna_Flow_Info* info); 78 | void Karuna_Init_Flow(struct Karuna_Flow* f); 79 | void Karuna_Init_Node(struct Karuna_Flow_Node* fn); 80 | void Karuna_Init_List(struct Karuna_Flow_List* fl); 81 | void Karuna_Init_Table(struct Karuna_Flow_Table* ft); 82 | 83 | //Insert functions 84 | unsigned int Karuna_Insert_List(struct Karuna_Flow_List* fl, struct Karuna_Flow* f, int flags); 85 | unsigned int Karuna_Insert_Table(struct Karuna_Flow_Table* ft,struct Karuna_Flow* f, int flags); 86 | 87 | //Search functions 88 | struct Karuna_Flow_Info* Karuna_Search_List(struct Karuna_Flow_List* fl, struct Karuna_Flow* f); 89 | struct Karuna_Flow_Info* Karuna_Search_Table(struct Karuna_Flow_Table* ft, struct Karuna_Flow* f); 90 | 91 | //Delete functions 92 | u32 Karuna_Delete_List(struct Karuna_Flow_List* fl, struct Karuna_Flow* f, u8* type); 93 | u32 Karuna_Delete_Table(struct Karuna_Flow_Table* ft,struct Karuna_Flow* f, u8* type); 94 | 95 | //Empty functions 96 | void Karuna_Empty_List(struct Karuna_Flow_List* fl); 97 | void Karuna_Empty_Table(struct Karuna_Flow_Table* ft); 98 | 99 | #endif -------------------------------------------------------------------------------- /backup/mixedflow/Karuna/network.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "network.h" 6 | #include "params.h" 7 | 8 | //Return the larges threshold which is smaller than size 9 | inline u32 Karuna_smaller_threshold(u32 size) 10 | { 11 | if(size<=Karuna_AWARE_THRESHOLD_2) 12 | return Karuna_AWARE_THRESHOLD_1; 13 | else if(size<=Karuna_AWARE_THRESHOLD_3) 14 | return Karuna_AWARE_THRESHOLD_2; 15 | else if(size<=Karuna_AWARE_THRESHOLD_4) 16 | return Karuna_AWARE_THRESHOLD_3; 17 | else if(size<=Karuna_AWARE_THRESHOLD_5) 18 | return Karuna_AWARE_THRESHOLD_4; 19 | else if(size<=Karuna_AWARE_THRESHOLD_6) 20 | return Karuna_AWARE_THRESHOLD_5; 21 | else 22 | return Karuna_AWARE_THRESHOLD_6; 23 | } 24 | 25 | //type: deadline flow(0), non-deadline flow with priori knowledge of size(1), non-deadline flow without priori knowledge of size(2) 26 | //size: 0 for deadline flow, bytes_total/bytes_sent for non-deadline flow 27 | u8 Karuna_priority(u8 type, u32 size) 28 | { 29 | //Type 2 flows 30 | if(type==1) 31 | { 32 | if(size<=Karuna_AWARE_THRESHOLD_1) 33 | return PRIORITY_DSCP_2; 34 | else if(size<=Karuna_AWARE_THRESHOLD_2) 35 | return PRIORITY_DSCP_3; 36 | else if(size<=Karuna_AWARE_THRESHOLD_3) 37 | return PRIORITY_DSCP_4; 38 | else if(size<=Karuna_AWARE_THRESHOLD_4) 39 | return PRIORITY_DSCP_5; 40 | else if(size<=Karuna_AWARE_THRESHOLD_5) 41 | return PRIORITY_DSCP_6; 42 | else if(size<=Karuna_AWARE_THRESHOLD_6) 43 | return PRIORITY_DSCP_7; 44 | else 45 | return PRIORITY_DSCP_8; 46 | } 47 | //Type 3 flows 48 | else if(type==2) 49 | { 50 | if(size<=Karuna_AGNOSTIC_THRESHOLD_1) 51 | return PRIORITY_DSCP_2; 52 | else if(size<=Karuna_AGNOSTIC_THRESHOLD_2) 53 | return PRIORITY_DSCP_3; 54 | else if(size<=Karuna_AGNOSTIC_THRESHOLD_3) 55 | return PRIORITY_DSCP_4; 56 | else if(size<=Karuna_AGNOSTIC_THRESHOLD_4) 57 | return PRIORITY_DSCP_5; 58 | else if(size<=Karuna_AGNOSTIC_THRESHOLD_5) 59 | return PRIORITY_DSCP_6; 60 | else if(size<=Karuna_AGNOSTIC_THRESHOLD_6) 61 | return PRIORITY_DSCP_7; 62 | else 63 | return PRIORITY_DSCP_8; 64 | } 65 | else//type 0 or thers 66 | { 67 | return PRIORITY_DSCP_1; 68 | } 69 | } 70 | 71 | //mark DSCP and enable ECN 72 | inline void Karuna_enable_ecn_dscp(struct sk_buff *skb, u8 dscp) 73 | { 74 | if(skb_make_writable(skb,sizeof(struct iphdr))) 75 | { 76 | ipv4_change_dsfield(ip_hdr(skb), 0xff, (dscp<<2)|INET_ECN_ECT_0); 77 | } 78 | } 79 | 80 | //Maximum unsigned 32-bit integer value: 4294967295 81 | //Function: determine whether seq1 is larger than seq2 82 | //If Yes, return 1. Else, return 0. 83 | //We use a simple heuristic to handle wrapped TCP sequence number 84 | inline bool Karuna_is_seq_larger(u32 seq1, u32 seq2) 85 | { 86 | if(likely(seq1>seq2&&seq1-seq2<=4294900000)) 87 | return 1; 88 | else if(seq14294900000) 89 | return 1; 90 | else 91 | return 0; 92 | } 93 | 94 | inline u32 Karuna_seq_gap(u32 larger, u32 smaller) 95 | { 96 | if(likely(larger>=smaller)) 97 | return larger-smaller; 98 | else 99 | return 4294967295-(smaller-larger); 100 | } 101 | -------------------------------------------------------------------------------- /backup/mixedflow/Karuna/network.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETWORK_H__ 2 | #define __NETWORK_H__ 3 | 4 | #include 5 | #include 6 | 7 | //Based on the flow type (ddl/non-ddl with flow size/non-ddl w/o flow size) and size (bytes_total/bytes_sent), return DSCP value 8 | u8 Karuna_priority(u8 type, u32 size); 9 | //mark DSCP and enable ECN 10 | inline void Karuna_enable_ecn_dscp(struct sk_buff *skb, u8 dscp); 11 | //If seq1 is larger than seq2 12 | inline bool Karuna_is_seq_larger(u32 seq1, u32 seq2); 13 | inline u32 Karuna_seq_gap(u32 larger, u32 smaller); 14 | inline u32 Karuna_smaller_threshold(u32 size); 15 | 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /backup/mixedflow/Karuna/params.c: -------------------------------------------------------------------------------- 1 | #include "params.h" 2 | 3 | const unsigned int Karuna_HASH_RANGE=256; 4 | const unsigned int Karuna_LIST_SIZE=32; 5 | 6 | const u32 Karuna_MAX_FLOW_SIZE=4294967295; 7 | const unsigned int Karuna_RTO_MIN=8*1000; 8 | const unsigned int Karuna_TIMEOUT_THRESH=3; 9 | 10 | const u8 PRIORITY_DSCP_1=7; 11 | const u8 PRIORITY_DSCP_2=6; 12 | const u8 PRIORITY_DSCP_3=5; 13 | const u8 PRIORITY_DSCP_4=4; 14 | const u8 PRIORITY_DSCP_5=3; 15 | const u8 PRIORITY_DSCP_6=2; 16 | const u8 PRIORITY_DSCP_7=1; 17 | const u8 PRIORITY_DSCP_8=0; 18 | -------------------------------------------------------------------------------- /backup/mixedflow/Karuna/params.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARAMS_H__ 2 | #define __PARAMS_H__ 3 | 4 | #include 5 | 6 | //Hash range 7 | extern const unsigned int Karuna_HASH_RANGE; 8 | //Maximum size of a list 9 | extern const unsigned int Karuna_LIST_SIZE; 10 | 11 | extern const u32 Karuna_MAX_FLOW_SIZE; 12 | //RTOmin in us 13 | extern const unsigned int Karuna_RTO_MIN; 14 | extern const unsigned int Karuna_TIMEOUT_THRESH; 15 | 16 | //Thresholds for information-aware non-deadline (type 2) flows (Karuna_AWARE_THRESHOLD_1 is the smallest value) 17 | extern const u32 Karuna_AWARE_THRESHOLD_1; 18 | extern const u32 Karuna_AWARE_THRESHOLD_2; 19 | extern const u32 Karuna_AWARE_THRESHOLD_3; 20 | extern const u32 Karuna_AWARE_THRESHOLD_4; 21 | extern const u32 Karuna_AWARE_THRESHOLD_5; 22 | extern const u32 Karuna_AWARE_THRESHOLD_6; 23 | //extern const u32 Karuna_AWARE_THRESHOLD_7; 24 | 25 | //Thresholds for information-agnostic non-deadline (type 3) flows (Karuna_AGNOSTIC_THRESHOLD_1 is the smallest value) 26 | extern const u32 Karuna_AGNOSTIC_THRESHOLD_1; 27 | extern const u32 Karuna_AGNOSTIC_THRESHOLD_2; 28 | extern const u32 Karuna_AGNOSTIC_THRESHOLD_3; 29 | extern const u32 Karuna_AGNOSTIC_THRESHOLD_4; 30 | extern const u32 Karuna_AGNOSTIC_THRESHOLD_5; 31 | extern const u32 Karuna_AGNOSTIC_THRESHOLD_6; 32 | //extern const u32 Karuna_AGNOSTIC_THRESHOLD_7; 33 | 34 | //DSCP value for different priority queues (PRIORITY_DSCP_1 is for the highest priority) 35 | extern const u8 PRIORITY_DSCP_1; 36 | extern const u8 PRIORITY_DSCP_2; 37 | extern const u8 PRIORITY_DSCP_3; 38 | extern const u8 PRIORITY_DSCP_4; 39 | extern const u8 PRIORITY_DSCP_5; 40 | extern const u8 PRIORITY_DSCP_6; 41 | extern const u8 PRIORITY_DSCP_7; 42 | extern const u8 PRIORITY_DSCP_8; 43 | 44 | #endif -------------------------------------------------------------------------------- /backup/mixedflow/MCP/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += mcp.o 2 | 3 | mcp-y := params.o flow.o network.o main.o 4 | 5 | all: 6 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 7 | 8 | clean: 9 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 10 | -------------------------------------------------------------------------------- /backup/mixedflow/MCP/flow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "flow.h" 5 | #include "params.h" 6 | 7 | //Print a flow information 8 | //Type: Add(0) Delete(1) 9 | void MCP_Print_Flow(struct MCP_Flow* f, int type) 10 | { 11 | char local_ip[16]={0}; //Local IP address 12 | char remote_ip[16]={0}; //Remote IP address 13 | 14 | snprintf(local_ip, 16, "%pI4", &(f->local_ip)); 15 | snprintf(remote_ip, 16, "%pI4", &(f->remote_ip)); 16 | 17 | if(type==0) 18 | { 19 | printk(KERN_INFO "Insert a Flow record: %s:%hu to %s:%hu \n",local_ip,f->local_port,remote_ip,f->remote_port); 20 | } 21 | else if(type==1) 22 | { 23 | printk(KERN_INFO "Delete a Flow record: %s:%hu to %s:%hu \n",local_ip,f->local_port,remote_ip,f->remote_port); 24 | } 25 | else 26 | { 27 | printk(KERN_INFO "Flow record: %s:%hu to %s:%hu \n",local_ip,f->local_port,remote_ip,f->remote_port); 28 | } 29 | } 30 | 31 | //Print a FlowNode 32 | void MCP_Print_Node(struct MCP_Flow_Node* fn) 33 | { 34 | MCP_Print_Flow(&(fn->f),2); 35 | } 36 | 37 | //Print a FlowList 38 | void MCP_Print_List(struct MCP_Flow_List* fl) 39 | { 40 | struct MCP_Flow_Node* Ptr; 41 | for(Ptr=fl->head->next;Ptr!=NULL;Ptr=Ptr->next) 42 | { 43 | MCP_Print_Node(Ptr); 44 | } 45 | } 46 | 47 | //Print a FlowTable 48 | void MCP_Print_Table(struct MCP_Flow_Table* ft) 49 | { 50 | int i=0; 51 | printk(KERN_INFO "Current flow table:\n"); 52 | for(i=0;itable[i].len>0) 55 | { 56 | printk(KERN_INFO "FlowList %d\n",i); 57 | MCP_Print_List(&(ft->table[i])); 58 | } 59 | } 60 | printk(KERN_INFO "There are %u flows in total\n",ft->size); 61 | } 62 | 63 | //Hash function, calculate the flow should be inserted into which MCP_Flow_List 64 | unsigned int MCP_Hash(struct MCP_Flow* f) 65 | { 66 | //return a value in [0,HASH_RANGE-1] 67 | return ((f->local_ip/(256*256*256)+1)*(f->remote_ip/(256*256*256)+1)*(f->local_port+1)*(f->remote_port+1))%MCP_HASH_RANGE; 68 | } 69 | 70 | //Determine whether two Flows are equal 71 | // determines a flow 72 | unsigned int MCP_Equal(struct MCP_Flow* f1,struct MCP_Flow* f2) 73 | { 74 | return ((f1->local_ip==f2->local_ip) 75 | &&(f1->remote_ip==f2->remote_ip) 76 | &&(f1->local_port==f2->local_port) 77 | &&(f1->remote_port==f2->remote_port)); 78 | } 79 | 80 | //Initialize the info of a Flow 81 | void MCP_Init_Info(struct MCP_Flow_Info* info) 82 | { 83 | //We need to initialize 11 variables in total 84 | info->latest_seq=0; 85 | info->bytes_received=0; 86 | info->bytes_total=0; 87 | info->current_window=0; 88 | info->target_window=0; 89 | info->scale=0; 90 | info->srtt=0; 91 | info->bytes_rtt_received=0; 92 | info->bytes_rtt_received_ecn=0; 93 | info->deadline=ktime_set(0,0); 94 | info->last_update=ktime_set(0,0); 95 | } 96 | 97 | //Initialize a Flow 98 | void MCP_Init_Flow(struct MCP_Flow* f) 99 | { 100 | f->local_ip=0; 101 | f->remote_ip=0; 102 | f->local_port=0; 103 | f->remote_port=0; 104 | 105 | //Initialize the Info of this Flow 106 | MCP_Init_Info(&(f->info)); 107 | } 108 | 109 | //Initialize a FlowNode 110 | void MCP_Init_Node(struct MCP_Flow_Node* fn) 111 | { 112 | //Initialize next pointer as null 113 | fn->next=NULL; 114 | //Initialize a flow structure 115 | MCP_Init_Flow(&(fn->f)); 116 | } 117 | 118 | //Initialize a FlowList 119 | void MCP_Init_List(struct MCP_Flow_List* fl) 120 | { 121 | struct MCP_Flow_Node* buf=NULL; 122 | //No node in current list 123 | fl->len=0; 124 | //We use vmalloc here since this function is ususally referenced when we inset the module 125 | buf=vmalloc(sizeof(struct MCP_Flow_Node)); 126 | if(buf==NULL) 127 | { 128 | printk(KERN_INFO "Vmalloc error in MCP_Init_List\n"); 129 | } 130 | else 131 | { 132 | fl->head=buf; 133 | MCP_Init_Node(fl->head); 134 | } 135 | } 136 | 137 | //Initialize a FlowTable 138 | void MCP_Init_Table(struct MCP_Flow_Table* ft) 139 | { 140 | int i=0; 141 | struct MCP_Flow_List* buf=NULL; 142 | 143 | //allocate space for FlowLists 144 | buf=vmalloc(MCP_HASH_RANGE*sizeof(struct MCP_Flow_List)); 145 | if(buf==NULL) 146 | { 147 | printk(KERN_INFO "Vmalloc error in MCP_Init_Table\n"); 148 | } 149 | else 150 | { 151 | ft->table=buf; 152 | //Initialize each FlowList 153 | for(i=0;itable[i])); 156 | } 157 | } 158 | //No nodes in current table 159 | ft->size=0; 160 | //Init spinlock 161 | spin_lock_init(&(ft->tableLock)); 162 | } 163 | 164 | //Insert a Flow into a FlowList and return 1 if it succeeds 165 | unsigned int MCP_Insert_List(struct MCP_Flow_List* fl, struct MCP_Flow* f, int flags) 166 | { 167 | if(fl->len>=MCP_LIST_SIZE) 168 | { 169 | printk(KERN_INFO "MCP_Insert_List: No enough space in this link list\n"); 170 | return 0; 171 | } 172 | else 173 | { 174 | struct MCP_Flow_Node* tmp=fl->head; 175 | struct MCP_Flow_Node* buf=NULL; 176 | 177 | //Come to the tail of this FlowList 178 | while(1) 179 | { 180 | //If pointer to next node is NULL, we find the tail of this FlowList. Here we can insert our new Flow 181 | if(tmp->next==NULL) 182 | { 183 | //Allocate memory. The 'flags' is determined by context 184 | buf=kmalloc(sizeof(struct MCP_Flow_Node),flags); 185 | if(buf==NULL) //Fail to allocate memory 186 | { 187 | printk(KERN_INFO "MCP_Insert_List: Kmalloc error\n"); 188 | return 0; 189 | } 190 | else 191 | { 192 | tmp->next=buf; 193 | //Copy data for this new FlowNode 194 | tmp->next->f=*f; 195 | //Pointer to next FlowNode is NUll 196 | tmp->next->next=NULL; 197 | //Increase length of FlowList 198 | fl->len++; 199 | return 1; 200 | } 201 | } 202 | //If the rule of next node is the same as our inserted flow, we just finish the insert 203 | else if(MCP_Equal(&(tmp->next->f),f)==1) 204 | { 205 | printk(KERN_INFO "MCP_Insert_List: Equal Flow\n"); 206 | return 0; 207 | } 208 | else //Move to next FlowNode 209 | { 210 | tmp=tmp->next; 211 | } 212 | } 213 | return 0; 214 | } 215 | } 216 | 217 | //Insert a flow to FlowTable and return 1 if it succeeds 218 | unsigned int MCP_Insert_Table(struct MCP_Flow_Table* ft,struct MCP_Flow* f, int flags) 219 | { 220 | unsigned int result=0; 221 | unsigned int index=MCP_Hash(f); 222 | 223 | //printk(KERN_INFO "Insert to link list %d\n",index); 224 | //Insert Flow to appropriate FlowList based on Hash value 225 | result=MCP_Insert_List(&(ft->table[index]),f,flags); 226 | //Increase the size of FlowTable 227 | ft->size+=result; 228 | 229 | return result; 230 | } 231 | 232 | //Search and return the pointer of information for a given flow in a FlowList 233 | struct MCP_Flow_Info* MCP_Search_List(struct MCP_Flow_List* fl, struct MCP_Flow* f) 234 | { 235 | //The length of FlowList is 0 236 | if(fl->len==0) 237 | { 238 | return NULL; 239 | } 240 | else 241 | { 242 | struct MCP_Flow_Node* tmp=fl->head; 243 | //Find the Flow in this FlowList 244 | while(1) 245 | { 246 | //If pointer to next node is NULL, we find the tail of this FlowList, no more FlowNodes to search 247 | if(tmp->next==NULL) 248 | { 249 | return NULL; 250 | } 251 | //Find matching flow (matching FlowNode is tmp->next rather than tmp) 252 | else if(MCP_Equal(&(tmp->next->f),f)==1) 253 | { 254 | //return the info of this Flow 255 | return &(tmp->next->f.info); 256 | } 257 | else 258 | { 259 | //Move to next FlowNode 260 | tmp=tmp->next; 261 | } 262 | } 263 | } 264 | return NULL; 265 | } 266 | 267 | //Search the information for a given Flow in a FlowTable 268 | struct MCP_Flow_Info* MCP_Search_Table(struct MCP_Flow_Table* ft, struct MCP_Flow* f) 269 | { 270 | unsigned int index=0; 271 | index=MCP_Hash(f); 272 | return MCP_Search_List(&(ft->table[index]),f); 273 | } 274 | 275 | //Delete a Flow from FlowList and return the window (>0) of this flow if it succeeds 276 | u16 MCP_Delete_List(struct MCP_Flow_List* fl, struct MCP_Flow* f) 277 | { 278 | u16 result=0; 279 | //No node in current FlowList 280 | if(fl->len==0) 281 | { 282 | //printk(KERN_INFO "No node in current list\n"); 283 | return 0; 284 | } 285 | else 286 | { 287 | struct MCP_Flow_Node* tmp=fl->head; 288 | struct MCP_Flow_Node* s=NULL; 289 | 290 | while(1) 291 | { 292 | //If pointer to next node is NULL, we find the tail of this FlowList, no more FlowNodes, return 0 293 | if(tmp->next==NULL) 294 | { 295 | //printk(KERN_INFO "There are %d flows in this list\n",fl->len); 296 | return 0; 297 | } 298 | //Find the matching flow (matching FlowNode is tmp->next rather than tmp), delete flow and return 299 | else if(MCP_Equal(&(tmp->next->f),f)==1) 300 | { 301 | //Get rwnd 302 | result=tmp->next->f.info.current_window; 303 | s=tmp->next; 304 | //Print_Flow(&(tmp->next->f),2); 305 | tmp->next=s->next; 306 | //Delete matching FlowNode from this FlowList 307 | kfree(s); 308 | //Reduce the length of this FlowList by one 309 | fl->len--; 310 | //printk(KERN_INFO "Delete a flow record\n"); 311 | return result; 312 | } 313 | //Unmatch 314 | else 315 | { 316 | //Move to next FlowNode 317 | tmp=tmp->next; 318 | } 319 | } 320 | return 0; 321 | } 322 | } 323 | 324 | //Delete a Flow from FlowTable and return the window (>0) of this flow if it succeeds 325 | u16 MCP_Delete_Table(struct MCP_Flow_Table* ft,struct MCP_Flow* f) 326 | { 327 | u16 result=0; 328 | unsigned int index=0; 329 | index=MCP_Hash(f); 330 | //printk(KERN_INFO "Delete from link list %d\n",index); 331 | //Delete Flow from appropriate FlowList based on Hash value 332 | result=MCP_Delete_List(&(ft->table[index]),f); 333 | //Reduce the size of FlowTable by one 334 | if(result>0) 335 | ft->size-=1; 336 | //printk(KERN_INFO "Delete %d \n",result); 337 | return result; 338 | } 339 | 340 | void MCP_Empty_List(struct MCP_Flow_List* fl) 341 | { 342 | struct MCP_Flow_Node* NextNode; 343 | struct MCP_Flow_Node* Ptr; 344 | for(Ptr=fl->head;Ptr!=NULL;Ptr=NextNode) 345 | { 346 | NextNode=Ptr->next; 347 | //Actually, we delete the fl->head in the first iteration 348 | //For fl->head, we use vfree. For other nodes, we use kfree 349 | if(Ptr==fl->head) 350 | vfree(Ptr); 351 | else 352 | kfree(Ptr); 353 | } 354 | } 355 | 356 | void MCP_Empty_Table(struct MCP_Flow_Table* ft) 357 | { 358 | int i=0; 359 | for(i=0;itable[i])); 362 | } 363 | vfree(ft->table); 364 | } 365 | 366 | -------------------------------------------------------------------------------- /backup/mixedflow/MCP/flow.h: -------------------------------------------------------------------------------- 1 | #ifndef __FLOW_H__ 2 | #define __FLOW_H__ 3 | 4 | #include 5 | #include 6 | 7 | /*Define structure of information for a TCP flow 8 | * latest_seq: the latest sequence number of this flow 9 | * bytes_received: the number of bytes that have been received (should exclude retranmission) 10 | * bytes_total: the total number of bytes of this flow 11 | * target_window: the target window size (MSS) of this flow. This variable is updated each RTT. 12 | * current_window: current window size (MSS) of this flow 13 | * scale: TCP window scale 14 | * srtt: the smoothed RTT value (us) 15 | * bytes_received_rtt: the number of bytes that have been received in this RTT 16 | * bytes_received_ecn_rtt: he number of bytes that have been received and marked with ECN in this RTT 17 | * deadline: deadline time 18 | * last_update: last update time of this flow 19 | */ 20 | struct MCP_Flow_Info 21 | { 22 | u32 latest_seq; 23 | u32 bytes_received; 24 | u32 bytes_total; 25 | u16 current_window; 26 | u16 target_window; 27 | u16 scale; 28 | u32 srtt; 29 | u32 bytes_rtt_received; 30 | u32 bytes_rtt_received_ecn; 31 | ktime_t deadline; 32 | ktime_t last_update; 33 | }; 34 | 35 | //Define structure of a TCP flow 36 | //A TCP Flow is defined by 4-tuple and its related information 37 | struct MCP_Flow 38 | { 39 | u32 local_ip; //Local IP address 40 | u32 remote_ip; //Remote IP address 41 | u16 local_port; //Local TCP port 42 | u16 remote_port; //Remote TCP port 43 | struct MCP_Flow_Info info; //Information for this flow 44 | }; 45 | 46 | //Link Node of Flow 47 | struct MCP_Flow_Node 48 | { 49 | struct MCP_Flow f; //structure of Flow 50 | struct MCP_Flow_Node* next; //pointer to next node 51 | }; 52 | 53 | //Link List of Flows 54 | struct MCP_Flow_List 55 | { 56 | struct MCP_Flow_Node* head; //pointer to head node of this link list 57 | unsigned int len; //current length of this list (max: QUEUE_SIZE) 58 | }; 59 | 60 | //Hash Table of Flows 61 | struct MCP_Flow_Table 62 | { 63 | struct MCP_Flow_List* table; //many FlowList (HASH_RANGE) 64 | unsigned int size; //total number of nodes in this table 65 | spinlock_t tableLock; 66 | }; 67 | 68 | //Print functions 69 | void MCP_Print_Flow(struct MCP_Flow* f, int type); 70 | void MCP_Print_Node(struct MCP_Flow_Node* fn); 71 | void MCP_Print_List(struct MCP_Flow_List* fl); 72 | void MCP_Print_Table(struct MCP_Flow_Table* ft); 73 | 74 | unsigned int MCP_Hash(struct MCP_Flow* f); 75 | unsigned int MCP_Equal(struct MCP_Flow* f1,struct MCP_Flow* f2); 76 | 77 | //Initialization functions 78 | void MCP_Init_Info(struct MCP_Flow_Info* info); 79 | void MCP_Init_Flow(struct MCP_Flow* f); 80 | void MCP_Init_Node(struct MCP_Flow_Node* fn); 81 | void MCP_Init_List(struct MCP_Flow_List* fl); 82 | void MCP_Init_Table(struct MCP_Flow_Table* ft); 83 | 84 | //Insert functions 85 | unsigned int MCP_Insert_List(struct MCP_Flow_List* fl, struct MCP_Flow* f, int flags); 86 | unsigned int MCP_Insert_Table(struct MCP_Flow_Table* ft,struct MCP_Flow* f, int flags); 87 | 88 | //Search functions 89 | struct MCP_Flow_Info* MCP_Search_List(struct MCP_Flow_List* fl, struct MCP_Flow* f); 90 | struct MCP_Flow_Info* MCP_Search_Table(struct MCP_Flow_Table* ft, struct MCP_Flow* f); 91 | 92 | //Delete functions 93 | u16 MCP_Delete_List(struct MCP_Flow_List* fl, struct MCP_Flow* f); 94 | u16 MCP_Delete_Table(struct MCP_Flow_Table* ft,struct MCP_Flow* f); 95 | 96 | //Empty functions 97 | void MCP_Empty_List(struct MCP_Flow_List* fl); 98 | void MCP_Empty_Table(struct MCP_Flow_Table* ft); 99 | 100 | #endif -------------------------------------------------------------------------------- /backup/mixedflow/MCP/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "flow.h" 16 | #include "network.h" 17 | #include "params.h" 18 | 19 | MODULE_LICENSE("GPL"); 20 | MODULE_AUTHOR("BAI Wei baiwei0427@gmail.com"); 21 | MODULE_VERSION("1.0"); 22 | MODULE_DESCRIPTION("Linux kernel module for MCP"); 23 | 24 | char *param_dev=NULL; 25 | MODULE_PARM_DESC(param_dev, "Interface to operate MCP"); 26 | module_param(param_dev, charp, 0); 27 | 28 | static struct MCP_Flow_Table ft; 29 | 30 | //The hook for outgoing packets at POSTROUTING 31 | static struct nf_hook_ops MCP_nf_hook_out; 32 | //The hook for incoming packets at PREROUTING 33 | static struct nf_hook_ops MCP_nf_hook_in; 34 | 35 | //POSTROUTING for outgoing packets 36 | static unsigned int MCP_hook_func_out(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 37 | { 38 | struct iphdr *iph=NULL; //IP header structure 39 | struct tcphdr *tcph=NULL; //TCP header structure 40 | struct MCP_Flow f; 41 | unsigned long flags; 42 | struct MCP_Flow_Info* infoPtr=NULL; 43 | u32 deadline=0; 44 | u32 delta_in_us=0; 45 | u32 window_bytes=0; 46 | ktime_t now=ktime_get(); 47 | 48 | if(!out) 49 | return NF_ACCEPT; 50 | 51 | if(strncmp(out->name,param_dev,IFNAMSIZ)!=0) 52 | return NF_ACCEPT; 53 | 54 | iph=(struct iphdr *)skb_network_header(skb); 55 | 56 | //The packet is not ip packet (e.g. ARP or others) 57 | if (unlikely(iph==NULL)) 58 | return NF_ACCEPT; 59 | 60 | //MCP packets 61 | if(iph->protocol==IPPROTO_TCP&&skb->mark>0) 62 | { 63 | tcph=(struct tcphdr *)((__u32 *)iph+iph->ihl); 64 | f.local_ip=iph->saddr; 65 | f.remote_ip=iph->daddr; 66 | f.local_port=ntohs(tcph->source); 67 | f.remote_port=ntohs(tcph->dest); 68 | MCP_Init_Info(&(f.info)); 69 | //It's a new MCP flow 70 | if(tcph->syn) 71 | { 72 | //Get data size (KB to B) 73 | f.info.bytes_total=((skb->mark)&0x000fffff)<<10; 74 | f.info.last_update=now; 75 | //Get deadline time (ms to ns) 76 | deadline=(skb->mark)&0xfff00000; 77 | //Potential deviations 78 | if(deadline>6*(MCP_INIT_RTT<<10)) 79 | deadline-=6*(MCP_INIT_RTT<<10); 80 | f.info.deadline.tv64=now.tv64+deadline; 81 | f.info.scale=(1<>10)/MCP_TCP_PAYLOAD_LEN*MCP_TCP_MSS; 86 | f.info.target_window=max(window_bytes/MCP_TCP_MSS+1,MCP_MIN_WIN); 87 | //printk(KERN_INFO "Flow size is %u bytes. Deadline is %u ms. Window scale is %hu.\n",f.info.bytes_total,deadline>>20,f.info.scale); 88 | //Insert MCP flow entry 89 | spin_lock_irqsave(&(ft.tableLock),flags); 90 | if(MCP_Insert_Table(&ft,&f,GFP_ATOMIC)==0) 91 | { 92 | printk(KERN_INFO "Insert fails\n"); 93 | } 94 | spin_unlock_irqrestore(&(ft.tableLock),flags); 95 | tcp_modify_outgoing(skb,f.info.current_window*MCP_TCP_MSS, get_tsval()); 96 | } 97 | else 98 | { 99 | infoPtr=MCP_Search_Table(&ft,&f); 100 | if(infoPtr!=NULL) 101 | { 102 | spin_lock_irqsave(&(ft.tableLock),flags); 103 | delta_in_us=ktime_us_delta(infoPtr->deadline,now); 104 | //Try to meet deadline 105 | if(delta_in_us>0) 106 | { 107 | //If the interval is larger than RTT, we should update window 108 | if(ktime_us_delta(now,infoPtr->last_update)>=infoPtr->srtt) 109 | { 110 | //Calculate window needed to meet flow ddl 111 | window_bytes=expect_window_bytes(infoPtr->bytes_total-infoPtr->bytes_received,infoPtr->srtt,delta_in_us)/ MCP_TCP_PAYLOAD_LEN*MCP_TCP_MSS; 112 | //Set new target_window 113 | infoPtr->target_window=max(window_bytes/MCP_TCP_MSS+1,MCP_MIN_WIN); 114 | infoPtr->last_update=now; 115 | } 116 | 117 | //Increase window by 1MSS each ACK at most 118 | if(infoPtr->current_windowtarget_window) 119 | { 120 | infoPtr->current_window+=1; 121 | } 122 | //Reduce window by 1MSS each ACK at most 123 | else if(infoPtr->current_window>infoPtr->target_window) 124 | { 125 | infoPtr->current_window=max(infoPtr->current_window-1,MCP_MIN_WIN); 126 | } 127 | } 128 | //Deadline has been missed (now>ddl) 129 | else 130 | { 131 | //We should set minimal window to this flow 132 | infoPtr->target_window=MCP_MIN_WIN; 133 | infoPtr->current_window=max(infoPtr->current_window-1,MCP_MIN_WIN); 134 | } 135 | spin_unlock_irqrestore(&(ft.tableLock),flags); 136 | //printk(KERN_INFO "Window is %u MSS\n",infoPtr->window); 137 | tcp_modify_outgoing(skb,infoPtr->current_window*MCP_TCP_MSS/infoPtr->scale+1, get_tsval()); 138 | } 139 | } 140 | } 141 | 142 | return NF_ACCEPT; 143 | } 144 | 145 | //PREROUTING for incoming packets 146 | static unsigned int MCP_hook_func_in(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 147 | { 148 | struct iphdr *iph=NULL; //IP header structure 149 | struct tcphdr *tcph=NULL; //TCP header structure 150 | struct MCP_Flow f; 151 | unsigned long flags; 152 | u16 result=0; 153 | u32 rtt=0; //Sample RTT value 154 | u32 seq=0; 155 | u16 payloadLen=0; //TCP payload length 156 | struct MCP_Flow_Info* infoPtr=NULL; 157 | //ktime_t now=ktime_get(); 158 | 159 | if(!in) 160 | return NF_ACCEPT; 161 | 162 | if(strncmp(in->name,param_dev,IFNAMSIZ)!=0) 163 | return NF_ACCEPT; 164 | 165 | iph=(struct iphdr *)skb_network_header(skb); 166 | 167 | //The packet is not ip packet (e.g. ARP or others) 168 | if (unlikely(iph==NULL)) 169 | return NF_ACCEPT; 170 | 171 | if(likely(iph->protocol==IPPROTO_TCP)) 172 | { 173 | tcph=(struct tcphdr *)((__u32 *)iph+ iph->ihl); 174 | f.local_ip=iph->daddr; 175 | f.remote_ip=iph->saddr; 176 | f.local_port=ntohs(tcph->dest); 177 | f.remote_port=ntohs(tcph->source); 178 | MCP_Init_Info(&(f.info)); 179 | 180 | if(tcph->fin||tcph->rst) 181 | { 182 | spin_lock_irqsave(&(ft.tableLock),flags); 183 | result=MCP_Delete_Table(&ft,&f); 184 | spin_unlock_irqrestore(&(ft.tableLock),flags); 185 | if(result>0) 186 | { 187 | tcp_modify_incoming(skb,(__u32)(jiffies)); 188 | clear_ecn(skb); 189 | } 190 | } 191 | else 192 | { 193 | infoPtr=MCP_Search_Table(&ft,&f); 194 | if(infoPtr!=NULL) 195 | { 196 | //printk(KERN_INFO "Flow entry exists\n"); 197 | //Get sample RTT 198 | rtt=max(tcp_modify_incoming(skb,(__u32)(jiffies)),MCP_INIT_RTT); 199 | //printk(KERN_INFO "RTT is %u us\n",rtt); 200 | payloadLen=ntohs(iph->tot_len)-(iph->ihl<<2)-(tcph->doff<<2); 201 | seq=ntohl(tcph->seq); 202 | if(payloadLen>=1) 203 | seq=seq+payloadLen-1; 204 | 205 | spin_lock_irqsave(&(ft.tableLock),flags); 206 | //Update smooth RTT 207 | infoPtr->srtt=min(MCP_MAX_RTT,(MCP_RTT_SMOOTH*infoPtr->srtt+(1000-MCP_RTT_SMOOTH)*rtt)/1000); 208 | //Update received data and sequence number 209 | if(is_seq_larger(seq,infoPtr->latest_seq)>0) 210 | { 211 | infoPtr->latest_seq=seq; 212 | infoPtr->bytes_received=min(infoPtr->bytes_received+payloadLen,infoPtr->bytes_total); 213 | } 214 | spin_unlock_irqrestore(&(ft.tableLock),flags); 215 | //Clear ECN marking for MCP flows 216 | clear_ecn(skb); 217 | } 218 | } 219 | } 220 | 221 | return NF_ACCEPT; 222 | } 223 | 224 | //Called when module loaded using 'insmod' 225 | int init_module() 226 | { 227 | int i=0; 228 | //Get interface 229 | if(param_dev==NULL) 230 | { 231 | printk(KERN_INFO "MCP: not specify network interface\n"); 232 | param_dev = "eth1\0"; 233 | } 234 | else 235 | { 236 | // trim 237 | for(i = 0; i < 32 && param_dev[i] != '\0'; i++) 238 | { 239 | if(param_dev[i] == '\n') 240 | { 241 | param_dev[i] = '\0'; 242 | break; 243 | } 244 | } 245 | } 246 | //Initialize FlowTable 247 | MCP_Init_Table(&ft); 248 | 249 | //Register POSTROUTING hook 250 | MCP_nf_hook_out.hook=MCP_hook_func_out; 251 | MCP_nf_hook_out.hooknum=NF_INET_POST_ROUTING; 252 | MCP_nf_hook_out.pf=PF_INET; 253 | MCP_nf_hook_out.priority=NF_IP_PRI_FIRST; 254 | nf_register_hook(&MCP_nf_hook_out); 255 | 256 | //Register PREROUTING hook 257 | MCP_nf_hook_in.hook=MCP_hook_func_in; 258 | MCP_nf_hook_in.hooknum=NF_INET_PRE_ROUTING; 259 | MCP_nf_hook_in.pf=PF_INET; 260 | MCP_nf_hook_in.priority=NF_IP_PRI_FIRST; 261 | nf_register_hook(&MCP_nf_hook_in); 262 | 263 | printk(KERN_INFO "Start MCP kernel module on %s\n", param_dev); 264 | 265 | return 0; 266 | } 267 | 268 | //Called when module unloaded using 'rmmod' 269 | void cleanup_module() 270 | { 271 | //Unregister two hooks 272 | nf_unregister_hook(&MCP_nf_hook_out); 273 | nf_unregister_hook(&MCP_nf_hook_in); 274 | 275 | //Clear flow table 276 | //Print_Table(&ft); 277 | MCP_Empty_Table(&ft); 278 | 279 | printk(KERN_INFO "Stop MCP kernel module\n"); 280 | } -------------------------------------------------------------------------------- /backup/mixedflow/MCP/network.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "network.h" 6 | 7 | //Calculate the expected window (bytes) to meet deadline 8 | inline u32 expect_window_bytes(u32 bytes_remaining, u32 rtt, u32 delta_in_us) 9 | { 10 | if(likely(delta_in_us>0)) 11 | { 12 | return bytes_remaining*rtt/delta_in_us; 13 | } 14 | else 15 | { 16 | return 0; 17 | } 18 | } 19 | 20 | //Calculate microsecond-granularity TCP timestamp value 21 | inline u32 get_tsval(void) 22 | { 23 | return (u32)(ktime_to_ns(ktime_get())>>10); 24 | } 25 | 26 | //Clear ECN marking 27 | inline void clear_ecn(struct sk_buff *skb) 28 | { 29 | struct iphdr *iph=ip_hdr(skb); 30 | if(likely(iph!=NULL)) 31 | { 32 | if(skb_make_writable(skb, sizeof(struct iphdr))) 33 | { 34 | ipv4_change_dsfield(iph, 0xff, iph->tos & ~0x3); 35 | } 36 | } 37 | } 38 | 39 | //Function: get TCP window scale shift count from SYN packets and return 0 by default 40 | u8 tcp_get_scale(struct sk_buff *skb) 41 | { 42 | struct iphdr *ip_header=NULL; //IP header structure 43 | struct tcphdr *tcp_header=NULL; //TCP header structure 44 | unsigned int tcp_header_len=0; //TCP header length 45 | u8 *tcp_opt=NULL; //TCP option pointer 46 | u8 tcp_opt_value=0; //TCP option pointer value 47 | 48 | //Get IP header 49 | ip_header=(struct iphdr *)skb_network_header(skb); 50 | //Get TCP header on the base of IP header 51 | tcp_header=(struct tcphdr *)((u32 *)ip_header+ ip_header->ihl); 52 | //Get TCP header length 53 | tcp_header_len=(unsigned int)(tcp_header->doff*4); 54 | 55 | //Minimum TCP header length=20(Raw TCP header)+10(TCP Timestamp option)+3(TCP window scale option) 56 | if(tcp_header_len<33) 57 | return 1; 58 | 59 | //TCP option offset=IP header pointer+IP header length+TCP header length 60 | tcp_opt=(u8*)ip_header+ ip_header->ihl*4+20; 61 | 62 | while(1) 63 | { 64 | //If pointer has moved out off the range of TCP option, stop current loop 65 | if(tcp_opt-(u8*)tcp_header>=tcp_header_len) 66 | break; 67 | 68 | //Get value of current byte 69 | tcp_opt_value=*tcp_opt; 70 | 71 | if(tcp_opt_value==0x01)//No-Operation (NOP) 72 | { 73 | //Move to next byte 74 | tcp_opt++; 75 | } 76 | else if(tcp_opt_value==0x03) //TCP option kind: window scale (3) 77 | { 78 | //return window scale shift count 79 | return *(tcp_opt+2); 80 | } 81 | else //Other TCP options (e.g. MSS(2)) 82 | { 83 | //Move to next byte to get length of this TCP option 84 | tcp_opt++; 85 | //Get length of this TCP option 86 | tcp_opt_value=*tcp_opt; 87 | //Move to next TCP option 88 | tcp_opt=tcp_opt+1+(tcp_opt_value-2); 89 | } 90 | } 91 | //By default, shift count=0 92 | return 0; 93 | } 94 | 95 | //Modify incoming TCP packets and return RTT sample value 96 | u32 tcp_modify_incoming(struct sk_buff *skb, u32 time) 97 | { 98 | struct iphdr *ip_header=NULL; //IP header structure 99 | struct tcphdr *tcp_header=NULL; //TCP header structure 100 | unsigned short tcp_header_len=0; //TCP header length 101 | u8 *tcp_opt=NULL; //TCP option pointer 102 | u32 *tsecr=NULL; //TCP Timestamp echo reply pointer 103 | unsigned short tcplen=0; //TCP packet length 104 | u8 tcp_opt_value=0; //TCP option pointer value 105 | u32 rtt=0; //Sample RTT 106 | 107 | //If we can not modify this packet, return 0 108 | if(skb_linearize(skb)!=0) 109 | { 110 | return 0; 111 | } 112 | 113 | //Get IP header 114 | ip_header=(struct iphdr *)skb_network_header(skb); 115 | //Get TCP header on the base of IP header 116 | tcp_header=(struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 117 | //Get TCP header length 118 | tcp_header_len=(unsigned short)(tcp_header->doff*4); 119 | 120 | //Minimum TCP header length=20(Raw TCP header)+10(TCP Timestamp option) 121 | if(tcp_header_len<30) 122 | { 123 | return 0; 124 | } 125 | 126 | //TCP option offset=IP header pointer+IP header length+TCP header length 127 | tcp_opt=(u8*)ip_header+ip_header->ihl*4+20; 128 | //printk(KERN_INFO "TCP header length is %hu\n",tcp_header_len); 129 | 130 | while(1) 131 | { 132 | //If pointer has moved out off the range of TCP option, stop current loop 133 | if(tcp_opt-(u8*)tcp_header>=tcp_header_len) 134 | { 135 | break; 136 | } 137 | //Get value of current byte 138 | tcp_opt_value=*tcp_opt; 139 | 140 | if(tcp_opt_value==0x01)//No-Operation (NOP) 141 | { 142 | //Move to next byte 143 | tcp_opt++; 144 | } 145 | else if(tcp_opt_value==0x08) //TCP option kind: Timestamp (8) 146 | { 147 | //Get pointer to Timestamp echo reply (TSecr) 148 | tsecr=(u32*)(tcp_opt+6); 149 | //Get one RTT sample 150 | rtt=get_tsval()-ntohl(*tsecr); 151 | //printk(KERN_INFO "Echo back value: %u\n",ntohl(*tsecr)); 152 | //Modify TCP TSecr back to jiffies 153 | //Don't disturb TCP. Wrong TCP timestamp echo reply may reset TCP connections 154 | *tsecr=htonl(time); 155 | break; 156 | } 157 | else //Other TCP options (e.g. MSS(2)) 158 | { 159 | //Move to next byte to get length of this TCP option 160 | tcp_opt++; 161 | //Get length of this TCP option 162 | tcp_opt_value=*tcp_opt; 163 | //Move to next TCP option 164 | tcp_opt=tcp_opt+1+((unsigned int)tcp_opt_value-2); 165 | } 166 | } 167 | 168 | //TCP length=Total length - IP header length 169 | //tcplen=(ip_header->tot_len)-(ip_header->ihl<<2); 170 | tcplen=skb->len-(ip_header->ihl<<2); 171 | tcp_header->check=0; 172 | tcp_header->check = csum_tcpudp_magic(ip_header->saddr, ip_header->daddr,tcplen, ip_header->protocol,csum_partial((char *)tcp_header, tcplen, 0)); 173 | skb->ip_summed = CHECKSUM_UNNECESSARY; 174 | return rtt; 175 | } 176 | 177 | //Modify timestamp and receive window of outgoing TCP packets. Input: win (receive window value in bytes) and time (us) 178 | //If it succeeds, return 1. Else, return 0. 179 | u8 tcp_modify_outgoing(struct sk_buff *skb, u16 win, u32 time) 180 | { 181 | struct iphdr *ip_header=NULL; //IP header structure 182 | struct tcphdr *tcp_header=NULL; //TCP header structure 183 | unsigned int tcp_header_len=0; //TCP header length 184 | u8 *tcp_opt=NULL; //TCP option pointer 185 | u32 *tsval=NULL; //TCP Timestamp value pointer 186 | u32 tcplen=0; //Length of TCP 187 | u8 tcp_opt_value=0; //TCP option pointer value 188 | 189 | if (skb_linearize(skb)!= 0) 190 | { 191 | return 0; 192 | } 193 | 194 | //Get IP header 195 | ip_header=(struct iphdr *)skb_network_header(skb); 196 | //Get TCP header on the base of IP header 197 | tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 198 | //Get TCP header length 199 | tcp_header_len=(unsigned int)(tcp_header->doff*4); 200 | 201 | //Minimum TCP header length=20(Raw TCP header)+10(TCP Timestamp option) 202 | if(tcp_header_len<30) 203 | { 204 | return 0; 205 | } 206 | 207 | //Modify TCP window. Note that TCP received window should be in (0,65535]. 208 | if(win>0) 209 | tcp_header->window=htons(min(win,65535)); 210 | 211 | //TCP option offset=IP header pointer+IP header length+TCP header length 212 | tcp_opt=(u8*)ip_header+ ip_header->ihl*4+20; 213 | 214 | while(1) 215 | { 216 | //If pointer has moved out off the range of TCP option, stop current loop 217 | if(tcp_opt-(u8*)tcp_header>=tcp_header_len) 218 | { 219 | break; 220 | } 221 | 222 | //Get value of current byte 223 | tcp_opt_value=*tcp_opt; 224 | 225 | if(tcp_opt_value==1)//No-Operation (NOP) 226 | { 227 | //Move to next byte 228 | tcp_opt++; 229 | } 230 | else if(tcp_opt_value==8) //TCP option kind: Timestamp (8) 231 | { 232 | if(time>0) 233 | { 234 | //Get pointer to Timestamp value 235 | tsval=(u32*)(tcp_opt+2); 236 | //Modify TCP Timestamp value 237 | if(time>0) 238 | *tsval=htonl(time); 239 | } 240 | break; 241 | } 242 | else //Other TCP options (e.g. MSS(2)) 243 | { 244 | //Move to next byte to get length of this TCP option 245 | tcp_opt++; 246 | //Get length of this TCP option 247 | tcp_opt_value=*tcp_opt; 248 | //Move to next TCP option 249 | tcp_opt=tcp_opt+1+((unsigned int)tcp_opt_value-2); 250 | } 251 | } 252 | 253 | //TCP length=Total length - IP header length 254 | //tcplen=(ip_header->tot_len)-(ip_header->ihl<<2); 255 | tcplen=skb->len-(ip_header->ihl<<2); 256 | tcp_header->check=0; 257 | tcp_header->check=csum_tcpudp_magic(ip_header->saddr, ip_header->daddr,tcplen, ip_header->protocol,csum_partial((char *)tcp_header, tcplen, 0)); 258 | skb->ip_summed = CHECKSUM_UNNECESSARY; 259 | 260 | return 1; 261 | } 262 | 263 | //Maximum unsigned 32-bit integer value: 4294967295 264 | //Function: determine whether seq1 is larger than seq2 265 | //If Yes, return 1. Else, return 0. 266 | //We use a simple heuristic to handle wrapped TCP sequence number 267 | inline u8 is_seq_larger(u32 seq1, u32 seq2) 268 | { 269 | if(likely(seq1>seq2&&seq1-seq2<=4294900000)) 270 | { 271 | return 1; 272 | } 273 | else if(seq14294900000) 274 | { 275 | return 1; 276 | } 277 | else 278 | { 279 | return 0; 280 | } 281 | } -------------------------------------------------------------------------------- /backup/mixedflow/MCP/network.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETWORK_H__ 2 | #define __NETWORK_H__ 3 | 4 | #include 5 | #include 6 | 7 | inline u32 expect_window_bytes(u32 bytes_remaining, u32 rtt, u32 delta_in_us); 8 | inline u32 get_tsval(void); 9 | inline void clear_ecn(struct sk_buff *skb); 10 | u8 tcp_get_scale(struct sk_buff *skb); 11 | u32 tcp_modify_incoming(struct sk_buff *skb, u32 time); 12 | u8 tcp_modify_outgoing(struct sk_buff *skb, u16 win, u32 time); 13 | inline u8 is_seq_larger(u32 seq1, u32 seq2); 14 | 15 | 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /backup/mixedflow/MCP/params.c: -------------------------------------------------------------------------------- 1 | #include "params.h" 2 | 3 | const unsigned int MCP_TCP_PAYLOAD_LEN=1448; 4 | const unsigned int MCP_TCP_MSS=1460; 5 | 6 | const unsigned int MCP_INIT_WIN=3; 7 | const unsigned int MCP_MIN_WIN=2; 8 | 9 | const unsigned int MCP_HASH_RANGE=256; 10 | const unsigned int MCP_LIST_SIZE=32; 11 | 12 | const u32 MCP_INIT_RTT=100; 13 | const unsigned int MCP_RTT_SMOOTH=875; 14 | const u32 MCP_MAX_RTT=1000; -------------------------------------------------------------------------------- /backup/mixedflow/MCP/params.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARAMS_H__ 2 | #define __PARAMS_H__ 3 | 4 | #include 5 | 6 | //extern const unsigned int MCP_ETHERNET_PKT_LEN; 7 | extern const unsigned int MCP_TCP_PAYLOAD_LEN; 8 | //Size (bytes) ofr Maximum Segment Size 9 | extern const unsigned int MCP_TCP_MSS; 10 | 11 | //Initialized TCP window size (MSS) 12 | extern const unsigned int MCP_INIT_WIN; 13 | //Mimum TCP window size (MSS) 14 | extern const unsigned int MCP_MIN_WIN; 15 | 16 | //Hash range 17 | extern const unsigned int MCP_HASH_RANGE; 18 | //Maximum size of a list 19 | extern const unsigned int MCP_LIST_SIZE; 20 | 21 | //Initialized RTT value (us) 22 | extern const u32 MCP_INIT_RTT; 23 | //parameter to smooth RTT: srtt=rtt_smooth/1000*srtt+(1000-rtt_smooth)/1000*rtt 24 | extern const unsigned int MCP_RTT_SMOOTH; 25 | //Maximum RTT value (us) 26 | extern const u32 MCP_MAX_RTT; 27 | 28 | #endif -------------------------------------------------------------------------------- /backup/mixedflow/dynamic_flow.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | import time 5 | import random 6 | import math 7 | import threading 8 | 9 | #This function is to print usage of this script 10 | def usage(): 11 | sys.stderr.write('This script is used for dynamic flow emulation:\n') 12 | sys.stderr.write('dynamic_flow.py [host file] [trace file] [result file] \n') 13 | 14 | class FlowThread(threading.Thread): 15 | #host: sender IP address 16 | #size: flow size (KB) 17 | #id: flow id 18 | #type: flow type (1,2 or 3) 19 | #deadline: deadline time (ms) for type 1 flows 20 | def __init__(self, host, size, id, type, deadline): 21 | self.host=host 22 | self.size=size 23 | self.id=id 24 | self.type=type 25 | self.deadline=deadline 26 | threading.Thread.__init__(self) 27 | 28 | def run(self): 29 | is_agnostic=1 30 | #For Type 1 and 2 flows, we need to deliver flow information to kernel space 31 | if self.type==1 or self.type==2: 32 | is_agnostic=0 33 | #By default, we use port number of 5001 34 | line=os.popen('./client.o '+str(self.host)+' '+str(5001)+' '+str(self.size)+' '+str(self.deadline)+' '+str(self.is_agnostic)).read() 35 | result=line.split() 36 | if len(result)>=2: 37 | #Get FCT for this flow and save it into global variable fcts 38 | fct=int(result[len(result)-2]) 39 | fcts[self.id]=fct 40 | 41 | #main function 42 | if len(sys.argv)!=4: 43 | usage() 44 | else: 45 | host_filename=sys.argv[1] 46 | trace_filename=sys.argv[2] 47 | result_filename=sys.argv[3] 48 | 49 | #Get hosts from host file 50 | hosts=[] 51 | host_file=open(host_filename,'r') 52 | lines=host_file.readlines() 53 | for line in lines: 54 | hosts.append(line.strip('\n')) 55 | host_file.close() 56 | 57 | #Flow Completion Time 58 | global fcts 59 | fcts=[] 60 | #Sleep Interval 61 | times=[] 62 | #Flow Size 63 | flows=[] 64 | #Flow Type 65 | types=[] 66 | #Deadlines 67 | deadlines=[] 68 | #Sender IP 69 | senders=[] 70 | 71 | #Get trace from trace file 72 | traces=[] 73 | trace_file=open(trace_filename,'r') 74 | traces=trace_file.readlines() 75 | 76 | for i in range(len(traces)): 77 | tmp=traces[i].split() 78 | if len(tmp)==5: 79 | times.append(float(tmp[0])) 80 | flows.append(int(tmp[1])) 81 | types.append(int(tmp[2])) 82 | deadlines.append(int(tmp[3])) 83 | senders.append(hosts[int(tmp[4])]) 84 | fcts.append(0) 85 | 86 | #Start emulation 87 | raw_input('Press any key to start emulation') 88 | 89 | for i in range(len(flows)): 90 | #Get next time interval (sleep time) 91 | sleeptime=times[i] 92 | #Get sender IP address 93 | host=senders[i] 94 | #Get flow type 95 | #Get deadline 96 | #Sleep 97 | time.sleep(sleeptime/1000) 98 | #Start thread to send traffic 99 | newthread=FlowThread(host,flows[i],i) 100 | newthread.start() 101 | 102 | #Stop emulation 103 | raw_input('Press any key to stop emulation') 104 | 105 | #Analyze FCT results 106 | short_fcts=[] 107 | medium_fcts=[] 108 | long_fcts=[] 109 | 110 | #Write FCT results into the file 111 | result_file=open(result_filename,'w') 112 | for i in range(len(flows)): 113 | #If flow size is smaller than 10KB 114 | if flows[i]<=100: 115 | tiny_fcts.append(fcts[i]) 116 | #If flow size is in (10KB,100KB) 117 | elif flows[i]<=10000: 118 | medium_fcts.append(fcts[i]) 119 | #If flow size is larger than 10MB 120 | else: 121 | long_fcts.append(fcts[i]) 122 | 123 | result_file.write(str(flows[i])+' KB '+str(fcts[i])+' us\n') 124 | result_file.close() 125 | 126 | if len(tiny_fcts)>0: 127 | print 'There are '+str(len(tiny_fcts))+' flows in (0,10KB). Their average FCT is '+str(sum(tiny_fcts)/len(tiny_fcts))+' us' 128 | if len(short_fcts)>0: 129 | print 'There are '+str(len(short_fcts))+' flows in (10KB,100KB). Their average FCT is '+str(sum(short_fcts)/len(short_fcts))+' us' 130 | if len(long_fcts)>0: 131 | print 'There are '+str(len(long_fcts))+' flows in (10MB,). Their average FCT is '+str(sum(long_fcts)/len(long_fcts))+' us' 132 | -------------------------------------------------------------------------------- /backup/mixedflow/generator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | import time 5 | import random 6 | import math 7 | 8 | #This function is to print usage of this script 9 | def usage(): 10 | sys.stderr.write('This script is used to generate dynamic flow workloads for mixedflow project:\n') 11 | sys.stderr.write('generator.py [percentage1] [percentage2] [percentage3] [CDF file 1] [CDF file 2] [CDF file 3] [load] [link capacity (Mbps)] [flow number] [host number] [output file]\n') 12 | 13 | def check_input(p1,p2,p3): 14 | if p1>=0 and p2>=0 and p3>=0 and (p1+p2+p3)==1: 15 | return True 16 | else: 17 | return False 18 | 19 | #http://preshing.com/20111007/how-to-generate-random-timings-for-a-poisson-process/ 20 | #Return next time interval (ms) 21 | def nextTime(rateParameter): 22 | #We use round function to get a integer 23 | return round(-math.log(1.0 - random.random()) / rateParameter) 24 | 25 | #Given a flow distribution and a random number in (0,1), return a flow size (KB) 26 | def flowsize(distribution, random): 27 | i=0 28 | for var in distribution: 29 | if var[0]>random: 30 | x1=distribution[i-1][0] 31 | x2=distribution[i][0] 32 | y1=distribution[i-1][1] 33 | y2=distribution[i][1] 34 | value=int(((y2-y1)/(x2-x1)*random+(x2*y1-x1*y2)/(x2-x1))*1448/1024) 35 | return value 36 | elif var[0]==random: 37 | return int(var[1]*1448/1024) 38 | else: 39 | i=i+1 40 | #By default, return 0 41 | return 0 42 | 43 | #main function 44 | if len(sys.argv)!=12: 45 | usage() 46 | else: 47 | p1=float(sys.argv[1]) 48 | p2=float(sys.argv[2]) 49 | p3=float(sys.argv[3]) 50 | 51 | if check_input(p1,p2,p3)==False: 52 | print 'Illegal percentages' 53 | sys.exit() 54 | 55 | cdf_filename1=sys.argv[4] 56 | cdf_filename2=sys.argv[5] 57 | cdf_filename3=sys.argv[6] 58 | 59 | load=float(sys.argv[7]) 60 | capacity=float(sys.argv[8]) 61 | flow_num=int(sys.argv[9]) 62 | host_num=int(sys.argv[10]) 63 | output_filename=sys.argv[11] 64 | 65 | #Initialize flow distribution 66 | #Type 1 flows 67 | distribution1=[] 68 | #Type 2 flows 69 | distribution2=[] 70 | #Type 3 flows 71 | distribution3=[] 72 | 73 | #Get traffic distribution line by line from 3 input files 74 | #Type 1 75 | cdf_file1=open(cdf_filename1,'r') 76 | lines=cdf_file1.readlines() 77 | i=0 78 | for line in lines: 79 | tmp=line.split() 80 | if len(tmp)>=2: 81 | distribution1.append([float(tmp[1]),float(tmp[0])]) 82 | i=i+1 83 | cdf_file1.close() 84 | #Type 2 85 | cdf_file2=open(cdf_filename2,'r') 86 | lines=cdf_file2.readlines() 87 | i=0 88 | for line in lines: 89 | tmp=line.split() 90 | if len(tmp)>=2: 91 | distribution2.append([float(tmp[1]),float(tmp[0])]) 92 | i=i+1 93 | cdf_file2.close() 94 | #Type 3 95 | cdf_file3=open(cdf_filename3,'r') 96 | lines=cdf_file3.readlines() 97 | i=0 98 | for line in lines: 99 | tmp=line.split() 100 | if len(tmp)>=2: 101 | distribution3.append([float(tmp[1]),float(tmp[0])]) 102 | i=i+1 103 | cdf_file3.close() 104 | 105 | #Generate flow size 106 | flows=[] 107 | for i in range(flow_num): 108 | number=random.random() 109 | #Type 1 flows 110 | if number<=p1: 111 | flows.append([flowsize(distribution1,random.random()),1]) 112 | #Type 2 flows 113 | elif number<=p1+p2: 114 | flows.append([flowsize(distribution2,random.random()),2]) 115 | #Type 3 flows 116 | else: 117 | flows.append([flowsize(distribution2,random.random()),3]) 118 | 119 | #Get average throughput 120 | throughput=load*capacity 121 | #Get average flow size 122 | total_size=0 123 | for flow in flows: 124 | total_size+=flow[0] 125 | avg=total_size/len(flows) 126 | 127 | #Get average number of requests per second 128 | num=throughput*1024*1024/(avg*1024*8) 129 | #Get average request rate (number of requests every 1 ms) 130 | rate=num/1000 131 | 132 | #Generate time interval 133 | times=[] 134 | for i in range(flow_num): 135 | #Get time interval (sleep time) 136 | times.append(nextTime(rate)) 137 | 138 | #Write trace results into output file 139 | #Trace format: 140 | output_file=open(output_filename,'w') 141 | start=random.randint(0,host_num-1) 142 | for i in range(flow_num): 143 | flow_size=flows[i][0] 144 | flow_type=flows[i][1] 145 | deadline=0 146 | #Type 1 flows 147 | if flow_type==1: 148 | #Calculate ideal FCT (ms) 149 | ideal_fct=0.2+flow_size*8*1024/(capacity*1024*1024)*1000 150 | #Deadline is assigned to 151 | deadline=int(math.ceil(2*ideal_fct)) 152 | output_file.write(str(times[i])+' '+str(flow_size)+' '+str(flow_type)+' '+str(deadline)+' '+str(start)+'\n') 153 | start=(start+1)%host_num 154 | output_file.close() 155 | 156 | print 'Auto generate '+str(len(flows))+' flows:' 157 | print 'The average flow size: '+str(avg)+' KB' 158 | print 'The average request speed: '+str(num)+' requests/second' 159 | print 'Dynamic flow emulation will last for about '+str(len(flows)/num)+' seconds' 160 | print 'Done' 161 | 162 | -------------------------------------------------------------------------------- /backup/mixedflow/workload/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | //Maximum data_size: 1024*1024KB=1GB (20bits) 13 | int max_data_size=1024*1024; 14 | //Maximum deadline: 4*1024=4096ms (12 bits) 15 | int max_deadline=4*1024; 16 | 17 | //Print usage information 18 | void usage(); 19 | 20 | int main(int argc, char **argv) 21 | { 22 | if(argc!=6) 23 | { 24 | usage(); 25 | return 0; 26 | } 27 | 28 | char server[16]; //IP address (e.g. 192.168.101.101) 29 | char query[30]; //query=data_size+' '+deadline+' '+agnostic 30 | int port; //TCP port number 31 | int data_size; //Request data size (KB) We allocate 20bits for this in nfmark [0, 4GB] 32 | int deadline; //Deadline time (ms) We allocate 12bits for this in nfmark [0,4096ms] 33 | int is_agnostic; //Whether server delivers flow size and deadline information into userspace 34 | 35 | struct timeval tv_start; //Start time (after three way handshake) 36 | struct timeval tv_end; //End time 37 | int sockfd; //Socket 38 | struct sockaddr_in servaddr; //Server address (IP:Port) 39 | int len; //Read length 40 | char buf[BUFSIZ]; //Receive buffer 41 | unsigned long fct; //Flow Completion Time 42 | 43 | //Initialize ‘server’ 44 | memset(server,'\0',16); 45 | //Initialize 'query' 46 | memset(query,'\0',30); 47 | 48 | //Get server address 49 | strncpy(server,argv[1],strlen(argv[1])); 50 | //Get TCP port: char* to int 51 | port=atoi(argv[2]); 52 | //Get data_size: char* to int 53 | data_size=atoi(argv[3]); 54 | //Get deadline information: char* to int 55 | deadline=atoi(argv[4]); 56 | //Get is_agnostic: char* to int 57 | is_agnostic=atoi(argv[5]); 58 | 59 | //If the inputs are legal 60 | if(check_input(data_size,deadline,is_agnostic)==0) 61 | { 62 | printf("Illegal input!\n"); 63 | return 0; 64 | } 65 | else 66 | { 67 | strcat(query,argv[3]); 68 | strcat(query," "); 69 | strcat(query,argv[4]); 70 | strcat(query," "); 71 | strcat(query,argv[5]); 72 | } 73 | 74 | //Init sockaddr_in 75 | memset(&servaddr,0,sizeof(servaddr)); 76 | servaddr.sin_family=AF_INET; 77 | //IP address 78 | servaddr.sin_addr.s_addr=inet_addr(server); 79 | //Port number 80 | servaddr.sin_port=htons(port); 81 | 82 | //Init socket 83 | if((sockfd=socket(PF_INET,SOCK_STREAM,0))<0) 84 | { 85 | perror("socket error\n"); 86 | return; 87 | } 88 | //Establish connection 89 | if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr))<0) 90 | { 91 | printf("Can not connect to %s\n",server); 92 | return 0; 93 | } 94 | 95 | //Get start time after connection establishment 96 | gettimeofday(&tv_start,NULL); 97 | 98 | //Send request 99 | len=send(sockfd,query,strlen(query),0); 100 | //Receive data 101 | while(1) 102 | { 103 | len=recv(sockfd,buf,BUFSIZ,0); 104 | if(len<=0) 105 | break; 106 | } 107 | //Get end time after receiving all of the data 108 | gettimeofday(&tv_end,NULL); 109 | //Close connection 110 | close(sockfd); 111 | //Calculate time interval (unit: microsecond) 112 | fct=(tv_end.tv_sec-tv_start.tv_sec)*1000000+(tv_end.tv_usec-tv_start.tv_usec); 113 | printf("From %s: %d KB %lu us\n", server,data_size,fct); 114 | return 0; 115 | } 116 | 117 | 118 | void usage() 119 | { 120 | printf("./client.o [server IP address] [server port] [request data size(KB)] [deadline(ms)] [is_agnostic]\n"); 121 | } 122 | 123 | int check_input(int data_size, int deadline, int is_agnostic) 124 | { 125 | return(data_size>0&&data_size=0&&deadline 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | //Start TCP server 14 | void start_server(int port); 15 | //Function to deal with an incoming connection 16 | void* server_thread_func(void* client_sockfd_ptr); 17 | //Print usage information 18 | void usage(); 19 | 20 | int main(int argc, char **argv) 21 | { 22 | if(argc!=2) 23 | { 24 | usage(); 25 | return 0; 26 | } 27 | start_server(atoi(argv[1])); 28 | return 0; 29 | } 30 | 31 | void usage() 32 | { 33 | printf("./server.o [port]\n"); 34 | } 35 | void start_server(int port) 36 | { 37 | //Socket for server 38 | int server_sockfd; 39 | //Socket pointer for client 40 | int* client_sockfd_ptr=NULL; 41 | //A thread to deal with client_sockfd 42 | pthread_t server_thread; 43 | //Server address 44 | struct sockaddr_in server_addr; 45 | //Client address 46 | struct sockaddr_in client_addr; 47 | 48 | memset(&server_addr,0,sizeof(server_addr)); 49 | //IP protocol 50 | server_addr.sin_family=AF_INET; 51 | //Listen on "0.0.0.0" (Any IP address of this host) 52 | server_addr.sin_addr.s_addr=INADDR_ANY; 53 | //Specify port number 54 | server_addr.sin_port=htons(port); 55 | 56 | //Init socket 57 | if((server_sockfd=socket(PF_INET,SOCK_STREAM,0))<0) 58 | { 59 | perror("socket error"); 60 | return; 61 | } 62 | 63 | //Bind socket on IP:Port 64 | if(bind(server_sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr))<0) 65 | { 66 | perror("bind error"); 67 | return; 68 | } 69 | 70 | //Start listen 71 | //The maximum number of concurrent connections is 200 72 | listen(server_sockfd,200); 73 | int sin_size=sizeof(struct sockaddr_in); 74 | 75 | while(1) 76 | { 77 | client_sockfd_ptr=(int*)malloc(sizeof(int)); 78 | int value=accept(server_sockfd,(struct sockaddr *)&client_addr,&sin_size); 79 | if(value<0) 80 | { 81 | perror("accept error"); 82 | free(client_sockfd_ptr); 83 | return; 84 | } 85 | *client_sockfd_ptr=value; 86 | if(pthread_create(&server_thread, NULL , server_thread_func, (void*)client_sockfd_ptr) < 0) 87 | { 88 | perror("could not create thread"); 89 | return; 90 | } 91 | } 92 | } 93 | 94 | void* server_thread_func(void* client_sockfd_ptr) 95 | { 96 | int i; 97 | int sock=*(int*)client_sockfd_ptr; 98 | char write_message[BUFSIZ+1]; 99 | char read_message[1024]={0}; 100 | int len; 101 | char *savePtr; 102 | int data_size=0; 103 | int deadline=0; 104 | int is_agnostic=1; 105 | unsigned int mark=0; 106 | int remaining_size; 107 | int loop; 108 | 109 | free(client_sockfd_ptr); 110 | memset(write_message,1,BUFSIZ); 111 | write_message[BUFSIZ]='\0'; 112 | len=recv(sock,read_message,1024,0); 113 | 114 | //Get data volume (KB) 115 | data_size=atoi(strtok_r(read_message," ",&savePtr)); 116 | //Get deadline (ms) 117 | deadline=atoi(strtok_r(NULL," ",&savePtr)); 118 | //Get is_agnostic 119 | is_agnostic=atoi(strtok_r(NULL," ",&savePtr)); 120 | 121 | //Just for test 122 | //printf("size:%dKB deadline:%dms is_agnostic:%d\n",data_size,deadline,is_agnostic); 123 | //Calculate mark 124 | if(is_agnostic==0) 125 | { 126 | mark=deadline*1024*1024+data_size; 127 | setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); 128 | } 129 | 130 | //Calculate loops. In each loop, we can send BUFSIZ (8192) bytes of data 131 | loop=data_size*1024/BUFSIZ; 132 | //Calculate remaining size to be sent 133 | remaining_size=data_size*1024-loop*BUFSIZ; 134 | 135 | //Send data with 8192 bytes each loop 136 | for(i=0;i 2} { 37 | Agent/TCP/FullTcp set spa_thresh_ [expr ($ackRatio - 1) * $pktSize] 38 | } 39 | 40 | ################ DCTCP Options ######################### 41 | Agent/TCP set ecnhat_ true 42 | Agent/TCPSink set ecnhat_ true 43 | Agent/TCP set ecnhat_g_ $DCTCP_g 44 | 45 | ################ Queue Options ######################### 46 | Queue set limit_ 10000 47 | 48 | ################ Random Early Detection ################ 49 | Queue/RED set bytes_ false 50 | Queue/RED set queue_in_bytes_ true 51 | Queue/RED set mean_pktsize_ $pktSize 52 | Queue/RED set setbit_ true 53 | Queue/RED set gentle_ false 54 | Queue/RED set q_weight_ 1.0 55 | Queue/RED set mark_p_ 1.0 56 | Queue/RED set thresh_ $DCTCP_K 57 | Queue/RED set maxthresh_ $DCTCP_K 58 | 59 | ############# Multi-level Feedback Queue ############## 60 | Queue/MLFQ set queue_num_ $queue_num 61 | Queue/MLFQ set thresh_ $DCTCP_K 62 | Queue/MLFQ set dequeue_marking_ 1 63 | Queue/MLFQ set mean_pktsize_ $pktSize 64 | 65 | #################### NS2 Trace ######################## 66 | set mytracefile [open mytracefile.tr w] 67 | $ns trace-all $mytracefile 68 | proc finish {} { 69 | global ns mytracefile 70 | $ns flush-trace 71 | close $mytracefile 72 | exit 0 73 | } 74 | 75 | ##################### Topology ######################### 76 | for {set i 0} {$i < $node} {incr i} { 77 | set n($i) [$ns node] 78 | } 79 | set nqueue [$ns node] 80 | set nclient [$ns node] 81 | 82 | for {set i 0} { $i < $node} {incr i} { 83 | $ns duplex-link $n($i) $nqueue $lineRate [expr $RTT/4] DropTail 84 | $ns duplex-link-op $n($i) $nqueue queuePos 0.25 85 | $ns queue-limit $n($i) $nqueue 10000; #End Host buffer size is very large 86 | $ns queue-limit $nqueue $n($i) 100 87 | } 88 | 89 | $ns simplex-link $nqueue $nclient $lineRate [expr $RTT/4] $switchAlg 90 | $ns simplex-link $nclient $nqueue $lineRate [expr $RTT/4] DropTail 91 | $ns queue-limit $nqueue $nclient 100 92 | $ns queue-limit $nclient $nqueue 100 93 | 94 | ################## Long-live Flows ####################### 95 | for {set i 0} {$i < 2 } {incr i} { 96 | set tcp($i) [new Agent/TCP/FullTcp/Sack] 97 | set sink($i) [new Agent/TCP/FullTcp/Sack] 98 | $sink($i) listen 99 | 100 | $ns attach-agent $n($i) $tcp($i) 101 | $ns attach-agent $nclient $sink($i) 102 | 103 | $tcp($i) set fid_ [expr $i] 104 | $sink($i) set fid_ [expr $i] 105 | 106 | $ns connect $tcp($i) $sink($i) 107 | set ftp($i) [new Application/FTP] 108 | $ftp($i) attach-agent $tcp($i) 109 | $ftp($i) set type_ FTP 110 | $ns at 0.1 "$ftp($i) start" 111 | $ns at $simulationTime "$ftp($i) stop" 112 | } 113 | 114 | ################## Short Flows ####################### 115 | for {set i 2} {$i < $node} {incr i} { 116 | set tcp($i) [new Agent/TCP/FullTcp/Sack] 117 | set sink($i) [new Agent/TCP/FullTcp/Sack] 118 | $sink($i) listen 119 | 120 | $ns attach-agent $n($i) $tcp($i) 121 | $ns attach-agent $nclient $sink($i) 122 | 123 | #Record TCP logs 124 | $tcp($i) attach [open ./$tracedir/$i.tr w] 125 | $tcp($i) set bugFix_ false 126 | $tcp($i) trace cwnd_ 127 | $tcp($i) trace ack_ 128 | $tcp($i) trace ssthresh_ 129 | $tcp($i) trace nrexmit_ 130 | $tcp($i) trace nrexmitpack_ 131 | $tcp($i) trace nrexmitbytes_ 132 | $tcp($i) trace ncwndcuts_ 133 | $tcp($i) trace ncwndcuts1_ 134 | $tcp($i) trace dupacks_ 135 | 136 | $tcp($i) set fid_ [expr $i] 137 | $sink($i) set fid_ [expr $i] 138 | 139 | $ns connect $tcp($i) $sink($i) 140 | set ftp($i) [new Application/FTP] 141 | $ftp($i) attach-agent $tcp($i) 142 | $ftp($i) set type_ FTP 143 | $ns at [expr 0.2+0.001*[expr rand()+1]*$i] "$ftp($i) send $data_size" 144 | } 145 | 146 | $ns at $simulationTime "finish" 147 | $ns run 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /backup/mlfq/mlfq.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Multi-Level Feedback Queue (MLFQ) 3 | * Copyright (c) 2014 Wei Bai (baiwei0427@gmail.com) from Hong Kong University of Science and Technology 4 | * All rights reserved. 5 | * 6 | * In MLFQ, it contains N CoS (Class of Service) queues. 7 | * MLFQ uses Strict Priority (SP) to schedule packets among multiple CoS queues. 8 | * To cooperate with ECN, MLFQ also has a ECN marking threshold. 9 | * When the queue lengths of all CoS queues exceed this threshold, ECN is marked. 10 | * You can select enqueue marking or dequeue marking 11 | * 12 | * Variables: 13 | * queue_num_: number of CoS queues 14 | * thresh_: ECN marking threshold 15 | * dequeue_marking_: 1 (dequeue marking) or 0 (enqueue_marking) 16 | * mean_pktsize_: configured mean packet size in bytes 17 | */ 18 | 19 | #include "mlfq.h" 20 | #include "flags.h" 21 | 22 | static class MLFQClass : public TclClass { 23 | public: 24 | MLFQClass() : TclClass("Queue/MLFQ") {} 25 | TclObject* create(int, const char*const*) { 26 | return (new MLFQ); 27 | } 28 | }class_mlfq; 29 | 30 | void MLFQ::enque(Packet* p) 31 | { 32 | hdr_ip *iph = hdr_ip::access(p); 33 | int prio = iph->prio(); 34 | hdr_flags* hf = hdr_flags::access(p); 35 | 36 | int qlimBytes = qlim_ * mean_pktsize_; 37 | 38 | //queue length exceeds the queue limit 39 | if(queueByteLength(queue_num_)+hdr_cmn::access(p)->size()>qlimBytes) 40 | { 41 | drop(p); 42 | return; 43 | } 44 | 45 | if(prio>=queue_num_) 46 | prio=queue_num_-1; 47 | 48 | //ECN enqueue marking and normal marking 49 | if(dequeue_marking_==0 && prio_marking_==0) 50 | { 51 | if(queueByteLength(queue_num_)+hdr_cmn::access(p)->size()>thresh_*mean_pktsize_) 52 | { 53 | if (hf->ect()) //If this packet is ECN-capable 54 | hf->ce() = 1; 55 | } 56 | } 57 | //ECN enqueue marking and priority marking 58 | else if(dequeue_marking_==0 && prio_marking_==1) 59 | { 60 | if(queueByteLength(prio+1)+hdr_cmn::access(p)->size()>thresh_*mean_pktsize_) 61 | { 62 | if (hf->ect()) //If this packet is ECN-capable 63 | hf->ce() = 1; 64 | } 65 | } 66 | 67 | //Enqueue packet 68 | q_[prio]->enque(p); 69 | } 70 | 71 | Packet* MLFQ::deque() 72 | { 73 | //high->low: 0->7 74 | for(int i=0;ilength()>0) 77 | { 78 | Packet* p=q_[i]->deque(); 79 | //ECN dequeue marking and normal marking 80 | if(dequeue_marking_==1&& prio_marking_==0) 81 | { 82 | if(queueByteLength(queue_num_)>thresh_*mean_pktsize_) 83 | { 84 | hdr_flags* hf = hdr_flags::access(p); 85 | if (hf->ect()) //If this packet is ECN-capable 86 | hf->ce() = 1; 87 | } 88 | } 89 | //ECN dequeue marking and priority marking 90 | else if(dequeue_marking_==1&& prio_marking_==1) 91 | { 92 | if(queueByteLength(i+1)>thresh_*mean_pktsize_) 93 | { 94 | hdr_flags* hf = hdr_flags::access(p); 95 | if (hf->ect()) //If this packet is ECN-capable 96 | hf->ce() = 1; 97 | } 98 | } 99 | 100 | //dequeue packet 101 | return (p); 102 | } 103 | } 104 | return q_[0]->deque(); 105 | } 106 | 107 | -------------------------------------------------------------------------------- /backup/mlfq/mlfq.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Multi-Level Feedback Queue (MLFQ) 3 | * Copyright (c) 2014 Wei Bai (baiwei0427@gmail.com) from Hong Kong University of Science and Technology 4 | * All rights reserved. 5 | * 6 | * In MLFQ, it contains N CoS (Class of Service) queues. 7 | * MLFQ uses Strict Priority (SP) to schedule packets among multiple CoS queues. 8 | * To cooperate with ECN, MLFQ also has a ECN marking threshold. 9 | * When the queue lengths of all CoS queues exceed this threshold, ECN is marked. 10 | * You can select enqueue marking or dequeue marking 11 | * 12 | * Variables: 13 | * queue_num_: number of CoS queues 14 | * thresh_: ECN marking threshold (pkts) 15 | * prio_marking_: enable Priority ECN Marking or not (1 enable 0 disable) 16 | * dequeue_marking_: 1 (dequeue marking) or 0 (enqueue_marking) 17 | * mean_pktsize_: configured mean packet size in bytes 18 | */ 19 | 20 | #ifndef ns_mlfq_h 21 | #define ns_mlfq_h 22 | 23 | #include 24 | #include "queue.h" 25 | #include "config.h" 26 | 27 | class MLFQ : public Queue { 28 | public: 29 | MLFQ() 30 | { 31 | //Bind variables 32 | bind("queue_num_", &queue_num_); 33 | bind("thresh_",&thresh_); 34 | bind("prio_marking_",&prio_marking_); 35 | bind("dequeue_marking_",&dequeue_marking_); 36 | bind("mean_pktsize_", &mean_pktsize_); 37 | 38 | //Init queues 39 | q_=new PacketQueue*[queue_num_]; 40 | for(int i=0;iqueue_num_) 70 | num=queue_num_; 71 | 72 | int length = 0; 73 | for(int i=0; ilength(); 75 | return length; 76 | } 77 | 78 | //Return total queue length (bytes) from queue 0 to queue num 79 | int queueByteLength(int num) 80 | { 81 | if(num>queue_num_) 82 | num=queue_num_; 83 | 84 | int bytelength = 0; 85 | for(int i=0; ibyteLength(); 87 | return bytelength; 88 | } 89 | }; 90 | 91 | #endif 92 | 93 | 94 | -------------------------------------------------------------------------------- /backup/mlfq/mlfq.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | 5 | #This function is to print usage of this script 6 | def usage(): 7 | sys.stderr.write('mlfq.py [nodes] [data] [queues]\n') 8 | 9 | #This function is to calculate FCT for a TCP flow 10 | def fct(file): 11 | fp = open(file) 12 | start='' 13 | end='' 14 | while True: 15 | line=fp.readline() 16 | if not line: 17 | break 18 | if len(start)==0 and not '0.00000' in line and 'cwnd' in line: 19 | start=line 20 | if len(start)>0: 21 | end=line 22 | fp.close() 23 | starttime=start.split()[0] 24 | endtime=end.split()[0] 25 | return float(endtime)-float(starttime) 26 | 27 | if len(sys.argv)==4: 28 | ns_path='/home/wei/ns-allinone-2.34/ns-2.34/ns' 29 | tcl_path='/home/wei/mlfq/mlfq-test.tcl' 30 | nodes=sys.argv[1] 31 | data=sys.argv[2] 32 | queues=sys.argv[3] 33 | os.system('rm ./tcp_flow -r\n') 34 | os.system('mkdir tcp_flow') 35 | cmd=ns_path+' '+tcl_path+' '+nodes+' '+data+' '+queues 36 | os.system(cmd) 37 | 38 | fcts=0.0 39 | flows=0 40 | #Get FCT results 41 | for file in os.listdir("./tcp_flow"): 42 | fcts=fcts+fct('./tcp_flow/'+file) 43 | flows=flows+1 44 | print fcts/flows 45 | 46 | else: 47 | usage() 48 | -------------------------------------------------------------------------------- /backup/mlfq/result.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | 5 | #This function is to print usage of this script 6 | def usage(): 7 | sys.stderr.write('result.py [file]\n') 8 | 9 | #Return a normalized time 10 | #pkt: number of packets in this flow 11 | #time: absolute time 12 | def fct(pkt,time): 13 | opt=0.0 14 | if pkt<=12: 15 | opt=0.000082+pkt*0.0000012 16 | elif pkt<=36: 17 | opt=2*0.000082+(pkt-12)*0.0000012 18 | elif pkt<=84: 19 | opt=3*0.000082+(pkt-36)*0.0000012 20 | else: 21 | opt=3*0.000082+(pkt-84)*0.0000012 22 | return time/opt 23 | 24 | #Get average FCT 25 | def avg(flows): 26 | sum=0.0 27 | for f in flows: 28 | sum=sum+f 29 | return sum/len(flows) 30 | 31 | #GET mean FCT 32 | def mean(flows): 33 | flows.sort() 34 | return flows[50*len(flows)/100] 35 | 36 | #GET 99% FCT 37 | def max(flows): 38 | flows.sort() 39 | return flows[95*len(flows)/100-1] 40 | 41 | 42 | if len(sys.argv)==2: 43 | file=sys.argv[1] 44 | 45 | #All the flows 46 | flows=[] 47 | 48 | #Mice flows (0,10KB) 49 | mice_flows=[] 50 | #Short flows (10KB,100KB) 51 | short_flows=[] 52 | #Large flows (10MB,) 53 | large_flows=[] 54 | #Median flows (100KB, 10MB) 55 | median_flows=[] 56 | #The number of total timeouts 57 | timeouts=0 58 | 59 | fp = open(file) 60 | #Get overall average normalized FCT 61 | while True: 62 | line=fp.readline() 63 | if not line: 64 | break 65 | pkt_size=int(float(line.split()[0])) 66 | byte_size=float(pkt_size)*1460 67 | time=float(line.split()[1]) 68 | result=fct(pkt_size,time) 69 | if result<1: 70 | print str(pkt_size)+" "+str(result) 71 | flows.append(result) 72 | 73 | #If there are TCP timeouts 74 | if int(line.split()[2])>0: 75 | #print line.split()[2] 76 | #timeouts+=1 77 | timeouts+=int(line.split()[2]) 78 | 79 | #If the flow is a mice flow (0, 10KB) 80 | if byte_size<=10*1000: 81 | mice_flows.append(result) 82 | #If the flow is a short flow (10KB,100KB) 83 | elif byte_size<=100*1000: 84 | short_flows.append(result) 85 | #If the flow is a median flow (100KB,10MB) 86 | elif byte_size<=10*1000*1000: 87 | median_flows.append(result) 88 | #If the flow is a large flow (10MB,) 89 | else: 90 | large_flows.append(result) 91 | 92 | fp.close() 93 | print "There are "+str(len(flows))+" flows in total" 94 | print "There are "+str(timeouts)+" TCP timeouts in total" 95 | print "Overall average normalized FCT: "+str(avg(flows)) 96 | print "Average normalized FCT (0,10KB): "+str(len(mice_flows))+" flows "+str(avg(mice_flows)) 97 | print "95th percentile normalized FCT (0,10KB): "+str(max(mice_flows)) 98 | print "Average normalized FCT (10KB,100KB): "+str(len(short_flows))+" flows "+str(avg(short_flows)) 99 | print "95th percentile normalized FCT (10KB, 100KB): "+str(max(short_flows)) 100 | print "Average normalized FCT (100KB,10MB): "+str(len(median_flows))+" flows "+str(avg(median_flows)) 101 | print "95th percentile normalized FCT (100KB, 10MB): "+str(max(median_flows)) 102 | print "Average normalized FCT (10MB,): "+str(len(large_flows))+" flows "+str(avg(large_flows)) 103 | print "95th percentile normalized FCT (10MB,): "+str(max(large_flows)) 104 | -------------------------------------------------------------------------------- /backup/mlfq/result2.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | 5 | #This function is to print usage of this script 6 | def usage(): 7 | sys.stderr.write('result.py [file]\n') 8 | 9 | #Return a normalized time 10 | #pkt: number of packets in this flow 11 | #time: absolute time 12 | def fct(pkt,time): 13 | opt=pkt*0.0000012 14 | return time/opt 15 | 16 | #Get average FCT 17 | def avg(flows): 18 | sum=0.0 19 | for f in flows: 20 | sum=sum+f 21 | return sum/len(flows) 22 | 23 | #GET mean FCT 24 | def mean(flows): 25 | flows.sort() 26 | return flows[50*len(flows)/100] 27 | 28 | #GET 99% FCT 29 | def max(flows): 30 | flows.sort() 31 | return flows[99*len(flows)/100] 32 | 33 | 34 | if len(sys.argv)==2: 35 | file=sys.argv[1] 36 | 37 | #All the flows 38 | flows=[] 39 | #Short flows (0,100KB) 40 | short_flows=[] 41 | #Large flows (10MB,) 42 | large_flows=[] 43 | #Median flows (100KB, 10MB) 44 | median_flows=[] 45 | #The number of total timeouts 46 | timeouts=0 47 | 48 | fp = open(file) 49 | #Get overall average normalized FCT 50 | while True: 51 | line=fp.readline() 52 | if not line: 53 | break 54 | pkt_size=int(float(line.split()[0])) 55 | byte_size=float(pkt_size)*1460 56 | time=float(line.split()[1]) 57 | result=fct(pkt_size,time) 58 | if result<1: 59 | print str(pkt_size)+" "+str(result) 60 | flows.append(result) 61 | 62 | #If there are TCP timeouts 63 | if int(line.split()[2])>0: 64 | #print line.split()[2] 65 | #timeouts+=1 66 | timeouts+=int(line.split()[2]) 67 | 68 | #If the flow is a short flow 69 | if byte_size<100*1024: 70 | short_flows.append(result) 71 | #If the flow is a large flow 72 | elif byte_size>10*1024*1024: 73 | large_flows.append(result) 74 | else: 75 | median_flows.append(result) 76 | 77 | fp.close() 78 | print "There are "+str(len(flows))+" flows in total" 79 | print "There are "+str(timeouts)+" TCP timeouts in total" 80 | print "Overall average normalized FCT: "+str(avg(flows)) 81 | print "Average normalized FCT (0,100KB): "+str(len(short_flows))+" flows "+str(avg(short_flows)) 82 | print "99th percentile normalized FCT (0, 100KB): "+str(max(short_flows)) 83 | print "Average normalized FCT (100KB,10MB): "+str(len(median_flows))+" flows "+str(avg(median_flows)) 84 | print "99th percentile normalized FCT (100KB, 10MB): "+str(max(median_flows)) 85 | print "Average normalized FCT (10MB,): "+str(len(large_flows))+" flows "+str(avg(large_flows)) 86 | print "99th percentile normalized FCT (10MB,): "+str(max(large_flows)) 87 | -------------------------------------------------------------------------------- /backup/mlfq/result3.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | 5 | #This function is to print usage of this script 6 | def usage(): 7 | sys.stderr.write('result.py [file]\n') 8 | 9 | #Return a optimal time for this flow 10 | #pkt: number of packets in this flow 11 | def optimal(pkt): 12 | opt=0.0 13 | if pkt<=12: 14 | opt=0.0000804+pkt*0.0000012 15 | elif pkt<=36: 16 | opt=2*0.0000804+(pkt-12)*0.0000012 17 | elif pkt<=84: 18 | opt=3*0.0000804+(pkt-36)*0.0000012 19 | else: 20 | opt=3*0.0000804+(pkt-84)*0.0000012 21 | return opt 22 | 23 | #pkt: number of packets in this flow 24 | #time: absolute time 25 | def fct(pkt,time): 26 | return time*1000 27 | #return time/opt 28 | 29 | #Get average FCT 30 | def avg(flows): 31 | sum=0.0 32 | for f in flows: 33 | sum=sum+f 34 | return sum/len(flows) 35 | 36 | #GET mean FCT 37 | def mean(flows): 38 | flows.sort() 39 | return flows[50*len(flows)/100] 40 | 41 | #GET 99% FCT 42 | def max(flows): 43 | flows.sort() 44 | return flows[99*len(flows)/100] 45 | 46 | 47 | if len(sys.argv)==2: 48 | file=sys.argv[1] 49 | 50 | #All the flows 51 | flows=[] 52 | #Short flows (0,100KB) 53 | short_flows=[] 54 | #Large flows (10MB,) 55 | large_flows=[] 56 | #Median flows (100KB, 10MB) 57 | median_flows=[] 58 | #The number of total timeouts 59 | timeouts=0 60 | 61 | fp = open(file) 62 | #Get overall average normalized FCT 63 | while True: 64 | line=fp.readline() 65 | if not line: 66 | break 67 | pkt_size=int(float(line.split()[0])) 68 | byte_size=float(pkt_size)*1460 69 | time=float(line.split()[1]) 70 | result=fct(pkt_size,time) 71 | #if result<1: 72 | # print str(pkt_size)+" "+str(result) 73 | flows.append(result) 74 | 75 | #If there are TCP timeouts 76 | if int(line.split()[2])>0: 77 | #print line.split()[2] 78 | #timeouts+=1 79 | timeouts+=int(line.split()[2]) 80 | 81 | #If the flow is a short flow 82 | if byte_size<100*1000: 83 | short_flows.append(result) 84 | #If the flow is a large flow 85 | elif byte_size>10*1000*1000: 86 | large_flows.append(result) 87 | else: 88 | median_flows.append(result) 89 | 90 | fp.close() 91 | print "There are "+str(len(flows))+" flows in total" 92 | print "There are "+str(timeouts)+" TCP timeouts in total" 93 | print "Overall average FCT: "+str(avg(flows)) 94 | print "Average FCT (0,100KB): "+str(len(short_flows))+" flows "+str(avg(short_flows)) 95 | print "Average FCT (100KB,10MB): "+str(len(median_flows))+" flows "+str(avg(median_flows)) 96 | print "Average FCT (10MB,): "+str(len(large_flows))+" flows "+str(avg(large_flows)) 97 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/CDF_dctcp.txt: -------------------------------------------------------------------------------- 1 | 6 0 2 | 6 0.15 3 | 13 0.2 4 | 19 0.3 5 | 33 0.4 6 | 53 0.53 7 | 133 0.6 8 | 667 0.7 9 | 1333 0.8 10 | 3333 0.9 11 | 6667 0.97 12 | 20000 1 13 | 14 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/CDF_vl2.txt: -------------------------------------------------------------------------------- 1 | 1 0 2 | 1 0.5 3 | 2 0.6 4 | 3 0.7 5 | 7 0.8 6 | 267 0.9 7 | 2107 0.95 8 | 66667 0.99 9 | 666667 1 10 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -pthread 3 | TARGETS = server client 4 | 5 | all: $(TARGETS) 6 | 7 | server: 8 | $(CC) $(CFLAGS) server.c -o server.o 9 | 10 | client: 11 | $(CC) $(CFLAGS) client.c -o client.o 12 | 13 | clean: 14 | rm client.o server.o 15 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define RECV_BUFSIZ 65536 //size of receive buffer 12 | 13 | //Print usage information 14 | void usage(char *program); 15 | 16 | int main(int argc, char **argv) 17 | { 18 | char server[16] = {'\0'}; //IP address (e.g. 192.168.101.101) 19 | int port; //TCP port number 20 | int data_size; //Request data size (KB) 21 | struct timeval tv_start; //Start time (after three way handshake) 22 | struct timeval tv_end; //End time 23 | int sockfd; //Socket 24 | struct sockaddr_in servaddr; //Server address (IP:Port) 25 | int len; //Read length 26 | char buf[RECV_BUFSIZ]; //Receive buffer 27 | int write_count = 0; //total number of bytes to write 28 | int read_count = 0; //total number of bytes received 29 | unsigned long fct; //Flow Completion Time 30 | 31 | if (argc != 4) 32 | { 33 | usage(argv[0]); 34 | return 0; 35 | } 36 | 37 | //Get server address 38 | strncpy(server, argv[1], 15); 39 | //Get TCP port: char* to int 40 | port = atoi(argv[2]); 41 | //Get data_size: char* to int 42 | data_size = atoi(argv[3]); 43 | 44 | //Init server address 45 | memset(&servaddr, 0, sizeof(servaddr)); 46 | servaddr.sin_family = AF_INET; 47 | servaddr.sin_addr.s_addr = inet_addr(server); 48 | servaddr.sin_port = htons(port); 49 | 50 | //Init socket 51 | if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 52 | { 53 | perror("Socket error\n"); 54 | return 0; 55 | } 56 | 57 | //Establish connection 58 | if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0) 59 | { 60 | printf("Can not connect to %s\n", server); 61 | return 0; 62 | } 63 | 64 | //Get start time after connection establishment 65 | gettimeofday(&tv_start,NULL); 66 | 67 | //Send request 68 | write_count = strlen(argv[3]); 69 | while (write_count > 0) 70 | write_count -= send(sockfd, argv[3], write_count, 0); 71 | 72 | //Receive data 73 | while(1) 74 | { 75 | len = recv(sockfd, buf, RECV_BUFSIZ, 0); 76 | read_count += len; 77 | 78 | if(len <= 0) 79 | break; 80 | } 81 | 82 | //Get end time after receiving all of the data 83 | gettimeofday(&tv_end,NULL); 84 | //Close connection 85 | close(sockfd); 86 | 87 | //Calculate time interval (unit: microsecond) 88 | fct = (tv_end.tv_sec - tv_start.tv_sec) * 1000000 + tv_end.tv_usec - tv_start.tv_usec; 89 | 90 | if (data_size * 1024 == read_count) 91 | printf("From %s: %d KB %lu us\n", server, data_size, fct); 92 | else 93 | printf("We receive %d (of %d) bytes.\n", read_count, data_size * 1024); 94 | 95 | return 0; 96 | } 97 | 98 | 99 | void usage(char *program) 100 | { 101 | printf("%s [server IP] [server port] [request flow size(KB)]\n", program); 102 | } 103 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/dynamic_flow.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | import time 5 | import random 6 | import math 7 | import threading 8 | 9 | #This function is to print usage of this script 10 | def usage(): 11 | sys.stderr.write('This script is used for dynamic flow emulation:\n') 12 | sys.stderr.write('dynamic_flow.py [host file] [trace file] [result file] \n') 13 | 14 | class FlowThread(threading.Thread): 15 | def __init__(self, host, size, id): 16 | self.host=host 17 | self.size=size 18 | self.id=id 19 | threading.Thread.__init__(self) 20 | 21 | def run(self): 22 | #By default, we use port number of 5001 23 | line=os.popen('./client.o '+str(self.host)+' '+str(5001)+' '+str(self.size)).read() 24 | result=line.split() 25 | if len(result)>=2: 26 | #Get FCT for this flow and save it into global variable fcts 27 | fct=int(result[len(result)-2]) 28 | fcts[self.id]=fct 29 | 30 | #main function 31 | if len(sys.argv)!=4: 32 | usage() 33 | else: 34 | host_filename=sys.argv[1] 35 | trace_filename=sys.argv[2] 36 | result_filename=sys.argv[3] 37 | 38 | #Get hosts from host file 39 | hosts=[] 40 | host_file=open(host_filename,'r') 41 | lines=host_file.readlines() 42 | for line in lines: 43 | hosts.append(line.strip('\n')) 44 | host_file.close() 45 | 46 | #Flow Completion Time 47 | global fcts 48 | fcts=[] 49 | #Sleep Interval 50 | times=[] 51 | #Flow Size 52 | flows=[] 53 | #Sender IP 54 | senders=[] 55 | 56 | #Get trace from trace file 57 | traces=[] 58 | trace_file=open(trace_filename,'r') 59 | traces=trace_file.readlines() 60 | 61 | for i in range(len(traces)): 62 | tmp=traces[i].split() 63 | if len(tmp)==3: 64 | times.append(float(tmp[0])) 65 | flows.append(int(tmp[1])) 66 | senders.append(hosts[int(tmp[2])]) 67 | fcts.append(0) 68 | 69 | #Start emulation 70 | raw_input('Press any key to start emulation') 71 | 72 | for i in range(len(flows)): 73 | #Get next time interval (sleep time) 74 | sleeptime=times[i] 75 | #Get sender IP address 76 | host=senders[i] 77 | #Sleep 78 | time.sleep(sleeptime/1000) 79 | #Start thread to send traffic 80 | newthread=FlowThread(host,flows[i],i) 81 | newthread.start() 82 | 83 | #Stop emulation 84 | raw_input('Press any key to stop emulation') 85 | 86 | #Analyze FCT results 87 | tiny_fcts=[] 88 | short_fcts=[] 89 | long_fcts=[] 90 | 91 | #Write FCT results into the file 92 | result_file=open(result_filename,'w') 93 | for i in range(len(flows)): 94 | #If flow size is smaller than 10KB 95 | if flows[i]<=10: 96 | tiny_fcts.append(fcts[i]) 97 | #If flow size is in (10KB,100KB) 98 | elif flows[i]<=100: 99 | short_fcts.append(fcts[i]) 100 | #If flow size is larger than 10MB 101 | elif flows[i]>=10000: 102 | long_fcts.append(fcts[i]) 103 | 104 | result_file.write(str(flows[i])+' KB '+str(fcts[i])+' us\n') 105 | result_file.close() 106 | 107 | if len(tiny_fcts)>0: 108 | print 'There are '+str(len(tiny_fcts))+' flows in (0,10KB). Their average FCT is '+str(sum(tiny_fcts)/len(tiny_fcts))+' us' 109 | if len(short_fcts)>0: 110 | print 'There are '+str(len(short_fcts))+' flows in (10KB,100KB). Their average FCT is '+str(sum(short_fcts)/len(short_fcts))+' us' 111 | if len(long_fcts)>0: 112 | print 'There are '+str(len(long_fcts))+' flows in (10MB,). Their average FCT is '+str(sum(long_fcts)/len(long_fcts))+' us' 113 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/generator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | import time 5 | import random 6 | import math 7 | 8 | #This function is to print usage of this script 9 | def usage(): 10 | sys.stderr.write('This script is used to generate dynamic flow workloads:\n') 11 | sys.stderr.write('generator.py [traffic distribution file] [load] [link capacity (Mbps)] [flow number] [host number] [output file]\n') 12 | 13 | #http://preshing.com/20111007/how-to-generate-random-timings-for-a-poisson-process/ 14 | #Return next time interval (ms) 15 | def nextTime(rateParameter): 16 | #We use round function to get a integer 17 | return round(-math.log(1.0 - random.random()) / rateParameter) 18 | 19 | #Given a flow distribution and a random number in (0,1), return a flow size (KB) 20 | def flowsize(distribution, random): 21 | i=0 22 | for var in distribution: 23 | if var[0]>random: 24 | x1=distribution[i-1][0] 25 | x2=distribution[i][0] 26 | y1=distribution[i-1][1] 27 | y2=distribution[i][1] 28 | value=int(((y2-y1)/(x2-x1)*random+(x2*y1-x1*y2)/(x2-x1))*1448/1024) 29 | return value 30 | elif var[0]==random: 31 | return int(var[1]*1448/1024) 32 | else: 33 | i=i+1 34 | #By default, return 0 35 | return 0 36 | 37 | #main function 38 | if len(sys.argv)!=7: 39 | usage() 40 | else: 41 | traffic_filename=sys.argv[1] 42 | load=float(sys.argv[2]) 43 | capacity=float(sys.argv[3]) 44 | flow_num=int(sys.argv[4]) 45 | host_num=int(sys.argv[5]) 46 | output_filename=sys.argv[6] 47 | 48 | #Initialize flow distribution 49 | distribution=[] 50 | #Get traffic distribution line by line from input file 51 | traffic_file=open(traffic_filename,'r') 52 | lines=traffic_file.readlines() 53 | i=0 54 | for line in lines: 55 | tmp=line.split() 56 | if len(tmp)>=2: 57 | distribution.append([float(tmp[1]),float(tmp[0])]) 58 | i=i+1 59 | traffic_file.close() 60 | 61 | #Generate flow size 62 | flows=[] 63 | for i in range(flow_num): 64 | flows.append(flowsize(distribution,random.random())) 65 | 66 | #Get average throughput 67 | throughput=load*capacity 68 | #Get average flow size 69 | avg=sum(flows)/len(flows) 70 | #Get average number of requests per second 71 | num=throughput*1024*1024/(avg*1024*8) 72 | #Get average request rate (number of requests every 1 ms) 73 | rate=num/1000 74 | 75 | #Generate time interval 76 | times=[] 77 | for i in range(flow_num): 78 | #Get time interval (sleep time) 79 | times.append(nextTime(rate)) 80 | 81 | #Write trace results into output file 82 | #Trace format: time_interval flow_size host_id 83 | output_file=open(output_filename,'w') 84 | start=random.randint(0,host_num-1) 85 | for i in range(flow_num): 86 | output_file.write(str(times[i])+' '+str(flows[i])+' '+str(start)+'\n') 87 | start=(start+1)%host_num 88 | output_file.close() 89 | 90 | print 'Auto generate '+str(len(flows))+' flows:' 91 | print 'The average flow size: '+str(avg)+' KB' 92 | print 'The average request speed: '+str(num)+' requests/second' 93 | print 'Dynamic flow emulation will last for about '+str(len(flows)/num)+' seconds' 94 | print 'Done' 95 | 96 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/host.txt: -------------------------------------------------------------------------------- 1 | 192.168.101.2 2 | 192.168.101.3 3 | 192.168.101.4 4 | 192.168.101.5 5 | 192.168.101.6 6 | 192.168.101.7 7 | 192.168.101.8 8 | 192.168.101.9 9 | 192.168.101.10 10 | 192.168.101.11 11 | 192.168.101.12 12 | 192.168.101.13 13 | 192.168.101.14 14 | 192.168.101.15 15 | 192.168.101.16 -------------------------------------------------------------------------------- /backup/pias/dynamic workload/memcached_dynamic_flow.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | import time 5 | import random 6 | import math 7 | import threading 8 | 9 | #This function is to print usage of this script 10 | def usage(): 11 | sys.stderr.write('This script is to generate memcached benchmark with backrgound traffic:\n') 12 | sys.stderr.write('dynamic_flow.py [host file] [backrgound trace file] [memcached query rate (number per second)] [result file] \n') 13 | 14 | #Memcached query thread 15 | class QueryThread(threading.Thread): 16 | def __init__(self): 17 | threading.Thread.__init__(self) 18 | 19 | def run(self): 20 | #By default, we have 15 memcached servers 21 | line=os.popen('./query.o 15').read() 22 | result=line.split() 23 | if len(result)>=2: 24 | #Get GCT (Group Completion Time) for this query and save it into global variable gcts 25 | gct=int(result[1]) 26 | gcts.append(gct) 27 | 28 | #Background flow thread 29 | class FlowThread(threading.Thread): 30 | def __init__(self, host, size, id): 31 | self.host=host 32 | self.size=size 33 | self.id=id 34 | threading.Thread.__init__(self) 35 | 36 | def run(self): 37 | #By default, we use port number of 5001. We don't need to get FCT for backrgound traffic 38 | line=os.popen('./client.o '+str(self.host)+' '+str(5001)+' '+str(self.size)).read() 39 | 40 | #main function 41 | if len(sys.argv)!=5: 42 | usage() 43 | else: 44 | host_filename=sys.argv[1] 45 | trace_filename=sys.argv[2] 46 | rate=int(sys.argv[3]) 47 | result_filename=sys.argv[4] 48 | 49 | #Get average time interval (ms) for query 50 | avg_interval=1000.0/rate; 51 | #Init number of queries in this emulation 52 | query_num=0 53 | #We maintain a currnet_interval for query. Once we find currnet_interval is larger than avg_interval, we will generate query. 54 | current_interval=0 55 | 56 | #Get hosts from host file 57 | hosts=[] 58 | host_file=open(host_filename,'r') 59 | lines=host_file.readlines() 60 | for line in lines: 61 | hosts.append(line.strip('\n')) 62 | host_file.close() 63 | 64 | #Maximum number of queries in an emulation 65 | max_query_num=1000 66 | #Group Completion Time 67 | global gcts 68 | gcts=[] 69 | 70 | #Sleep Interval 71 | times=[] 72 | #Flow Size 73 | flows=[] 74 | #Sender IP 75 | senders=[] 76 | 77 | #Get trace from trace file 78 | traces=[] 79 | trace_file=open(trace_filename,'r') 80 | traces=trace_file.readlines() 81 | 82 | for i in range(len(traces)): 83 | tmp=traces[i].split() 84 | if len(tmp)==3: 85 | times.append(float(tmp[0])) 86 | flows.append(int(tmp[1])) 87 | senders.append(hosts[int(tmp[2])]) 88 | 89 | #Start emulation 90 | raw_input('Press any key to start emulation') 91 | 92 | for i in range(len(flows)): 93 | #Get next time interval (sleep time) 94 | sleeptime=times[i] 95 | #Get sender IP address 96 | host=senders[i] 97 | #Sleep 98 | time.sleep(sleeptime/1000) 99 | #Start thread to send traffic 100 | newthread=FlowThread(host,flows[i],i) 101 | newthread.start() 102 | 103 | if query_numavg_interval: 107 | #Generate query 108 | query=QueryThread() 109 | query.start() 110 | #Update related variables for next query generatation 111 | query_num=query_num+1 112 | current_interval=current_interval-avg_interval 113 | 114 | #Stop emulation 115 | raw_input('Press any key to stop emulation') 116 | 117 | #Write GCT results into the file 118 | result_file=open(result_filename,'w') 119 | for gct in gcts: 120 | result_file.write(str(gct)+'\n') 121 | result_file.close() 122 | 123 | gcts.sort() 124 | if len(gcts)>0: 125 | print 'We generate '+str(len(gcts))+' queries in total \n' 126 | print 'The average GCT is '+str(sum(gcts)/len(gcts))+' us\n' 127 | print 'The 99th GCT is '+str(gcts[99*len(gcts)/100-1])+ 'us\n' 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/result.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | 5 | #This function is to print usage of this script 6 | def usage(): 7 | sys.stderr.write('This script is used to analyze FCT of dynamic flow workloads for PIAS project:\n') 8 | sys.stderr.write('result.py [result file]\n') 9 | 10 | #main function 11 | if len(sys.argv)!=2: 12 | usage() 13 | else: 14 | #Open file 15 | filename=sys.argv[1] 16 | file=open(filename,'r') 17 | lines=file.readlines() 18 | 19 | #Initialize variables 20 | fcts=[] 21 | tiny_fcts=[] #0-10KB 22 | short_fcts=[] #10KB-100KB 23 | median_fcts=[] #100KB-10MB 24 | long_fcts=[] #10MB- 25 | 26 | for line in lines: 27 | result=line.split() 28 | if len(result)==4: 29 | size=int(result[0]) 30 | fct=int(result[2]) 31 | if fct>0: 32 | fcts.append(fct) 33 | if size<=10: 34 | tiny_fcts.append(fct) 35 | elif size<=100: 36 | short_fcts.append(fct) 37 | elif size<=10000: 38 | median_fcts.append(fct) 39 | else: 40 | long_fcts.append(fct) 41 | 42 | #Close file 43 | file.close() 44 | tiny_fcts.sort() 45 | short_fcts.sort() 46 | 47 | if len(tiny_fcts)>0: 48 | print 'There are '+str(len(tiny_fcts))+' flows in (0,10KB). Their average FCT is '+str(sum(tiny_fcts)/len(tiny_fcts))+' us. Their 99th FCT is '+str(tiny_fcts[int(0.99*len(tiny_fcts)-1)])+' us' 49 | if len(short_fcts)>0: 50 | print 'There are '+str(len(short_fcts))+' flows in (10KB,100KB). Their average FCT is '+str(sum(short_fcts)/len(short_fcts))+' us. Their 99th FCT is '+str(short_fcts[int(0.99*len(short_fcts)-1)])+' us' 51 | if len(median_fcts)>0: 52 | print 'There are '+str(len(median_fcts))+' flows in (100KB,10MB). Their average FCT is '+str(sum(median_fcts)/len(median_fcts))+' us' 53 | if len(long_fcts)>0: 54 | print 'There are '+str(len(long_fcts))+' flows in (10MB,). Their average FCT is '+str(sum(long_fcts)/len(long_fcts))+' us' 55 | if len(fcts)>0: 56 | print 'There are '+str(len(fcts))+' flows in total. Their average FCT is '+str(sum(fcts)/len(fcts))+' us' -------------------------------------------------------------------------------- /backup/pias/dynamic workload/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SEND_BUFSIZ 65536 //size of send buffer 14 | 15 | //Start TCP server 16 | void start_server(int port); 17 | //Function to deal with an incoming connection 18 | void* server_thread_func(void* client_sockfd_ptr); 19 | //Print usage information 20 | void usage(char *program); 21 | 22 | int main(int argc, char **argv) 23 | { 24 | if (argc != 2) 25 | { 26 | usage(argv[0]); 27 | return 0; 28 | } 29 | 30 | start_server(atoi(argv[1])); 31 | return 0; 32 | } 33 | 34 | void usage(char *program) 35 | { 36 | printf("%s [port]\n", program); 37 | } 38 | 39 | void start_server(int port) 40 | { 41 | //Socket for server 42 | int server_sockfd; 43 | //Socket pointer for client 44 | int* client_sockfd_ptr = NULL; 45 | //A thread to deal with client_sockfd 46 | pthread_t server_thread; 47 | //Server address 48 | struct sockaddr_in server_addr; 49 | //Client address 50 | struct sockaddr_in client_addr; 51 | int sock_opt = 1; 52 | socklen_t sin_size = sizeof(struct sockaddr_in); 53 | 54 | //Initialize server address (0.0.0.0:port) 55 | memset(&server_addr, 0, sizeof(server_addr)); 56 | server_addr.sin_family = AF_INET; 57 | server_addr.sin_addr.s_addr = INADDR_ANY; 58 | server_addr.sin_port = htons(port); 59 | 60 | //Init socket 61 | if ((server_sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 62 | { 63 | perror("socket error"); 64 | return; 65 | } 66 | 67 | //Set socket options 68 | if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &sock_opt, sizeof(sock_opt)) < 0) 69 | { 70 | perror("Error: set SO_REUSEADDR option"); 71 | return; 72 | } 73 | if (setsockopt(server_sockfd, IPPROTO_TCP, TCP_NODELAY, &sock_opt, sizeof(sock_opt)) < 0) 74 | { 75 | perror("ERROR: set TCP_NODELAY option"); 76 | return; 77 | } 78 | 79 | //Bind socket on IP:Port 80 | if (bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0) 81 | { 82 | perror("bind error"); 83 | return; 84 | } 85 | 86 | //Start listen 87 | listen(server_sockfd, SOMAXCONN); 88 | 89 | while (1) 90 | { 91 | client_sockfd_ptr = (int*)malloc(sizeof(int)); 92 | if (!client_sockfd_ptr) 93 | { 94 | perror("malloc error"); 95 | return; 96 | } 97 | 98 | int value = accept(server_sockfd, (struct sockaddr *)&client_addr, &sin_size); 99 | if (value < 0) 100 | { 101 | perror("accept error"); 102 | free(client_sockfd_ptr); 103 | return; 104 | } 105 | 106 | *client_sockfd_ptr = value; 107 | if (pthread_create(&server_thread, NULL , server_thread_func, (void*)client_sockfd_ptr) < 0) 108 | { 109 | perror("could not create thread"); 110 | return; 111 | } 112 | } 113 | } 114 | 115 | void* server_thread_func(void* client_sockfd_ptr) 116 | { 117 | int sock = *(int*)client_sockfd_ptr; 118 | char write_message[SEND_BUFSIZ] = {1}; 119 | char read_message[64] = {'\0'}; 120 | int len; 121 | int data_size; 122 | 123 | free(client_sockfd_ptr); 124 | 125 | len = recv(sock, read_message, 64, 0); 126 | if (len <= 0) 127 | { 128 | close(sock); 129 | return((void *)0); 130 | } 131 | 132 | //Get data volume (Unit:KB) 133 | data_size = atoi(read_message) * 1024; 134 | while (data_size > 0) 135 | { 136 | len = (SEND_BUFSIZ < data_size)? SEND_BUFSIZ : data_size; 137 | data_size -= send(sock, write_message, len, 0); 138 | } 139 | 140 | close(sock); 141 | return((void *)0); 142 | } 143 | -------------------------------------------------------------------------------- /backup/pias/dynamic workload/static_flow.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | import time 5 | import threading 6 | 7 | #Static flow workloads: 8 | #Sender 1 and Sender 2 to the Receiver: large flows of 10MB following dependent/sequential pattern 9 | #Sender 3 to the Receiver: small flows of 20KB following dependent/sequential pattern 10 | 11 | #This function is to print usage of this script 12 | def usage(): 13 | sys.stderr.write('This script is used to generate static flow workloads for PIAS project:\n') 14 | sys.stderr.write('static_flow.py [iterations] [output]\n') 15 | 16 | class FlowThread(threading.Thread): 17 | def __init__(self, host, size, iterations,output): 18 | self.host=host 19 | self.size=size 20 | self.iterations=iterations 21 | self.output=output 22 | threading.Thread.__init__(self) 23 | 24 | def run(self): 25 | fcts=[] 26 | for i in range(self.iterations): 27 | #If the flow size is smaller than 1MB, we believe this is a short flow and sleep for 10ms 28 | if self.size<1024*1024: 29 | time.sleep(10/1000) 30 | #By default, we use port number of 5001 31 | line=os.popen('./client.o '+str(self.host)+' '+str(5001)+' '+str(self.size)).read() 32 | #We need to get FCT results for this thread 33 | if len(self.output)>0: 34 | result=line.split() 35 | if len(result)>=2: 36 | #Get FCT for this flow and save it into global variable fcts 37 | fct=int(result[len(result)-2]) 38 | fcts.append(fct) 39 | #Get final results 40 | if len(fcts)>0: 41 | #Sort FCT from low to high 42 | fcts.sort() 43 | #Write FCT results into the file 44 | result_file=open(self.output,'w') 45 | for i in range(len(fcts)): 46 | result_file.write(str(fcts[i])+'\n') 47 | result_file.close() 48 | avg=sum(fcts)/len(fcts) 49 | tail=fcts[len(fcts)*99/100-1] 50 | print 'Avg FCT: '+str(avg)+' us\n' 51 | print '99th FCT: '+str(tail)+' us\n' 52 | 53 | #main function 54 | if len(sys.argv)==3: 55 | iterations=int(sys.argv[1]) 56 | filename=sys.argv[2] 57 | 58 | #20KB 59 | small_flow=20 60 | #10MB 61 | large_flow=10*1024 62 | 63 | #Senders 64 | sender1='192.168.101.2' 65 | sender2='192.168.101.3' 66 | sender3='192.168.101.4' 67 | 68 | #Init three threads for emulation 69 | thread1=FlowThread(sender1,large_flow,iterations,'') 70 | thread2=FlowThread(sender2,large_flow,iterations,'') 71 | thread3=FlowThread(sender3,small_flow,iterations,filename) 72 | 73 | #Start three threads 74 | thread1.start() 75 | thread2.start() 76 | thread3.start() 77 | 78 | #Wait for three threads 79 | thread3.join() 80 | thread2.join() 81 | thread1.join() 82 | 83 | else: 84 | usage() -------------------------------------------------------------------------------- /backup/pias/dynamic workload/trace.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | 5 | #This function is to print usage of this script 6 | def usage(): 7 | sys.stderr.write('This script is used to analyze dynamic flow trace:\n') 8 | sys.stderr.write('dynamic_flow.py [trace file] [percentage] \n') 9 | 10 | #main function 11 | if len(sys.argv)!=3: 12 | usage() 13 | else: 14 | trace_filename=sys.argv[1] 15 | percentage=float(sys.argv[2]) 16 | #Open trace file 17 | trace_file=open(trace_filename,'r') 18 | lines=trace_file.readlines() 19 | flows=[] 20 | for line in lines: 21 | tmp=line.split() 22 | if len(tmp)>=3: 23 | flows.append(int(tmp[1])) 24 | trace_file.close() 25 | flows.sort() 26 | sum=sum(flows) 27 | size=0 28 | for i in range(int(len(flows)*percentage)): 29 | size=size+flows[i] 30 | print 'The '+str(int(percentage*100))+'th flow in our trace is '+str(flows[int(len(flows)*percentage)-1])+'KB' 31 | print float(size)/sum 32 | print (float(size)+flows[int(len(flows)*percentage)-1]*(len(flows)-int(len(flows)*percentage)))/sum -------------------------------------------------------------------------------- /backup/pias/incast applications/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | //Host list. In our experiment, we have 15 physical machines as senders. 14 | #define max_hosts 15 15 | char* hosts[max_hosts]={ 16 | "192.168.101.2", 17 | "192.168.101.3", 18 | "192.168.101.4", 19 | "192.168.101.5", 20 | "192.168.101.6", 21 | "192.168.101.7", 22 | "192.168.101.8", 23 | "192.168.101.9", 24 | "192.168.101.10", 25 | "192.168.101.11", 26 | "192.168.101.12", 27 | "192.168.101.13", 28 | "192.168.101.14", 29 | "192.168.101.15", 30 | "192.168.101.16" 31 | }; 32 | //Mutex for printf of multi-threads 33 | pthread_mutex_t mutex; 34 | 35 | //A struct for a connection 36 | struct connection 37 | { 38 | int id; 39 | int hostid; 40 | int port; 41 | int size; 42 | }; 43 | 44 | //Function to init a connection to transmit data 45 | void* client_thread_func(void* connection_ptr); 46 | 47 | //Set send window 48 | void set_send_window(int sockfd, int window); 49 | 50 | //Set receive window 51 | void set_recv_window(int sockfd, int window); 52 | 53 | //Print usage information 54 | void usage(); 55 | 56 | int main(int argc, char **argv) 57 | { 58 | int i=0; 59 | int port=5001; 60 | int data_size=0; 61 | int connections=0; 62 | //Array of struct connection 63 | struct connection* incast_connections=NULL; 64 | //Array of pthread_t 65 | pthread_t* client_threads=NULL; 66 | //Total start time 67 | struct timeval tv_start_total; 68 | //Total end time 69 | struct timeval tv_end_total; 70 | 71 | if(argc!=3) 72 | { 73 | usage(); 74 | return 0; 75 | } 76 | 77 | //Get connections: char* to int 78 | connections=atoi(argv[1]); 79 | //Get data_size: char* to int 80 | data_size=atoi(argv[2]); 81 | //Initialize 82 | incast_connections=(struct connection*)malloc(connections*sizeof(struct connection)); 83 | client_threads=(pthread_t*)malloc(connections*sizeof(pthread_t)); 84 | 85 | gettimeofday(&tv_start_total,NULL); 86 | for(i=0;ibit 1024*8 107 | float throughput=data_size*connections*1024*8.0/interval; 108 | printf("[Total] 0-%lu ms, %d KB, %.1f Mbps\n",interval/1000,data_size*connections,throughput); 109 | free(incast_connections); 110 | free(client_threads); 111 | return 0; 112 | } 113 | 114 | void* client_thread_func(void* connection_ptr) 115 | { 116 | struct connection incast_connection=*(struct connection*)connection_ptr; 117 | //Get ID 118 | int id=incast_connection.id; 119 | //Get IP address from hostid 120 | char* IPaddress=hosts[incast_connection.hostid]; 121 | //Get port 122 | int port=incast_connection.port; 123 | //Get traffic size 124 | int size=incast_connection.size; 125 | int sockfd; 126 | struct sockaddr_in servaddr; 127 | int len; 128 | char data_size[6]={0}; 129 | char buf[BUFSIZ]; 130 | struct timeval tv_start; 131 | struct timeval tv_end; 132 | 133 | //Init sockaddr_in 134 | memset(&servaddr,0,sizeof(servaddr)); 135 | servaddr.sin_family=AF_INET; 136 | //IP address 137 | servaddr.sin_addr.s_addr=inet_addr(IPaddress); 138 | //Port number 139 | servaddr.sin_port=htons(port); 140 | 141 | //Convert int to char* 142 | sprintf(data_size,"%d",size); 143 | 144 | //Init socket 145 | if((sockfd=socket(PF_INET,SOCK_STREAM,0))<0) 146 | { 147 | perror("socket error\n"); 148 | return; 149 | } 150 | 151 | //set_recv_window(sockfd, 512000); 152 | //set_send_window(sockfd, 32000); 153 | 154 | //Establish connection 155 | if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr))<0) 156 | { 157 | //Print throughput information 158 | pthread_mutex_lock(&mutex); 159 | printf("Can not connect to %s\n",IPaddress); 160 | pthread_mutex_unlock(&mutex); 161 | return((void *)0); 162 | } 163 | 164 | //Get start time 165 | gettimeofday(&tv_start,NULL); 166 | 167 | //Send Request 168 | len=send(sockfd,data_size,strlen(data_size),0); 169 | 170 | //Recv Data from Server 171 | int total=0; 172 | while(1) 173 | { 174 | len=recv(sockfd,buf,BUFSIZ,0); 175 | if(len<=0) 176 | break; 177 | } 178 | 179 | //Get end time 180 | gettimeofday(&tv_end,NULL); 181 | close(sockfd); 182 | 183 | //Time interval (unit: microsecond) 184 | unsigned long interval=(tv_end.tv_sec-tv_start.tv_sec)*1000000+(tv_end.tv_usec-tv_start.tv_usec); 185 | //KB->bit 1024*8 186 | float throughput=size*1024*8.0/interval; 187 | 188 | //Print throughput information 189 | pthread_mutex_lock(&mutex); 190 | printf("[%d] From %s 0-%lu ms, %d KB, %.1f Mbps\n",id,IPaddress,interval/1000,size,throughput); 191 | pthread_mutex_unlock(&mutex); 192 | return((void *)0); 193 | } 194 | 195 | void set_recv_window(int sockfd, int rcvbuf) 196 | { 197 | setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, sizeof(rcvbuf)); 198 | } 199 | 200 | void set_send_window(int sockfd, int sndbuf) 201 | { 202 | setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf)); 203 | } 204 | 205 | void usage() 206 | { 207 | printf("./client.o [connections] [data_size]\n"); 208 | } -------------------------------------------------------------------------------- /backup/pias/incast applications/readme.txt: -------------------------------------------------------------------------------- 1 | This application is used to generate incast pattern traffic. 2 | 3 | It consists of two parts: the client application running on the receiver and the server application running on the senders 4 | 5 | The client application can generate N requests to senders for the data of D bytes. The server application responds with requested data. 6 | 7 | Considering there are M senders, N may be larger than N. In this scenario, we try to load balance requests to senders. -------------------------------------------------------------------------------- /backup/pias/incast applications/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | //Mutex for printf of multi-threads 13 | pthread_mutex_t mutex; 14 | 15 | //Start TCP server 16 | void start_server(int port); 17 | //Function to deal with an incoming connection 18 | void* server_thread_func(void* client_sockfd_ptr); 19 | //Set send window 20 | void set_send_window(int sockfd, int window); 21 | //Print usage information 22 | void usage(); 23 | 24 | int main(int argc, char **argv) 25 | { 26 | if(argc!=2) 27 | { 28 | usage(); 29 | return 0; 30 | } 31 | start_server(atoi(argv[1])); 32 | return 0; 33 | } 34 | 35 | void usage() 36 | { 37 | printf("./server.o [port]\n"); 38 | } 39 | void start_server(int port) 40 | { 41 | //Socket for server 42 | int server_sockfd; 43 | //Socket pointer for client 44 | int* client_sockfd_ptr=NULL; 45 | //A thread to deal with client_sockfd 46 | pthread_t server_thread; 47 | //Server address 48 | struct sockaddr_in server_addr; 49 | //Client address 50 | struct sockaddr_in client_addr; 51 | 52 | memset(&server_addr,0,sizeof(server_addr)); 53 | //IP protocol 54 | server_addr.sin_family=AF_INET; 55 | //Listen on "0.0.0.0" (Any IP address of this host) 56 | server_addr.sin_addr.s_addr=INADDR_ANY; 57 | //Specify port number 58 | server_addr.sin_port=htons(port); 59 | 60 | //Init socket 61 | if((server_sockfd=socket(PF_INET,SOCK_STREAM,0))<0) 62 | { 63 | perror("socket error"); 64 | return; 65 | } 66 | 67 | //Bind socket on IP:Port 68 | if(bind(server_sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr))<0) 69 | { 70 | perror("bind error"); 71 | return; 72 | } 73 | 74 | //Start listen 75 | //The maximum number of concurrent connections is 100 76 | listen(server_sockfd,100); 77 | int sin_size=sizeof(struct sockaddr_in); 78 | 79 | while(1) 80 | { 81 | client_sockfd_ptr=(int*)malloc(sizeof(int)); 82 | int value=accept(server_sockfd,(struct sockaddr *)&client_addr,&sin_size); 83 | if(value<0) 84 | { 85 | perror("accept error"); 86 | free(client_sockfd_ptr); 87 | return; 88 | } 89 | *client_sockfd_ptr=value; 90 | if(pthread_create(&server_thread, NULL , server_thread_func, (void*)client_sockfd_ptr) < 0) 91 | { 92 | perror("could not create thread"); 93 | return; 94 | } 95 | } 96 | } 97 | 98 | void* server_thread_func(void* client_sockfd_ptr) 99 | { 100 | int i; 101 | int sock=*(int*)client_sockfd_ptr; 102 | char write_message[BUFSIZ+1]; 103 | char read_message[1024]={0}; 104 | int len; 105 | int data_size; 106 | 107 | free(client_sockfd_ptr); 108 | memset(write_message,1,BUFSIZ); 109 | write_message[BUFSIZ]='\0'; 110 | len=recv(sock,read_message,1024,0); 111 | data_size=atoi(read_message); 112 | 113 | int loop=data_size*1024/BUFSIZ; 114 | //printf("%d\n", loop); 115 | for(i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define max_hosts 15 9 | 10 | //Constant key value for all memcached connections 11 | char *key="1"; 12 | //Constant port number of all memcached servers 13 | int port=11211; 14 | //Mutex for printf of multi-threads 15 | pthread_mutex_t mutex; 16 | 17 | //Host list 18 | char* hosts[max_hosts]={ 19 | "192.168.101.2", 20 | "192.168.101.3", 21 | "192.168.101.4", 22 | "192.168.101.5", 23 | "192.168.101.6", 24 | "192.168.101.7", 25 | "192.168.101.8", 26 | "192.168.101.9", 27 | "192.168.101.10", 28 | "192.168.101.11", 29 | "192.168.101.12", 30 | "192.168.101.13", 31 | "192.168.101.14", 32 | "192.168.101.15", 33 | "192.168.101.16"}; 34 | 35 | //A struct for a connection 36 | struct connection 37 | { 38 | int id; 39 | int hostid; 40 | }; 41 | 42 | //Function to GET data from a memcached server 43 | void* client_thread_func(void* connection_ptr); 44 | 45 | //Print usage information 46 | void usage(); 47 | 48 | int main(int argc, char **argv) 49 | { 50 | int i=0; 51 | int connections=0; 52 | //Array of structure connection 53 | struct connection* memcached_connections=NULL; 54 | //Key value 55 | char *key=NULL; 56 | //Array of pthread_t 57 | pthread_t* client_threads=NULL; 58 | //Total start time 59 | struct timeval tv_start_total; 60 | //Total end time 61 | struct timeval tv_end_total; 62 | 63 | if(argc!=2) 64 | { 65 | usage(); 66 | return 0; 67 | } 68 | 69 | //Get connections: char* to int 70 | connections=atoi(argv[1]); 71 | 72 | //Initialize 73 | memcached_connections=(struct connection*)malloc(connections*sizeof(struct connection)); 74 | client_threads=(pthread_t*)malloc(connections*sizeof(pthread_t)); 75 | 76 | //Get start time 77 | gettimeofday(&tv_start_total,NULL); 78 | 79 | //Start threads 80 | for(i=0;i 5 | #include 6 | 7 | //Function to calculate microsecond-granularity TCP timestamp value 8 | static unsigned int get_tsval(void) 9 | { 10 | return (unsigned int)(ktime_to_ns(ktime_get())>>10); 11 | } 12 | 13 | //Modify DSCP value and make the packet ECT, if success, return 1, else return 0 14 | static unsigned int modify_dscp(struct sk_buff *skb, unsigned int dscp) 15 | { 16 | struct iphdr *ip_header; //IP header structure 17 | unsigned int tos_value=0; //TOS value (Note that TOS is 4*DSCP) 18 | unsigned char* tmp=NULL; //temporary variable 19 | 20 | //Get IP header 21 | ip_header=(struct iphdr *)skb_network_header(skb); 22 | 23 | //The packet is not a IP packet (e.g. ARP or others) 24 | if (!ip_header) 25 | { 26 | return 0; 27 | } 28 | if(!skb_make_writable(skb,sizeof(*ip_header))) 29 | { 30 | printk(KERN_INFO "Not writable\n"); 31 | return 0; 32 | } 33 | //Get new IP header 34 | ip_header=(struct iphdr *)skb_network_header(skb); 35 | //Calculate ideal TOS value. Note that packets must be set to be ECT (CE bits=10) 36 | //CE bits=10 or 00 37 | if(ip_header->tos==0x00||ip_header->tos==0x02) 38 | { 39 | tos_value=4*dscp+2; 40 | } 41 | //CE bits=01 42 | else if(ip_header->tos==0x01) 43 | { 44 | tos_value=4*dscp+1; 45 | } 46 | //CE bits=11 47 | else 48 | { 49 | tos_value=4*dscp+3; 50 | } 51 | tmp=(unsigned char*)&tos_value; 52 | //Modify TOS of IP header 53 | ip_header->tos=*tmp; 54 | //Recalculate IP checksum 55 | ip_header->check=0; 56 | ip_header->check=ip_fast_csum(ip_header,ip_header->ihl); 57 | return 1; 58 | } 59 | 60 | //Modify TCP packets' Timestamp option and get sample RTT value 61 | //If time>0: modify outgoing TCP packets' Timestamp value 62 | //Else: modify incoming TCP pakcets' Timestamp echo reply and return RTT 63 | static unsigned int modify_timestamp(struct sk_buff *skb, unsigned int time) 64 | { 65 | struct iphdr *ip_header=NULL; //IP header structure 66 | struct tcphdr *tcp_header=NULL; //TCP header structure 67 | unsigned int tcp_header_len=0; //TCP header length 68 | unsigned char *tcp_opt=NULL; //TCP option pointer 69 | unsigned int *tsecr=NULL; //TCP Timestamp echo reply pointer 70 | unsigned int *tsval=NULL; //TCP Timestamp value pointer 71 | int tcplen=0; //Length of TCP 72 | unsigned char tcp_opt_value=0; //TCP option pointer value 73 | unsigned int rtt=0; //Sample RTT 74 | unsigned int option_len=0; //TCP option length 75 | 76 | //If we can not modify this packet, return 0 77 | if (skb_linearize(skb)!= 0) 78 | { 79 | return 0; 80 | } 81 | 82 | //Get IP header 83 | ip_header=(struct iphdr *)skb_network_header(skb); 84 | //Get TCP header on the base of IP header 85 | tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 86 | //Get TCP header length 87 | tcp_header_len=(unsigned int)(tcp_header->doff*4); 88 | 89 | //Minimum TCP header length=20(Raw TCP header)+10(TCP Timestamp option) 90 | if(tcp_header_len<30) 91 | { 92 | return 0; 93 | } 94 | 95 | //TCP option offset=IP header pointer+IP header length+TCP header length 96 | tcp_opt=(unsigned char*)ip_header+ ip_header->ihl*4+20; 97 | 98 | while(1) 99 | { 100 | //If pointer has moved out off the range of TCP option, stop current loop 101 | if(tcp_opt-(unsigned char*)tcp_header>=tcp_header_len) 102 | { 103 | break; 104 | } 105 | 106 | //Get value of current byte 107 | tcp_opt_value=*tcp_opt; 108 | 109 | if(tcp_opt_value==1)//No-Operation (NOP) 110 | { 111 | //Move to next byte 112 | tcp_opt++; 113 | } 114 | else if(tcp_opt_value==8) //TCP option kind: Timestamp (8) 115 | { 116 | if(time>0) //Modify outgoing packets 117 | { 118 | //Get pointer to Timestamp value 119 | tsval=(unsigned int*)(tcp_opt+2); 120 | //Modify TCP Timestamp value 121 | *tsval=htonl(time); 122 | } 123 | else //Modify incoming packets 124 | { 125 | //Get pointer to Timestamp echo reply (TSecr) 126 | tsecr=(unsigned int*)(tcp_opt+6); 127 | //Get one RTT sample 128 | rtt=get_tsval()-ntohl(*tsecr); 129 | printk(KERN_INFO "RTT: %u\n",rtt); 130 | //Modify TCP TSecr back to jiffies 131 | //Don't disturb TCP. Wrong TCP timestamp echo reply may reset TCP connections 132 | *tsecr=htonl(jiffies); 133 | } 134 | break; 135 | } 136 | else //Other TCP options (e.g. MSS(2)) 137 | { 138 | //Move to next byte to get length of this TCP option 139 | tcp_opt++; 140 | //Get length of this TCP option 141 | tcp_opt_value=*tcp_opt; 142 | option_len=(unsigned int)tcp_opt_value; 143 | 144 | //Move to next TCP option 145 | tcp_opt=tcp_opt+1+(option_len-2); 146 | } 147 | } 148 | 149 | //TCP length=Total length - IP header length 150 | tcplen=skb->len-(ip_header->ihl<<2); 151 | tcp_header->check=0; 152 | 153 | tcp_header->check = csum_tcpudp_magic(ip_header->saddr, ip_header->daddr, 154 | tcplen, ip_header->protocol, 155 | csum_partial((char *)tcp_header, tcplen, 0)); 156 | 157 | skb->ip_summed = CHECKSUM_UNNECESSARY; 158 | return rtt; 159 | } 160 | 161 | #endif 162 | -------------------------------------------------------------------------------- /backup/pias/pias/pias.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include /* copy_from/to_user */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "hash.h" 30 | #include "prio.h" 31 | #include "network.h" 32 | 33 | MODULE_LICENSE("GPL"); 34 | MODULE_AUTHOR("BAI Wei wbaiab@cse.ust.hk"); 35 | MODULE_VERSION("1.0"); 36 | MODULE_DESCRIPTION("Kernel module of PIAS (Practical Information-Agnostic Flow Scheduling)"); 37 | 38 | //FlowTable 39 | static struct FlowTable ft; 40 | //Global Lock (For FlowTable) 41 | static spinlock_t globalLock; 42 | 43 | //Hook for outgoing packets at LOCAL_OUT 44 | static struct nf_hook_ops nfho_outgoing; 45 | //Hook for outgoing packets at LOCAL_IN 46 | static struct nf_hook_ops nfho_incoming; 47 | 48 | //Deal with outgoing packets 49 | static unsigned int hook_func_out(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 50 | { 51 | struct iphdr *ip_header=NULL; //IP header structure 52 | struct tcphdr *tcp_header=NULL; //TCP header structure 53 | struct Flow f; //Flow structure 54 | struct Information* info_pointer=NULL; //Pointer to structure Information 55 | unsigned short int src_port; //TCP source port 56 | unsigned short int dst_port; //TCP destination port 57 | unsigned long flags; //variable for save current states of irq 58 | unsigned int dscp; //DSCP value 59 | unsigned int payload_len; //TCP payload length 60 | unsigned int result; //Delete_Table return result 61 | 62 | //Get IP header 63 | ip_header=(struct iphdr *)skb_network_header(skb); 64 | //The packet is not an IP packet (e.g. ARP or others), return NF_ACCEPT 65 | if (!ip_header) 66 | { 67 | return NF_ACCEPT; 68 | } 69 | 70 | //TCP 71 | if(ip_header->protocol==IPPROTO_TCP) 72 | { 73 | tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 74 | src_port=ntohs(tcp_header->source); 75 | dst_port=ntohs(tcp_header->dest); 76 | //We only deal with our experiment traffic: TCP source port or destination port = 5001 77 | if(src_port==5001||dst_port==5001) 78 | { 79 | Init_Flow(&f); 80 | f.local_ip=ip_header->saddr; 81 | f.remote_ip=ip_header->daddr; 82 | f.local_port=src_port; 83 | f.remote_port=dst_port; 84 | 85 | if(tcp_header->syn) //TCP SYN packet, a new initialized outgoing connection 86 | { 87 | //A new Flow entry should be inserted into FlowTable 88 | spin_lock_irqsave(&globalLock,flags); 89 | if(Insert_Table(&ft,&f)==0) 90 | { 91 | printk(KERN_INFO "Insert fail\n"); 92 | } 93 | spin_unlock_irqrestore(&globalLock,flags); 94 | //Give this packet highest priority because bytes sent=0 when the flow is initialized 95 | dscp=priority(0); 96 | modify_dscp(skb,dscp); 97 | } 98 | else if(tcp_header->fin||tcp_header->rst) //TCP FIN/RST packets, connection will be closed 99 | { 100 | //An existing Flow entry should be deleted from FlowTable. 101 | spin_lock_irqsave(&globalLock,flags); 102 | //Result=bytes sent of this flow 103 | result=Delete_Table(&ft,&f); 104 | if(result==0) 105 | { 106 | printk(KERN_INFO "Delete fail\n"); 107 | } 108 | /*else 109 | { 110 | printk(KERN_INFO "Delete succeed\n"); 111 | }*/ 112 | spin_unlock_irqrestore(&globalLock,flags); 113 | dscp=priority(result); 114 | modify_dscp(skb,dscp); 115 | } 116 | else 117 | { 118 | //Update existing Flow entry's information 119 | spin_lock_irqsave(&globalLock,flags); 120 | info_pointer=Search_Table(&ft,&f); 121 | spin_unlock_irqrestore(&globalLock,flags); 122 | if(info_pointer!=NULL) 123 | { 124 | //TCP payload length=Total length - IP header length-TCP header length 125 | payload_len=skb->len-(ip_header->ihl<<2)-(unsigned int)(tcp_header->doff*4); 126 | //payload length>0 and info_pointer->send_data will not exceed the maximum value of unsigned int (4,294,967,295) 127 | if(payload_len>0 && payload_len+info_pointer->send_data<4294967295) 128 | { 129 | info_pointer->send_data+=payload_len; 130 | info_pointer->last_update_time=get_tsval(); 131 | } 132 | dscp=priority(info_pointer->send_data); 133 | modify_dscp(skb,dscp); 134 | } 135 | //No such Flow entry, last few packets. We need to accelerate flow completion. 136 | else 137 | { 138 | dscp=priority(0); 139 | modify_dscp(skb,dscp); 140 | } 141 | } 142 | } 143 | } 144 | return NF_ACCEPT; 145 | } 146 | 147 | //Deal with incoming packets 148 | /*static unsigned int hook_func_in(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 149 | { 150 | 151 | struct iphdr *ip_header=NULL; //IP header structure 152 | struct tcphdr *tcp_header=NULL; //TCP header structure 153 | struct Flow f; //Flow structure 154 | struct Information* info_pointer=NULL; //Pointer to structure Information 155 | unsigned short int src_port; //TCP source port 156 | unsigned short int dst_port; //TCP destination port 157 | unsigned long flags; //variable for save current states of irq 158 | unsigned int payload_len; //TCP payload length 159 | 160 | //Get IP header 161 | ip_header=(struct iphdr *)skb_network_header(skb); 162 | //The packet is not an IP packet (e.g. ARP or others), return NF_ACCEPT 163 | if (!ip_header) 164 | { 165 | return NF_ACCEPT; 166 | } 167 | 168 | //TCP 169 | if(ip_header->protocol==IPPROTO_TCP) 170 | { 171 | tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 172 | src_port=ntohs(tcp_header->source); 173 | dst_port=ntohs(tcp_header->dest); 174 | //We only deal with our experiment traffic: TCP source port or destination port = 5001 175 | if(src_port==5001||dst_port==5001) 176 | { 177 | //Update existing Flow entry's information. Note that direction has been changed. 178 | Init_Flow(&f); 179 | f.local_ip=ip_header->daddr; 180 | f.remote_ip=ip_header->saddr; 181 | f.local_port=dst_port; 182 | f.remote_port=src_port; 183 | //TCP SYN packet, a new initialized outgoing connection 184 | if(tcp_header->syn&&!tcp_header->ack) 185 | { 186 | //A new Flow entry should be inserted into FlowTable 187 | spin_lock_irqsave(&globalLock,flags); 188 | if(Insert_Table(&ft,&f)==0) 189 | { 190 | printk(KERN_INFO "Insert fail\n"); 191 | } 192 | else 193 | { 194 | printk(KERN_INFO "Insert succeed\n"); 195 | } 196 | spin_unlock_irqrestore(&globalLock,flags); 197 | } 198 | else 199 | { 200 | //spin_lock_irqsave(&globalLock,flags); 201 | info_pointer=Search_Table(&ft,&f); 202 | //spin_unlock_irqrestore(&globalLock,flags); 203 | if(info_pointer!=NULL) 204 | { 205 | //TCP payload length=Total length - IP header length-TCP header length 206 | payload_len=skb->len-(ip_header->ihl<<2)-(unsigned int)(tcp_header->doff*4); 207 | if(payload_len>0) 208 | info_pointer->last_update_time=get_tsval(); 209 | } 210 | } 211 | } 212 | } 213 | return NF_ACCEPT; 214 | }*/ 215 | 216 | //Called when module loaded using 'insmod' 217 | int init_module() 218 | { 219 | //Initialize Global Lock 220 | spin_lock_init(&globalLock); 221 | 222 | //Initialize FlowTable 223 | Init_Table(&ft); 224 | 225 | //NF_LOCAL_IN Hook 226 | //nfho_incoming.hook = hook_func_in; //function to call when conditions below met 227 | //nfho_incoming.hooknum = NF_INET_LOCAL_IN; //called in NF_IP_LOCAL_IN 228 | //nfho_incoming.pf = PF_INET; //IPv4 packets 229 | //nfho_incoming.priority = NF_IP_PRI_FIRST; //set to highest priority over all other hook functions 230 | //nf_register_hook(&nfho_incoming); //register hook*/ 231 | 232 | //NF_LOCAL_OUT Hook 233 | nfho_outgoing.hook = hook_func_out; //function to call when conditions below met 234 | nfho_outgoing.hooknum = NF_INET_LOCAL_OUT; //called in NF_IP_LOCAL_OUT 235 | nfho_outgoing.pf = PF_INET; //IPv4 packets 236 | nfho_outgoing.priority = NF_IP_PRI_FIRST; //set to highest priority over all other hook functions 237 | nf_register_hook(&nfho_outgoing); //register hook 238 | 239 | printk(KERN_INFO "Start PIAS kernel module\n"); 240 | return 0; 241 | } 242 | 243 | //Called when module unloaded using 'rmmod' 244 | void cleanup_module() 245 | { 246 | //Unregister two hooks 247 | nf_unregister_hook(&nfho_outgoing); 248 | //nf_unregister_hook(&nfho_incoming); 249 | 250 | //Clear table 251 | Empty_Table(&ft); 252 | 253 | printk(KERN_INFO "Stop PIAS kernel module\n"); 254 | } 255 | -------------------------------------------------------------------------------- /backup/pias/pias/prio.h: -------------------------------------------------------------------------------- 1 | #ifndef PRIO_H 2 | #define PRIO_H 3 | 4 | //Input: bytes sent (Note that size<0 denotes that no such flow entry or last few packets) 5 | //Output: DSCP 6 | static int priority(unsigned int size) 7 | { 8 | if(size<=965816) 9 | return 1; 10 | else 11 | return 0; 12 | } 13 | #endif -------------------------------------------------------------------------------- /backup/pias/pias2/Makefile: -------------------------------------------------------------------------------- 1 | obj-m+=pias.o 2 | 3 | all: 4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 5 | 6 | clean: 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 8 | 9 | 10 | -------------------------------------------------------------------------------- /backup/pias/pias2/flow.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOW_H 2 | #define FLOW_H 3 | 4 | //The structure of information of a TCP flow 5 | //latest_update_time: the last time when we observe an outgoing packet (from local side to remote side) 6 | //latest_timeout_time: the last time when we observe an TCP timeout 7 | //latest_timeout_seq: the sequence number for last TCP timeout 8 | //latest_seq: the largest (latest) sequence number for outoging traffic 9 | //latest_ack: the largest (latest) ACK number for outoging traffic 10 | //bytes_sent: the total payload size of outgoing traffic 11 | //timeouts: the number of consecutive timeouts experienced by outgoing traffic 12 | struct Information 13 | { 14 | ktime_t latest_update_time; 15 | ktime_t latest_timeout_time; 16 | u32 latest_timeout_seq; 17 | u32 latest_seq; 18 | u32 latest_ack; 19 | u32 bytes_sent; 20 | u32 timeouts; 21 | //0 is the highest priority 22 | //unsigned int priority; 23 | }; 24 | 25 | //The structure of for a TCP flow 26 | //A TCP flow is defined by 4-tuple and its related information 27 | struct Flow 28 | { 29 | u32 remote_ip; 30 | u32 local_ip; 31 | u16 remote_port; 32 | u16 local_port; 33 | struct Information info; 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /backup/pias/pias2/network.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORK_H 2 | #define NETWORK_H 3 | 4 | #include 5 | #include 6 | 7 | //Function to calculate microsecond-granularity TCP timestamp value 8 | static u32 get_tsval(void) 9 | { 10 | return (u32)(ktime_to_ns(ktime_get())>>10); 11 | } 12 | 13 | static void enable_ecn_dscp(struct sk_buff *skb, u8 dscp) 14 | { 15 | struct iphdr *iph =ip_hdr(skb); 16 | if(likely(iph!=NULL)) 17 | { 18 | ipv4_change_dsfield(iph, 0xff, (dscp<<2)|INET_ECN_ECT_0); 19 | } 20 | } 21 | 22 | //Function: modify incoming TCP packets 23 | //return RTT sample value 24 | static unsigned int tcp_modify_incoming(struct sk_buff *skb) 25 | { 26 | struct iphdr *ip_header=NULL; //IP header structure 27 | struct tcphdr *tcp_header=NULL; //TCP header structure 28 | unsigned int tcp_header_len=0; //TCP header length 29 | unsigned char *tcp_opt=NULL; //TCP option pointer 30 | unsigned int *tsecr=NULL; //TCP Timestamp echo reply pointer 31 | int tcplen=0; //Length of TCP 32 | unsigned char tcp_opt_value=0; //TCP option pointer value 33 | unsigned int rtt=0; //Sample RTT 34 | unsigned int option_len=0; //TCP option length 35 | 36 | //If we can not modify this packet, return 0 37 | if (skb_linearize(skb)!= 0) 38 | { 39 | return 0; 40 | } 41 | 42 | //Get IP header 43 | ip_header=(struct iphdr *)skb_network_header(skb); 44 | //Get TCP header on the base of IP header 45 | tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 46 | //Get TCP header length 47 | tcp_header_len=(unsigned int)(tcp_header->doff*4); 48 | 49 | //Minimum TCP header length=20(Raw TCP header)+10(TCP Timestamp option) 50 | if(tcp_header_len<30) 51 | { 52 | return 0; 53 | } 54 | 55 | //TCP option offset=IP header pointer+IP header length+TCP header length 56 | tcp_opt=(unsigned char*)ip_header+ ip_header->ihl*4+20; 57 | 58 | while(1) 59 | { 60 | //If pointer has moved out off the range of TCP option, stop current loop 61 | if(tcp_opt-(unsigned char*)tcp_header>=tcp_header_len) 62 | { 63 | break; 64 | } 65 | //Get value of current byte 66 | tcp_opt_value=*tcp_opt; 67 | 68 | if(tcp_opt_value==1)//No-Operation (NOP) 69 | { 70 | //Move to next byte 71 | tcp_opt++; 72 | } 73 | else if(tcp_opt_value==8) //TCP option kind: Timestamp (8) 74 | { 75 | //Get pointer to Timestamp echo reply (TSecr) 76 | tsecr=(unsigned int*)(tcp_opt+6); 77 | //Get one RTT sample 78 | rtt=get_tsval()-ntohl(*tsecr); 79 | //printk(KERN_INFO "RTT: %u\n",rtt); 80 | //Modify TCP TSecr back to jiffies 81 | //Don't disturb TCP. Wrong TCP timestamp echo reply may reset TCP connections 82 | *tsecr=htonl(jiffies); 83 | break; 84 | } 85 | else //Other TCP options (e.g. MSS(2)) 86 | { 87 | //Move to next byte to get length of this TCP option 88 | tcp_opt++; 89 | //Get length of this TCP option 90 | tcp_opt_value=*tcp_opt; 91 | option_len=(unsigned int)tcp_opt_value; 92 | 93 | //Move to next TCP option 94 | tcp_opt=tcp_opt+1+(option_len-2); 95 | } 96 | } 97 | 98 | //TCP length=Total length - IP header length 99 | tcplen=skb->len-(ip_header->ihl<<2); 100 | tcp_header->check=0; 101 | 102 | tcp_header->check = csum_tcpudp_magic(ip_header->saddr, ip_header->daddr, 103 | tcplen, ip_header->protocol, 104 | csum_partial((char *)tcp_header, tcplen, 0)); 105 | 106 | skb->ip_summed = CHECKSUM_UNNECESSARY; 107 | return rtt; 108 | } 109 | 110 | //Function: modify outgoing TCP packets 111 | // 1. modify millisecond-granularity TCP timestamp to microsecond-granularity value 112 | // 2. modify TCP receive window 113 | //Input: 114 | // win: receive window value (in bytes) 115 | // time: microsecond-granularity value 116 | //If successfully, return 1. Else, return 0. 117 | static unsigned int tcp_modify_outgoing(struct sk_buff *skb, unsigned int win, unsigned int time) 118 | { 119 | struct iphdr *ip_header=NULL; //IP header structure 120 | struct tcphdr *tcp_header=NULL; //TCP header structure 121 | unsigned int tcp_header_len=0; //TCP header length 122 | unsigned char *tcp_opt=NULL; //TCP option pointer 123 | unsigned int *tsval=NULL; //TCP Timestamp value pointer 124 | int tcplen=0; //Length of TCP 125 | unsigned char tcp_opt_value=0; //TCP option pointer value 126 | unsigned int option_len=0; //TCP option length 127 | 128 | if (skb_linearize(skb)!= 0) 129 | { 130 | return 0; 131 | } 132 | 133 | //Get IP header 134 | ip_header=(struct iphdr *)skb_network_header(skb); 135 | //Get TCP header on the base of IP header 136 | tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 137 | //Get TCP header length 138 | tcp_header_len=(unsigned int)(tcp_header->doff*4); 139 | 140 | //Minimum TCP header length=20(Raw TCP header)+10(TCP Timestamp option) 141 | if(tcp_header_len<30) 142 | { 143 | return 0; 144 | } 145 | 146 | //Modify TCP window. Note that TCP received window should be no larger than 65535 bytes. 147 | if(win<65535) 148 | tcp_header->window=htons(win); 149 | 150 | //TCP option offset=IP header pointer+IP header length+TCP header length 151 | tcp_opt=(unsigned char*)ip_header+ ip_header->ihl*4+20; 152 | 153 | while(1) 154 | { 155 | //If pointer has moved out off the range of TCP option, stop current loop 156 | if(tcp_opt-(unsigned char*)tcp_header>=tcp_header_len) 157 | { 158 | break; 159 | } 160 | 161 | //Get value of current byte 162 | tcp_opt_value=*tcp_opt; 163 | 164 | if(tcp_opt_value==1)//No-Operation (NOP) 165 | { 166 | //Move to next byte 167 | tcp_opt++; 168 | } 169 | else if(tcp_opt_value==8) //TCP option kind: Timestamp (8) 170 | { 171 | if(time>0) 172 | { 173 | //Get pointer to Timestamp value 174 | tsval=(unsigned int*)(tcp_opt+2); 175 | //Modify TCP Timestamp value 176 | *tsval=htonl(time); 177 | } 178 | break; 179 | } 180 | else //Other TCP options (e.g. MSS(2)) 181 | { 182 | //Move to next byte to get length of this TCP option 183 | tcp_opt++; 184 | //Get length of this TCP option 185 | tcp_opt_value=*tcp_opt; 186 | option_len=(unsigned int)tcp_opt_value; 187 | 188 | //Move to next TCP option 189 | tcp_opt=tcp_opt+1+(option_len-2); 190 | } 191 | } 192 | 193 | //TCP length=Total length - IP header length 194 | tcplen=skb->len-(ip_header->ihl<<2); 195 | tcp_header->check=0; 196 | 197 | tcp_header->check = csum_tcpudp_magic(ip_header->saddr, ip_header->daddr, 198 | tcplen, ip_header->protocol, 199 | csum_partial((char *)tcp_header, tcplen, 0)); 200 | 201 | skb->ip_summed = CHECKSUM_UNNECESSARY; 202 | 203 | return 1; 204 | } 205 | 206 | //Maximum unsigned 32-bit integer value: 4294967295 207 | //Function: determine whether seq1 is larger than seq2 208 | //If Yes, return 1. Else, return 0. 209 | //We use a simple heuristic to handle wrapped TCP sequence number 210 | static u8 is_seq_larger(u32 seq1, u32 seq2) 211 | { 212 | if(likely(seq1>seq2&&seq1-seq2<=4294900000)) 213 | { 214 | return 1; 215 | } 216 | else if(seq14294900000) 217 | { 218 | return 1; 219 | } 220 | else 221 | { 222 | return 0; 223 | } 224 | } 225 | 226 | static u32 seq_gap(u32 seq1, u32 seq2) 227 | { 228 | if(likely(seq1>=seq2)) 229 | return seq1-seq2; 230 | else 231 | return 4294967295-(seq2-seq1); 232 | } 233 | #endif 234 | -------------------------------------------------------------------------------- /backup/pias/pias2/params.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARAMS_H__ 2 | #define __PARAMS_H__ 3 | 4 | //Maximum size of bytes sent 5 | const u32 MAX_BYTES_SENT=4294967295; 6 | //RTOmin is 10ms in our testbed. We set RTO_MIN to 8ms to avoid deviation. 7 | const unsigned int RTO_MIN=8*1000; 8 | //The threshold of consecutive TCP timeouts 9 | const unsigned int TIMEOUT_THRESH=2; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /backup/pias/pias2/pias.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include /* copy_from/to_user */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "hash.h" 30 | #include "prio.h" 31 | #include "network.h" 32 | #include "params.h" 33 | 34 | MODULE_LICENSE("GPL"); 35 | MODULE_AUTHOR("BAI Wei wbaiab@cse.ust.hk"); 36 | MODULE_VERSION("1.1"); 37 | MODULE_DESCRIPTION("Kernel module of PIAS (Practical Information-Agnostic Flow Scheduling)"); 38 | 39 | char *param_dev=NULL; 40 | MODULE_PARM_DESC(param_dev, "Interface to operate PIAS"); 41 | module_param(param_dev, charp, 0); 42 | 43 | //FlowTable 44 | static struct FlowTable ft; 45 | 46 | //Hook for outgoing packets at LOCAL_OUT 47 | static struct nf_hook_ops nfho_outgoing; 48 | //Hook for outgoing packets at LOCAL_IN 49 | static struct nf_hook_ops nfho_incoming; 50 | 51 | //Deal with outgoing packets 52 | static unsigned int hook_func_out(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 53 | { 54 | struct iphdr *ip_header=NULL; //IP header structure 55 | struct tcphdr *tcp_header=NULL; //TCP header structure 56 | struct Flow f; //Flow structure 57 | struct Information* info_pointer=NULL; //Pointer to structure Information 58 | unsigned long flags; //variable for save current states of irq 59 | u8 dscp; //DSCP value 60 | u16 payload_len; //TCP payload length 61 | u32 seq; //TCP sequence number 62 | u32 result; //Delete_Table return result 63 | ktime_t now; //current time 64 | 65 | if(!out) 66 | return NF_ACCEPT; 67 | 68 | if(strcmp(out->name,param_dev)!=0) 69 | return NF_ACCEPT; 70 | 71 | //Get IP header 72 | ip_header=(struct iphdr *)skb_network_header(skb); 73 | //The packet is not an IP packet (e.g. ARP or others), return NF_ACCEPT 74 | if (unlikely(ip_header==NULL)) 75 | { 76 | return NF_ACCEPT; 77 | } 78 | 79 | //TCP 80 | if(ip_header->protocol==IPPROTO_TCP) 81 | { 82 | now=ktime_get(); 83 | tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 84 | Init_Flow(&f); 85 | f.local_ip=ip_header->saddr; 86 | f.remote_ip=ip_header->daddr; 87 | f.local_port=(u16)ntohs(tcp_header->source); 88 | f.remote_port=(u16)ntohs(tcp_header->dest); 89 | //TCP SYN packet, a new connection 90 | if(tcp_header->syn) 91 | { 92 | f.info.latest_seq=ntohl(tcp_header->seq); 93 | f.info.latest_update_time=now; 94 | //A new Flow entry should be inserted into FlowTable 95 | spin_lock_irqsave(&(ft.tableLock),flags); 96 | if(Insert_Table(&ft,&f)==0) 97 | { 98 | printk(KERN_INFO "Insert fail\n"); 99 | } 100 | spin_unlock_irqrestore(&(ft.tableLock),flags); 101 | //Give this packet highest priority because bytes sent=0 when the flow is initialized 102 | dscp=priority(0); 103 | //Modify DSCP and make the packet ECT 104 | enable_ecn_dscp(skb,dscp); 105 | } 106 | //TCP FIN/RST packets, connection will be closed 107 | else if(tcp_header->fin||tcp_header->rst) 108 | { 109 | //An existing Flow entry should be deleted from FlowTable. 110 | spin_lock_irqsave(&(ft.tableLock),flags); 111 | //Result=bytes sent of this flow 112 | result=Delete_Table(&ft,&f); 113 | if(result==0) 114 | { 115 | printk(KERN_INFO "Delete fail\n"); 116 | } 117 | spin_unlock_irqrestore(&(ft.tableLock),flags); 118 | dscp=priority(result); 119 | enable_ecn_dscp(skb,dscp); 120 | } 121 | else 122 | { 123 | //Update existing Flow entry's information 124 | spin_lock_irqsave(&(ft.tableLock),flags); 125 | info_pointer=Search_Table(&ft,&f); 126 | if(info_pointer!=NULL) 127 | { 128 | //TCP payload length=Total IP length - IP header length-TCP header length 129 | payload_len=ntohs(ip_header->tot_len)-(ip_header->ihl<<2)-(tcp_header->doff<<2); 130 | seq=ntohl(tcp_header->seq); 131 | if(payload_len>=1) 132 | seq=seq+payload_len-1; 133 | if(is_seq_larger(seq,info_pointer->latest_seq)==1) 134 | { 135 | if(payload_len+info_pointer->bytes_sentbytes_sent+=payload_len; 138 | info_pointer->latest_seq=seq; 139 | } 140 | } 141 | //Packet drops happen!. We should not inrease bytes_sent of this flow 142 | else 143 | { 144 | //TCP timeout 145 | if(ktime_us_delta(now,info_pointer->latest_update_time)>=RTO_MIN&&is_seq_larger(info_pointer->latest_seq,info_pointer->latest_ack)==1) 146 | { 147 | printk(KERN_INFO "TCP timeout is detected with RTO = %u and bytes sent = %u",(unsigned int)ktime_us_delta(now,info_pointer->latest_update_time),(unsigned int)(info_pointer->bytes_sent)); 148 | //It's a 'consecutive' TCP timeout? 149 | if(TIMEOUT_THRESH==1||(TIMEOUT_THRESH>=2&&seq_gap(seq,info_pointer->latest_timeout_seq)<=5*1448||seq_gap(info_pointer->latest_timeout_seq,seq)<=5*1448)) 150 | { 151 | info_pointer->timeouts++; 152 | //Fixed threshold of consecutive TCP timeouts 153 | if(info_pointer->timeouts>=TIMEOUT_THRESH) 154 | { 155 | printk(KERN_INFO "%u consecutive TCP timeouts are detected!\n", TIMEOUT_THRESH); 156 | info_pointer->timeouts=0; 157 | info_pointer->bytes_sent=0; 158 | } 159 | } 160 | //It is the first timeout 161 | else 162 | { 163 | info_pointer->timeouts=1; 164 | } 165 | info_pointer->latest_timeout_seq=seq; 166 | } 167 | } 168 | info_pointer->latest_update_time=now; 169 | dscp=priority(info_pointer->bytes_sent); 170 | enable_ecn_dscp(skb,dscp); 171 | } 172 | //No such Flow entry, last few packets. We need to accelerate flow completion. 173 | else 174 | { 175 | dscp=priority(0); 176 | enable_ecn_dscp(skb,dscp); 177 | } 178 | spin_unlock_irqrestore(&(ft.tableLock),flags); 179 | } 180 | } 181 | return NF_ACCEPT; 182 | } 183 | 184 | //Deal with incoming packets 185 | static unsigned int hook_func_in(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 186 | { 187 | 188 | struct iphdr *ip_header=NULL; //IP header structure 189 | struct tcphdr *tcp_header=NULL; //TCP header structure 190 | struct Flow f; //Flow structure 191 | struct Information* info_pointer=NULL; //Pointer to structure Information 192 | u32 ack; 193 | unsigned long flags; //variable for save current states of irq 194 | 195 | if(!in) 196 | return NF_ACCEPT; 197 | 198 | if(strcmp(in->name,param_dev)!=0) 199 | return NF_ACCEPT; 200 | 201 | //Get IP header 202 | ip_header=(struct iphdr *)skb_network_header(skb); 203 | //The packet is not an IP packet (e.g. ARP or others), return NF_ACCEPT 204 | if (unlikely(ip_header==NULL)) 205 | { 206 | return NF_ACCEPT; 207 | } 208 | 209 | //TCP 210 | if(ip_header->protocol==IPPROTO_TCP) 211 | { 212 | tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); 213 | //Update existing Flow entry's information. Note that direction has been changed. 214 | Init_Flow(&f); 215 | f.local_ip=ip_header->daddr; 216 | f.remote_ip=ip_header->saddr; 217 | f.local_port=(u16)ntohs(tcp_header->dest); 218 | f.remote_port=(u16)ntohs(tcp_header->source); 219 | //Update existing Flow entry's information 220 | spin_lock_irqsave(&(ft.tableLock),flags); 221 | info_pointer=Search_Table(&ft,&f); 222 | if(info_pointer!=NULL) 223 | { 224 | ack=(u32)ntohl(tcp_header->ack); 225 | if(is_seq_larger(ack,info_pointer->latest_ack)==1) 226 | { 227 | info_pointer->latest_ack=ack; 228 | } 229 | } 230 | spin_unlock_irqrestore(&(ft.tableLock),flags); 231 | } 232 | return NF_ACCEPT; 233 | } 234 | 235 | //Called when module loaded using 'insmod' 236 | int init_module() 237 | { 238 | int i=0; 239 | //Get interface 240 | if(param_dev==NULL) 241 | { 242 | printk(KERN_INFO "PIAS: not specify network interface.\n"); 243 | param_dev = "eth1\0"; 244 | } 245 | // trim 246 | for(i = 0; i < 32 && param_dev[i] != '\0'; i++) 247 | { 248 | if(param_dev[i] == '\n') 249 | { 250 | param_dev[i] = '\0'; 251 | break; 252 | } 253 | } 254 | printk(KERN_INFO "PIAS: work on %s\n",param_dev); 255 | 256 | //Initialize FlowTable 257 | Init_Table(&ft); 258 | 259 | //NF_LOCAL_IN Hook 260 | nfho_incoming.hook = hook_func_in; //function to call when conditions below met 261 | nfho_incoming.hooknum = NF_INET_LOCAL_IN; //called in NF_IP_LOCAL_IN 262 | nfho_incoming.pf = PF_INET; //IPv4 packets 263 | nfho_incoming.priority = NF_IP_PRI_FIRST; //set to highest priority over all other hook functions 264 | nf_register_hook(&nfho_incoming); //register hook 265 | 266 | //NF_LOCAL_OUT Hook 267 | nfho_outgoing.hook = hook_func_out; //function to call when conditions below met 268 | nfho_outgoing.hooknum = NF_INET_LOCAL_OUT; //called in NF_IP_LOCAL_OUT 269 | nfho_outgoing.pf = PF_INET; //IPv4 packets 270 | nfho_outgoing.priority = NF_IP_PRI_FIRST; //set to highest priority over all other hook functions 271 | nf_register_hook(&nfho_outgoing); //register hook 272 | 273 | printk(KERN_INFO "Start PIAS kernel module\n"); 274 | return 0; 275 | } 276 | 277 | //Called when module unloaded using 'rmmod' 278 | void cleanup_module() 279 | { 280 | //Unregister two hooks 281 | nf_unregister_hook(&nfho_outgoing); 282 | nf_unregister_hook(&nfho_incoming); 283 | 284 | //Clear table 285 | Empty_Table(&ft); 286 | 287 | printk(KERN_INFO "Stop PIAS kernel module\n"); 288 | } 289 | -------------------------------------------------------------------------------- /backup/pias/pias2/prio.h: -------------------------------------------------------------------------------- 1 | #ifndef PRIO_H 2 | #define PRIO_H 3 | 4 | //Input: bytes sent (Note that size<0 denotes that no such flow entry or last few packets) 5 | //Output: DSCP 6 | static u8 priority(u32 size) 7 | { 8 | //For Web Search, it's 965816 9 | /*if(size<=965816) 10 | return 1; 11 | else 12 | return 0;*/ 13 | //For Data Mining, it's 6KB 14 | /*if(size<=6*1024) 15 | return 1; 16 | else 17 | return 0;*/ 18 | //For Data Mining with four queues, our thresholds are 1KB, 9KB and 167KB (load=0.8) 19 | /* 20 | if(size<=1*1024) 21 | return 3; 22 | else if(size<=9*1024) 23 | return 2; 24 | else if(size<=167*1024) 25 | return 1; 26 | else 27 | return 0;*/ 28 | //For Data Mining with eight queues, our thresholds are 1KB, 8KB, 80KB, 122KB, 130KB, 132KB, 133KB 29 | /*if(size<=1*1024) 30 | return 7; 31 | else if(size<=8*1024) 32 | return 6; 33 | else if(size<=80*1024) 34 | return 5; 35 | else if(size<=122*1024) 36 | return 4; 37 | else if(size<=130*1024) 38 | return 3; 39 | else if(size<=132*1024) 40 | return 2; 41 | else if(size<=133*1024) 42 | return 1; 43 | else 44 | return 0;*/ 45 | //For Web Search with two queues (equal split), our thresholds are 72KB 46 | /*if(size<=72*1024) 47 | return 1; 48 | else 49 | return 0;*/ 50 | //For Web Search with four queues (equal split), our thresholds are 24KB, 72KB, 1448KB 51 | /*if(size<=24*1024) 52 | return 3; 53 | else if(size<=72*1024) 54 | return 2; 55 | else if(size<=1448*1024) 56 | return 1; 57 | else 58 | return 0;*/ 59 | //For Web Search with four queues (optimal), our thresholds are 70KB 1785KB 3.18MB 60 | /*if(size<=70*1024) 61 | return 3; 62 | else if(size<=1785*1024) 63 | return 2; 64 | else if(size<=3180*1024) 65 | return 1; 66 | else 67 | return 0;*/ 68 | //For Web search with eight queues (optimal), our thresholds are 65KB 1491KB 2257KB 2814KB 2880KB 2896KB 3000KB 69 | if(size<=65*1024) 70 | return 7; 71 | /*else if(size<=1491*1024) 72 | return 6; 73 | else if(size<=2257*1024) 74 | return 5; 75 | else if(size<=2814*1024) 76 | return 4; 77 | else if(size<=2880*1024) 78 | return 3; 79 | else if(size<=2896*1024) 80 | return 2; 81 | else if (size<=3000*1024) 82 | return 1;*/ 83 | else 84 | return 0; 85 | //For static flow experiment, the right threshold is 20KB 86 | /*if(size<=20*1024) 87 | return 1; 88 | else 89 | return 0;*/ 90 | } 91 | #endif -------------------------------------------------------------------------------- /backup/pias/sp/Makefile: -------------------------------------------------------------------------------- 1 | obj-m+=sp.o 2 | 3 | all: 4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 5 | 6 | clean: 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 8 | 9 | 10 | -------------------------------------------------------------------------------- /backup/pias/sp/queue.h: -------------------------------------------------------------------------------- 1 | #ifndef QUEUE_H 2 | #define QUEUE_H 3 | 4 | #include 5 | 6 | struct Packet{ 7 | 8 | int (*okfn)(struct sk_buff *); //function pointer to reinject packets 9 | struct sk_buff *skb; //socket buffer descriptor to packet 10 | }; 11 | 12 | struct PacketQueue{ 13 | struct Packet *packets; //Array to store packets 14 | unsigned int head; //Head packet 15 | unsigned int size; //Current queue size (packets) 16 | unsigned int bytes; //Current queue size (bytes) 17 | unsigned int max_length; //Maximum length for this packet queue 18 | }; 19 | 20 | //If initialization succeeds, return 1 21 | //Else, return 0 22 | unsigned int Init_PacketQueue(struct PacketQueue* q, unsigned int length) 23 | { 24 | struct Packet *buf=vmalloc(length*sizeof(struct Packet)); 25 | if(buf!=NULL) 26 | { 27 | q->packets=buf; 28 | q->head=0; 29 | q->size=0; 30 | q->max_length=length=length; 31 | return 1; 32 | } 33 | else 34 | { 35 | printk(KERN_INFO "Vmalloc error\n"); 36 | return 0; 37 | } 38 | } 39 | 40 | void Free_PacketQueue(struct PacketQueue* q) 41 | { 42 | vfree(q->packets); 43 | } 44 | 45 | int Enqueue_PacketQueue(struct PacketQueue* q,struct sk_buff *skb,int (*okfn)(struct sk_buff *)) 46 | { 47 | //There is capacity to contain new packets 48 | if(q->sizemax_length) { 49 | 50 | //Index for new insert packet 51 | int queueIndex=(q->head+q->size)%q->max_length; 52 | q->packets[queueIndex].skb=skb; 53 | q->packets[queueIndex].okfn=okfn; 54 | q->size++; 55 | q->bytes=q->bytes+skb->len; 56 | return 1; 57 | 58 | } else { 59 | 60 | return 0; 61 | } 62 | } 63 | 64 | int Dequeue_PacketQueue(struct PacketQueue* q) 65 | { 66 | if(q->size>0) { 67 | //Reinject head packet of current queue 68 | (q->packets[q->head].okfn)(q->packets[q->head].skb); 69 | q->size--; 70 | q->bytes=q->bytes-q->packets[q->head].skb->len; 71 | q->head=(q->head+1)%q->max_length; 72 | return 1; 73 | 74 | } else { 75 | 76 | return 0; 77 | } 78 | } 79 | 80 | #endif -------------------------------------------------------------------------------- /pias3/Makefile: -------------------------------------------------------------------------------- 1 | obj-m +=pias.o 2 | pias-y :=params.o flow.o network.o main.o 3 | EXTRA_CFLAGS += -DANTI_STARVATION 4 | 5 | all: 6 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 7 | 8 | clean: 9 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 10 | -------------------------------------------------------------------------------- /pias3/flow.h: -------------------------------------------------------------------------------- 1 | #ifndef __FLOW_H__ 2 | #define __FLOW_H__ 3 | 4 | #include 5 | #include 6 | 7 | /*Define structure of information for a TCP flow 8 | *latest_update_time: the last time when we observe an outgoing packet (from local side to remote side) 9 | *latest_timeout_seq: the sequence number for last TCP timeout 10 | *latest_seq: the largest (latest) sequence number for outoging traffic 11 | *latest_ack: the largest (latest) ACK number for outoging traffic 12 | *bytes_sent: bytes sent of outgoing traffic 13 | *timeouts: the number of consecutive timeouts experienced by outgoing traffic 14 | */ 15 | 16 | struct PIAS_Flow_Info 17 | { 18 | ktime_t latest_update_time; 19 | u32 latest_timeout_seq; 20 | u32 latest_seq; 21 | u32 latest_ack; 22 | u32 bytes_sent; 23 | u16 timeouts; 24 | }; 25 | 26 | /* A TCP Flow is defined by 4-tuple and its related information */ 27 | struct PIAS_Flow 28 | { 29 | u32 local_ip; //Local IP address 30 | u32 remote_ip; //Remote IP address 31 | u16 local_port; //Local TCP port 32 | u16 remote_port; //Remote TCP port 33 | struct PIAS_Flow_Info info; //Information for this flow 34 | }; 35 | 36 | /* Link Node of Flow */ 37 | struct PIAS_Flow_Node 38 | { 39 | struct PIAS_Flow f; //structure of Flow 40 | struct PIAS_Flow_Node* next; //pointer to next node 41 | }; 42 | 43 | /* Link List of Flows */ 44 | struct PIAS_Flow_List 45 | { 46 | struct PIAS_Flow_Node* head; //pointer to head node of this link list 47 | unsigned int len; //current length of this list 48 | }; 49 | 50 | /* Hash Table of Flows */ 51 | struct PIAS_Flow_Table 52 | { 53 | struct PIAS_Flow_List* table; //many FlowList 54 | unsigned int size; //total number of nodes in this table 55 | spinlock_t tableLock; 56 | }; 57 | 58 | /* Print functions */ 59 | void PIAS_Print_Flow(struct PIAS_Flow* f, int type); 60 | void PIAS_Print_Node(struct PIAS_Flow_Node* fn); 61 | void PIAS_Print_List(struct PIAS_Flow_List* fl); 62 | void PIAS_Print_Table(struct PIAS_Flow_Table* ft); 63 | 64 | inline unsigned int PIAS_Hash(struct PIAS_Flow* f); 65 | inline bool PIAS_Equal(struct PIAS_Flow* f1,struct PIAS_Flow* f2); 66 | 67 | /* Initialization functions */ 68 | void PIAS_Init_Info(struct PIAS_Flow_Info* info); 69 | void PIAS_Init_Flow(struct PIAS_Flow* f); 70 | void PIAS_Init_Node(struct PIAS_Flow_Node* fn); 71 | void PIAS_Init_List(struct PIAS_Flow_List* fl); 72 | void PIAS_Init_Table(struct PIAS_Flow_Table* ft); 73 | 74 | /* Insert functions: insert a new flow entry to flow table/list */ 75 | unsigned int PIAS_Insert_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f, int flags); 76 | unsigned int PIAS_Insert_Table(struct PIAS_Flow_Table* ft,struct PIAS_Flow* f, int flags); 77 | 78 | /* Search functions: search a flow entry from flow table/list */ 79 | struct PIAS_Flow_Info* PIAS_Search_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f); 80 | struct PIAS_Flow_Info* PIAS_Search_Table(struct PIAS_Flow_Table* ft, struct PIAS_Flow* f); 81 | 82 | /* Delete functions: delete a flow entry from flow table/list */ 83 | u32 PIAS_Delete_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f); 84 | u32 PIAS_Delete_Table(struct PIAS_Flow_Table* ft,struct PIAS_Flow* f); 85 | 86 | /* Clear functions: clear flow entries from flow table/list */ 87 | void PIAS_Clear_List(struct PIAS_Flow_List* fl); 88 | void PIAS_Clear_Table(struct PIAS_Flow_Table* ft); 89 | 90 | /* Exit functions: delete whole flow table */ 91 | void PIAS_Exit_List(struct PIAS_Flow_List* fl); 92 | void PIAS_Exit_Table(struct PIAS_Flow_Table* ft); 93 | 94 | #endif -------------------------------------------------------------------------------- /pias3/network.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "network.h" 6 | #include "params.h" 7 | 8 | /* Based on size, return DSCP value. We have 8 priorities at most. */ 9 | u8 PIAS_priority(u32 size) 10 | { 11 | if(size<=PIAS_PRIO_THRESH_1) 12 | return (u8)PIAS_PRIO_DSCP_1; 13 | else if(size<=PIAS_PRIO_THRESH_2) 14 | return (u8)PIAS_PRIO_DSCP_2; 15 | else if(size<=PIAS_PRIO_THRESH_3) 16 | return (u8)PIAS_PRIO_DSCP_3; 17 | else if(size<=PIAS_PRIO_THRESH_4) 18 | return (u8)PIAS_PRIO_DSCP_4; 19 | else if(size<=PIAS_PRIO_THRESH_5) 20 | return (u8)PIAS_PRIO_DSCP_5; 21 | else if(size<=PIAS_PRIO_THRESH_6) 22 | return (u8)PIAS_PRIO_DSCP_6; 23 | else if(size<=PIAS_PRIO_THRESH_7) 24 | return (u8)PIAS_PRIO_DSCP_7; 25 | else 26 | return (u8)PIAS_PRIO_DSCP_8; 27 | } 28 | 29 | /* mark DSCP and enable ECN */ 30 | inline void PIAS_enable_ecn_dscp(struct sk_buff *skb, u8 dscp) 31 | { 32 | if(skb_make_writable(skb,sizeof(struct iphdr))) 33 | { 34 | ipv4_change_dsfield(ip_hdr(skb), 0xff, (dscp<<2)|INET_ECN_ECT_0); 35 | } 36 | } 37 | 38 | /* 39 | * Maximum unsigned 32-bit integer value: 4294967295 40 | * Function: determine whether seq1 is larger than seq2 41 | * If Yes, return 1. Else, return 0. 42 | * We use a simple heuristic to handle wrapped TCP sequence number. 43 | */ 44 | inline bool PIAS_is_seq_larger(u32 seq1, u32 seq2) 45 | { 46 | if(likely(seq1>seq2&&seq1-seq2<=4294900000)) 47 | return 1; 48 | else if(seq14294900000) 49 | return 1; 50 | else 51 | return 0; 52 | } 53 | 54 | /* Calculate gap between seq1 and seq2 */ 55 | u32 PIAS_seq_gap(u32 seq1, u32 seq2) 56 | { 57 | //seq1 is larger seq2 58 | if(PIAS_is_seq_larger(seq1,seq2)==1) 59 | { 60 | if(likely(seq1>seq2)) 61 | return seq1-seq2; 62 | else 63 | return 4294967295-(seq2-seq1); 64 | } 65 | else 66 | { 67 | if(likely(seq2>seq1)) 68 | return seq2-seq1; 69 | else 70 | return 4294967295-(seq1-seq2); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pias3/network.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETWORK_H__ 2 | #define __NETWORK_H__ 3 | 4 | #include 5 | #include 6 | 7 | /* Based on size, return DSCP value */ 8 | u8 PIAS_priority(u32 size); 9 | 10 | /* Mark DSCP and enable ECN */ 11 | inline void PIAS_enable_ecn_dscp(struct sk_buff *skb, u8 dscp); 12 | 13 | /* Determine whether seq1 is larger than seq2 */ 14 | inline bool PIAS_is_seq_larger(u32 seq1, u32 seq2); 15 | 16 | /* Calculate gap between seq1 and seq2 */ 17 | u32 PIAS_seq_gap(u32 larger, u32 smaller); 18 | 19 | #endif 20 | 21 | -------------------------------------------------------------------------------- /pias3/params.c: -------------------------------------------------------------------------------- 1 | #include "params.h" 2 | #include 3 | #include 4 | 5 | int PIAS_RTO_MIN=8*1000; 6 | int PIAS_TIMEOUT_THRESH=2; 7 | int PIAS_SEQ_GAP_THRESH=3*1448; 8 | 9 | int PIAS_PRIO_DSCP_1=7; 10 | int PIAS_PRIO_DSCP_2=6; 11 | int PIAS_PRIO_DSCP_3=5; 12 | int PIAS_PRIO_DSCP_4=4; 13 | int PIAS_PRIO_DSCP_5=3; 14 | int PIAS_PRIO_DSCP_6=2; 15 | int PIAS_PRIO_DSCP_7=1; 16 | int PIAS_PRIO_DSCP_8=0; 17 | 18 | int PIAS_PRIO_THRESH_1=20*1024; 19 | int PIAS_PRIO_THRESH_2=2147483647; 20 | int PIAS_PRIO_THRESH_3=2147483647; 21 | int PIAS_PRIO_THRESH_4=2147483647; 22 | int PIAS_PRIO_THRESH_5=2147483647; 23 | int PIAS_PRIO_THRESH_6=2147483647; 24 | int PIAS_PRIO_THRESH_7=2147483647; 25 | 26 | /* All parameters that can be configured through sysctl */ 27 | struct PIAS_param PIAS_params[32]={ 28 | {"PIAS_RTO_MIN\0", &PIAS_RTO_MIN}, 29 | {"PIAS_TIMEOUT_THRESH\0", &PIAS_TIMEOUT_THRESH}, 30 | {"PIAS_SEQ_GAP_THRESH\0", &PIAS_SEQ_GAP_THRESH}, 31 | {"PIAS_PRIO_DSCP_1\0", &PIAS_PRIO_DSCP_1}, 32 | {"PIAS_PRIO_DSCP_2\0", &PIAS_PRIO_DSCP_2}, 33 | {"PIAS_PRIO_DSCP_3\0", &PIAS_PRIO_DSCP_3}, 34 | {"PIAS_PRIO_DSCP_4\0", &PIAS_PRIO_DSCP_4}, 35 | {"PIAS_PRIO_DSCP_5\0", &PIAS_PRIO_DSCP_5}, 36 | {"PIAS_PRIO_DSCP_6\0", &PIAS_PRIO_DSCP_6}, 37 | {"PIAS_PRIO_DSCP_7\0", &PIAS_PRIO_DSCP_7}, 38 | {"PIAS_PRIO_DSCP_8\0", &PIAS_PRIO_DSCP_8}, 39 | {"PIAS_PRIO_THRESH_1\0", &PIAS_PRIO_THRESH_1}, 40 | {"PIAS_PRIO_THRESH_2\0", &PIAS_PRIO_THRESH_2}, 41 | {"PIAS_PRIO_THRESH_3\0", &PIAS_PRIO_THRESH_3}, 42 | {"PIAS_PRIO_THRESH_4\0", &PIAS_PRIO_THRESH_4}, 43 | {"PIAS_PRIO_THRESH_5\0", &PIAS_PRIO_THRESH_5}, 44 | {"PIAS_PRIO_THRESH_6\0", &PIAS_PRIO_THRESH_6}, 45 | {"PIAS_PRIO_THRESH_7\0", &PIAS_PRIO_THRESH_7}, 46 | {"\0", NULL}, 47 | }; 48 | 49 | struct ctl_table PIAS_params_table[32]; 50 | struct ctl_path PIAS_params_path[] = { 51 | { .procname = "pias" }, 52 | { }, 53 | }; 54 | struct ctl_table_header *PIAS_sysctl=NULL; 55 | 56 | int PIAS_params_init(void) 57 | { 58 | int i=0; 59 | memset(PIAS_params_table, 0, sizeof(PIAS_params_table)); 60 | 61 | for(i = 0; i < 32; i++) 62 | { 63 | struct ctl_table *entry = &PIAS_params_table[i]; 64 | //End 65 | if(PIAS_params[i].ptr == NULL) 66 | break; 67 | //Initialize entry (ctl_table) 68 | entry->procname=PIAS_params[i].name; 69 | entry->data=PIAS_params[i].ptr; 70 | entry->mode=0644; 71 | entry->proc_handler=&proc_dointvec; 72 | entry->maxlen=sizeof(int); 73 | } 74 | 75 | PIAS_sysctl=register_sysctl_paths(PIAS_params_path, PIAS_params_table); 76 | if(PIAS_sysctl==NULL) 77 | return -1; 78 | else 79 | return 0; 80 | } 81 | 82 | void PIAS_params_exit(void) 83 | { 84 | if(PIAS_sysctl!=NULL) 85 | unregister_sysctl_table(PIAS_sysctl); 86 | } 87 | -------------------------------------------------------------------------------- /pias3/params.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARAMS_H__ 2 | #define __PARAMS_H__ 3 | 4 | #include 5 | 6 | //Hash range (Number of lists) 7 | #define PIAS_HASH_RANGE (256) 8 | //Maximum lengh of a list 9 | #define PIAS_LIST_SIZE (32) 10 | //Maximum flow size (maximum value of signed 32-bit integer due to sysctl) 11 | #define PIAS_MAX_FLOW_SIZE (2147483647) 12 | 13 | //RTOmin in us 14 | extern int PIAS_RTO_MIN; 15 | //Threshold of consecutive timeouts to reset priority 16 | extern int PIAS_TIMEOUT_THRESH; 17 | //Sequence gap in bytes 18 | extern int PIAS_SEQ_GAP_THRESH; 19 | 20 | //DSCP value for different priority queues (PIAS_PRIO_DSCP_1 is for the highest priority) 21 | extern int PIAS_PRIO_DSCP_1; 22 | extern int PIAS_PRIO_DSCP_2; 23 | extern int PIAS_PRIO_DSCP_3; 24 | extern int PIAS_PRIO_DSCP_4; 25 | extern int PIAS_PRIO_DSCP_5; 26 | extern int PIAS_PRIO_DSCP_6; 27 | extern int PIAS_PRIO_DSCP_7; 28 | extern int PIAS_PRIO_DSCP_8; 29 | 30 | //7 demotion thresholds in bytes. PIAS_PRIO_THRESH_1 is the smallest one 31 | extern int PIAS_PRIO_THRESH_1; 32 | extern int PIAS_PRIO_THRESH_2; 33 | extern int PIAS_PRIO_THRESH_3; 34 | extern int PIAS_PRIO_THRESH_4; 35 | extern int PIAS_PRIO_THRESH_5; 36 | extern int PIAS_PRIO_THRESH_6; 37 | extern int PIAS_PRIO_THRESH_7; 38 | 39 | struct PIAS_param { 40 | char name[64]; 41 | int *ptr; 42 | }; 43 | 44 | extern struct PIAS_param PIAS_params[32]; 45 | 46 | 47 | //Intialize parameters and register sysctl 48 | int PIAS_params_init(void); 49 | //Unregister sysctl 50 | void PIAS_params_exit(void); 51 | 52 | #endif -------------------------------------------------------------------------------- /pias4/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += pias.o 2 | pias-y := params.o netfilter.o jprobe.o flow.o network.o main.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 9 | -------------------------------------------------------------------------------- /pias4/flow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flow.h" 6 | 7 | /* Print a flow information. Operation: "Add", "Delete", etc.*/ 8 | void PIAS_Print_Flow(struct PIAS_Flow* f, char* operation) 9 | { 10 | char local_ip[16] = {0}; //Local IP address 11 | char remote_ip[16] = {0}; //Remote IP address 12 | 13 | if (unlikely(!f)) 14 | { 15 | printk(KERN_INFO "PIAS_Print_Flow: NULL pointer\n"); 16 | return; 17 | } 18 | 19 | snprintf(local_ip, 16, "%pI4", &(f->local_ip)); 20 | snprintf(remote_ip, 16, "%pI4", &(f->remote_ip)); 21 | 22 | if (operation) 23 | printk(KERN_INFO "PIAS: %s a flow record from %s:%hu to %s:%hu bytes_sent=%u seq=%u ACK=%u\n", operation, local_ip, f->local_port, remote_ip, f->remote_port, f->info.bytes_sent, f->info.last_seq, f->info.last_ack); 24 | else 25 | printk(KERN_INFO "PIAS: a flow record from %s:%hu to %s:%hu bytes_sent=%u seq=%u ACK=%u\n", local_ip, f->local_port, remote_ip, f->remote_port, f->info.bytes_sent, f->info.last_seq, f->info.last_ack); 26 | } 27 | 28 | /* Print a Flow List */ 29 | void PIAS_Print_List(struct PIAS_Flow_List* fl) 30 | { 31 | struct PIAS_Flow* ptr = NULL; 32 | 33 | if (unlikely(!fl)) 34 | { 35 | printk(KERN_INFO "PIAS_Print_List: NULL pointer\n"); 36 | return; 37 | } 38 | 39 | list_for_each_entry(ptr, &(fl->head_node), list) 40 | PIAS_Print_Flow(ptr, NULL); 41 | } 42 | 43 | /* Print a Flow Table */ 44 | void PIAS_Print_Table(struct PIAS_Flow_Table* ft) 45 | { 46 | int i = 0; 47 | 48 | if (unlikely(!ft)) 49 | { 50 | printk(KERN_INFO "PIAS_Print_Table: NULL pointer\n"); 51 | return; 52 | } 53 | 54 | printk(KERN_INFO "PIAS: current flow table\n"); 55 | for (i = 0; i < PIAS_HASH_RANGE; i++) 56 | { 57 | if (ft->flow_lists[i].len > 0) 58 | { 59 | printk(KERN_INFO "PIAS: flowlist %d\n", i); 60 | PIAS_Print_List(&(ft->flow_lists[i])); 61 | } 62 | } 63 | printk(KERN_INFO "PIAS: there are %d flows in total\n", atomic_read(&(ft->size))); 64 | } 65 | 66 | /* Hash function, calculate the flow should be inserted into which PIAS_Flow_List */ 67 | inline unsigned int PIAS_Hash_Flow(struct PIAS_Flow* f) 68 | { 69 | //return a value in [0,HASH_RANGE-1] 70 | if (likely(f)) 71 | return (((f->local_ip >> 24) + 1) * ((f->remote_ip >> 24) + 1) * (f->local_port + 1) * (f->remote_port + 1)) % PIAS_HASH_RANGE; 72 | else 73 | { 74 | printk(KERN_INFO "PIAS_Hash_Flow: NULL pointer\n"); 75 | return 0; 76 | } 77 | } 78 | 79 | /* Determine whether two Flows are equal. determines a flow */ 80 | inline bool PIAS_Equal_Flow(struct PIAS_Flow* f1, struct PIAS_Flow* f2) 81 | { 82 | if (likely(f1 && f2)) 83 | return (f1->local_ip == f2->local_ip) && (f1->remote_ip == f2->remote_ip) && (f1->local_port == f2->local_port) && (f1->remote_port == f2->remote_port); 84 | else 85 | { 86 | printk(KERN_INFO "PIAS_Equal_Flow: NULL pointer\n"); 87 | return false; 88 | } 89 | } 90 | 91 | /* Initialize the info of a Flow */ 92 | bool PIAS_Init_Info(struct PIAS_Flow_Info* info) 93 | { 94 | //We need to initialize 7 variables in total 95 | if (likely(info)) 96 | { 97 | info->last_copy_time = ktime_set(0, 0); 98 | info->last_update_time = ktime_set(0, 0); 99 | info->last_timeout_seq = 0; 100 | info->last_seq = 0; 101 | info->last_ack = 0; 102 | info->bytes_sent = 0; 103 | info->timeouts = 0; 104 | info->messages = 0; 105 | return true; 106 | } 107 | else 108 | { 109 | printk(KERN_INFO "PIAS_Init_Info: NULL pointer\n"); 110 | return false; 111 | } 112 | } 113 | 114 | /* Initialize a Flow */ 115 | bool PIAS_Init_Flow(struct PIAS_Flow* f) 116 | { 117 | if (likely(f)) 118 | { 119 | f->local_ip = 0; 120 | f->remote_ip = 0; 121 | f->local_port = 0; 122 | f->remote_port = 0; 123 | INIT_LIST_HEAD(&(f->list)); 124 | spin_lock_init(&(f->lock)); 125 | //Initialize the Info of this Flow 126 | PIAS_Init_Info(&(f->info)); 127 | return true; 128 | } 129 | else 130 | { 131 | printk(KERN_INFO "PIAS_Init_Flow: NULL pointer\n"); 132 | return false; 133 | } 134 | } 135 | 136 | /* Initialize a Flow List */ 137 | bool PIAS_Init_List(struct PIAS_Flow_List* fl) 138 | { 139 | if (likely(fl)) 140 | { 141 | fl->len = 0; 142 | INIT_LIST_HEAD(&(fl->head_node)); 143 | spin_lock_init(&(fl->lock)); 144 | return true; 145 | } 146 | else 147 | { 148 | printk(KERN_INFO "PIAS_Init_List: NULL pointer\n"); 149 | return false; 150 | } 151 | } 152 | 153 | /* Initialize a Flow Table */ 154 | bool PIAS_Init_Table(struct PIAS_Flow_Table* ft) 155 | { 156 | int i = 0; 157 | struct PIAS_Flow_List* buf = NULL; 158 | 159 | if (unlikely(!ft)) 160 | { 161 | printk(KERN_INFO "PIAS_Init_Table: NULL pointer\n"); 162 | return false; 163 | } 164 | 165 | buf = vmalloc(PIAS_HASH_RANGE * sizeof(struct PIAS_Flow_List)); 166 | if (buf) 167 | { 168 | ft->flow_lists = buf; 169 | atomic_set(&(ft->size), 0); 170 | 171 | for (i = 0; i < PIAS_HASH_RANGE; i++) 172 | { 173 | if (!PIAS_Init_List(&(ft->flow_lists[i]))) 174 | return false; 175 | } 176 | return true; 177 | } 178 | else 179 | { 180 | printk(KERN_INFO "PIAS_Init_Table: vmalloc error\n"); 181 | return false; 182 | } 183 | } 184 | 185 | /* Search and return the pointer of given flow in a Flow List */ 186 | struct PIAS_Flow* PIAS_Search_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f) 187 | { 188 | struct PIAS_Flow* ptr = NULL; 189 | 190 | if (unlikely(!fl || !f)) 191 | { 192 | printk(KERN_INFO "PIAS_Search_List: NULL pointer\n"); 193 | return NULL; 194 | } 195 | 196 | list_for_each_entry(ptr, &(fl->head_node), list) 197 | { 198 | if (PIAS_Equal_Flow(ptr, f)) 199 | return ptr; 200 | } 201 | 202 | return NULL; 203 | } 204 | 205 | /* Search the information for a given Flow in a Flow Table */ 206 | struct PIAS_Flow* PIAS_Search_Table(struct PIAS_Flow_Table* ft, struct PIAS_Flow* f) 207 | { 208 | unsigned int index = 0; 209 | 210 | if (unlikely(!ft || !f)) 211 | { 212 | printk(KERN_INFO "PIAS_Search_Table: NULL pointer\n"); 213 | return NULL; 214 | } 215 | 216 | index = PIAS_Hash_Flow(f); 217 | return PIAS_Search_List(&(ft->flow_lists[index]), f); 218 | } 219 | 220 | /* Insert a Flow into a Flow List and return true if it succeeds */ 221 | bool PIAS_Insert_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f, int flags) 222 | { 223 | struct PIAS_Flow* buf = NULL; 224 | unsigned long tmp; //variable for save current states of irq 225 | 226 | if (unlikely(!fl || !f)) 227 | { 228 | printk(KERN_INFO "PIAS_Insert_List: NULL pointer\n"); 229 | return false; 230 | } 231 | 232 | //No such flow entry in this Flow List 233 | if (PIAS_Search_List(fl, f)) 234 | { 235 | printk(KERN_INFO "PIAS_Insert_List: equal flow\n"); 236 | return false; 237 | } 238 | else 239 | { 240 | //Allocate memory 241 | buf = kmalloc(sizeof(struct PIAS_Flow), flags); 242 | if (!buf) 243 | { 244 | printk(KERN_INFO "PIAS_Insert_List: kmalloc error\n"); 245 | return false; 246 | } 247 | *buf = *f; 248 | INIT_LIST_HEAD(&(buf->list)); 249 | spin_lock_init(&(buf->lock)); 250 | 251 | spin_lock_irqsave(&(fl->lock), tmp); 252 | list_add_tail(&(buf->list), &(fl->head_node)); 253 | fl->len++; 254 | spin_unlock_irqrestore(&(fl->lock), tmp); 255 | 256 | return true; 257 | } 258 | } 259 | 260 | /* Insert a Flow into a Flow Table and return true if it succeeds */ 261 | bool PIAS_Insert_Table(struct PIAS_Flow_Table* ft, struct PIAS_Flow* f, int flags) 262 | { 263 | unsigned int index = 0; 264 | 265 | if (unlikely(!ft || !f)) 266 | { 267 | printk(KERN_INFO "PIAS_Insert_Table: NULL pointer\n"); 268 | return false; 269 | } 270 | 271 | index = PIAS_Hash_Flow(f); 272 | if (PIAS_Insert_List(&(ft->flow_lists[index]), f, flags)) 273 | { 274 | atomic_inc(&(ft->size)); 275 | return true; 276 | } 277 | else 278 | return false; 279 | } 280 | 281 | /* Delete a Flow from a Flow List and return the bytes_sent (>=1) of this flow if it succeeds */ 282 | u32 PIAS_Delete_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f) 283 | { 284 | struct PIAS_Flow *ptr, *next; 285 | unsigned long tmp; 286 | u32 result; 287 | 288 | if (unlikely(!fl || !f)) 289 | { 290 | printk(KERN_INFO "PIAS_Delete_List: NULL pointer\n"); 291 | return 0; 292 | } 293 | 294 | list_for_each_entry_safe(ptr, next, &(fl->head_node), list) 295 | { 296 | if (PIAS_Equal_Flow(ptr, f)) 297 | { 298 | spin_lock_irqsave(&(fl->lock), tmp); 299 | result = max_t(u32, 1, ptr->info.bytes_sent); 300 | list_del(&(ptr->list)); 301 | kfree(ptr); 302 | fl->len--; 303 | spin_unlock_irqrestore(&(fl->lock), tmp); 304 | return result; 305 | } 306 | } 307 | 308 | return 0; 309 | } 310 | 311 | /* Delete a Flow from a Flow Table and return the bytes_sent (>=1) of this flow if it succeeds */ 312 | u32 PIAS_Delete_Table(struct PIAS_Flow_Table* ft, struct PIAS_Flow* f) 313 | { 314 | u32 result = 0; 315 | unsigned int index = 0; 316 | 317 | if (unlikely(!ft || !f)) 318 | { 319 | printk(KERN_INFO "PIAS_Delete_Table: NULL pointer\n"); 320 | return 0; 321 | } 322 | 323 | index = PIAS_Hash_Flow(f); 324 | result = PIAS_Delete_List(&(ft->flow_lists[index]), f); 325 | if (result > 0) 326 | atomic_dec(&(ft->size)); 327 | 328 | return result; 329 | } 330 | 331 | /* Delete all flow entries in this Flow List */ 332 | bool PIAS_Clear_List(struct PIAS_Flow_List* fl) 333 | { 334 | struct PIAS_Flow *ptr, *next; 335 | unsigned long tmp; 336 | 337 | if (unlikely(!fl)) 338 | { 339 | printk(KERN_INFO "PIAS_Clear_List: NULL pointer\n"); 340 | return false; 341 | } 342 | 343 | if (fl->len > 0) 344 | { 345 | spin_lock_irqsave(&(fl->lock), tmp); 346 | list_for_each_entry_safe(ptr, next, &(fl->head_node), list) 347 | { 348 | list_del(&(ptr->list)); 349 | kfree(ptr); 350 | fl->len--; 351 | } 352 | spin_unlock_irqrestore(&(fl->lock), tmp); 353 | } 354 | 355 | return true; 356 | } 357 | 358 | /* Delete all flow entries in this Flow Table */ 359 | bool PIAS_Clear_Table(struct PIAS_Flow_Table* ft) 360 | { 361 | int i = 0; 362 | 363 | if (unlikely(!ft)) 364 | { 365 | printk(KERN_INFO "PIAS_Clear_Table: NULL pointer\n"); 366 | return false; 367 | } 368 | 369 | for (i = 0; i < PIAS_HASH_RANGE; i++) 370 | { 371 | if (unlikely(!PIAS_Clear_List(&(ft->flow_lists[i])))) 372 | printk(KERN_INFO "Cannot clear flow list %d\n", i); 373 | } 374 | 375 | atomic_set(&(ft->size), 0); 376 | return true; 377 | } 378 | 379 | bool PIAS_Exit_Table(struct PIAS_Flow_Table* ft) 380 | { 381 | if (likely(PIAS_Clear_Table(ft))) 382 | { 383 | vfree(ft->flow_lists); 384 | return true; 385 | } 386 | else 387 | return false; 388 | } 389 | -------------------------------------------------------------------------------- /pias4/flow.h: -------------------------------------------------------------------------------- 1 | #ifndef __FLOW_H__ 2 | #define __FLOW_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | //Hash range (Number of flow lists) 9 | #define PIAS_HASH_RANGE 256 10 | 11 | /* 12 | * Define structure of information for a TCP flow (connections) 13 | * last_copy_time: last time when we observe data copy from user space to kernel TCP send buffer 14 | * last_update_time: last time when we observe an outgoing packet (from local side to remote side) 15 | * last_timeout_seq: sequence number for the lastest TCP timeout 16 | * last_seq: the latest (largest) sequence number for outoging traffic 17 | * last_ack: the latest (largest) ACK number for outoging traffic 18 | * bytes_sent: bytes sent of outgoing traffic 19 | * timeouts: the number of consecutive timeouts experienced by outgoing traffic 20 | * messages: the number of messages in this TCP connections 21 | */ 22 | 23 | struct PIAS_Flow_Info 24 | { 25 | ktime_t last_copy_time; 26 | ktime_t last_update_time; 27 | u32 last_timeout_seq; 28 | u32 last_seq; 29 | u32 last_ack; 30 | u32 bytes_sent; 31 | u16 timeouts; 32 | u16 messages; 33 | }; 34 | 35 | /* A TCP Flow is defined by 4-tuple and its related information */ 36 | struct PIAS_Flow 37 | { 38 | u32 local_ip; //Local IP address 39 | u32 remote_ip; //Remote IP address 40 | u16 local_port; //Local TCP port 41 | u16 remote_port; //Remote TCP port 42 | struct PIAS_Flow_Info info; //Information for this flow 43 | spinlock_t lock; //lock for this flow 44 | struct list_head list; //linked list 45 | }; 46 | 47 | /* Link List of Flows */ 48 | struct PIAS_Flow_List 49 | { 50 | struct list_head head_node; //head node of the flow list 51 | unsigned int len; //total number of flows in the list 52 | spinlock_t lock; //lock for this flow list 53 | }; 54 | 55 | /* Hash Table of Flows */ 56 | struct PIAS_Flow_Table 57 | { 58 | struct PIAS_Flow_List* flow_lists; //array of linked lists to store per-flow information 59 | atomic_t size; 60 | }; 61 | 62 | /* Print functions */ 63 | void PIAS_Print_Flow(struct PIAS_Flow* f, char* operation); 64 | void PIAS_Print_List(struct PIAS_Flow_List* fl); 65 | void PIAS_Print_Table(struct PIAS_Flow_Table* ft); 66 | 67 | inline unsigned int PIAS_Hash_Flow(struct PIAS_Flow* f); 68 | inline bool PIAS_Equal_Flow(struct PIAS_Flow* f1, struct PIAS_Flow* f2); 69 | 70 | /* Initialization functions */ 71 | bool PIAS_Init_Info(struct PIAS_Flow_Info* info); 72 | bool PIAS_Init_Flow(struct PIAS_Flow* f); 73 | bool PIAS_Init_List(struct PIAS_Flow_List* fl); 74 | bool PIAS_Init_Table(struct PIAS_Flow_Table* ft); 75 | 76 | /* Search functions: search a flow entry from flow table/list */ 77 | struct PIAS_Flow* PIAS_Search_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f); 78 | struct PIAS_Flow* PIAS_Search_Table(struct PIAS_Flow_Table* ft, struct PIAS_Flow* f); 79 | 80 | /* Insert functions: insert a new flow entry to flow table/list */ 81 | bool PIAS_Insert_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f, int flags); 82 | bool PIAS_Insert_Table(struct PIAS_Flow_Table* ft,struct PIAS_Flow* f, int flags); 83 | 84 | /* Delete functions: delete a flow entry from flow table/list */ 85 | u32 PIAS_Delete_List(struct PIAS_Flow_List* fl, struct PIAS_Flow* f); 86 | u32 PIAS_Delete_Table(struct PIAS_Flow_Table* ft, struct PIAS_Flow* f); 87 | 88 | /* Clear functions: clear flow entries from flow table/list */ 89 | bool PIAS_Clear_List(struct PIAS_Flow_List* fl); 90 | bool PIAS_Clear_Table(struct PIAS_Flow_Table* ft); 91 | 92 | /* Exit functions: delete whole flow table */ 93 | bool PIAS_Exit_Table(struct PIAS_Flow_Table* ft); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /pias4/jprobe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "jprobe.h" 7 | #include "flow.h" 8 | #include "params.h" 9 | 10 | /* Flow Table */ 11 | extern struct PIAS_Flow_Table ft; 12 | /* TCP port */ 13 | extern int param_port; 14 | 15 | /* Hook inserted to be called before each socket call. 16 | * Note: arguments must match tcp_sendmsg()! */ 17 | static int jtcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t size) 18 | { 19 | struct PIAS_Flow f; //PIAS flow structure 20 | struct PIAS_Flow *ptr = NULL; //pointer to PIAS flow structure 21 | ktime_t now = ktime_get(); //get current time 22 | const struct tcp_sock *tp = tcp_sk(sk); 23 | const struct inet_sock *inet = inet_sk(sk); 24 | s64 idle_time = 0; //idle time in us 25 | unsigned long flags; 26 | 27 | f.local_ip = inet->inet_saddr; 28 | f.remote_ip = inet->inet_daddr; 29 | f.local_port = (u16)ntohs(inet->inet_sport); 30 | f.remote_port = (u16)ntohs(inet->inet_dport); 31 | 32 | if (param_port == 0 || f.local_port == param_port || f.remote_port == param_port) 33 | { 34 | ptr = PIAS_Search_Table(&ft, &f); 35 | if (ptr) 36 | { 37 | spin_lock_irqsave(&(ptr->lock), flags); 38 | //First message in this connections 39 | if (ptr->info.last_copy_time.tv64 == 0) 40 | { 41 | ptr->info.messages++; 42 | if (PIAS_DEBUG_MODE) 43 | printk(KERN_INFO "Meesage %hu is detected on TCP connection %pI4:%hu to %pI4:%hu\n", ptr->info.messages, &(f.local_ip), f.local_port, &(f.remote_ip), f.remote_port); 44 | } 45 | else if(tp->snd_nxt == tp->write_seq) 46 | { 47 | idle_time = ktime_us_delta(now, ptr->info.last_copy_time); 48 | if (idle_time > PIAS_IDLE_TIME) 49 | { 50 | ptr->info.bytes_sent = 0; 51 | ptr->info.messages++; 52 | if (PIAS_DEBUG_MODE) 53 | printk(KERN_INFO "Message %hu is detected on TCP connection %pI4:%hu to %pI4:%hu after %lld us idle time\n", ptr->info.messages, &(f.local_ip), f.local_port, &(f.remote_ip), f.remote_port, idle_time); 54 | } 55 | } 56 | ptr->info.last_copy_time = now; 57 | spin_unlock_irqrestore(&(ptr->lock), flags); 58 | } 59 | } 60 | 61 | jprobe_return(); 62 | return 0; 63 | } 64 | 65 | static struct jprobe pias_tcp_sendmsg = 66 | { 67 | .kp = { .symbol_name = "tcp_sendmsg",}, 68 | .entry = jtcp_sendmsg, 69 | }; 70 | 71 | bool PIAS_JProbe_Init(void) 72 | { 73 | pias_tcp_sendmsg.kp.symbol_name = "tcp_sendmsg"; 74 | pias_tcp_sendmsg.entry = jtcp_sendmsg; 75 | 76 | //Register jprobe hook 77 | BUILD_BUG_ON(__same_type(tcp_sendmsg, jtcp_sendmsg) == 0); 78 | if (register_jprobe(&pias_tcp_sendmsg)) 79 | { 80 | printk(KERN_INFO "Cannot register the jprobe hook for tcp_sendmsg\n"); 81 | return false; 82 | } 83 | else 84 | return true; 85 | } 86 | 87 | void PIAS_JProbe_Exit(void) 88 | { 89 | //Unregister jprobe hook 90 | unregister_jprobe(&pias_tcp_sendmsg); 91 | } 92 | -------------------------------------------------------------------------------- /pias4/jprobe.h: -------------------------------------------------------------------------------- 1 | #ifndef JPROBE_H 2 | #define JPROBE_H 3 | 4 | /* Install jprobe hooks */ 5 | bool PIAS_JProbe_Init(void); 6 | /* Uninstall jprobe hooks */ 7 | void PIAS_JProbe_Exit(void); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /pias4/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "netfilter.h" 5 | #include "jprobe.h" 6 | #include "params.h" 7 | #include "flow.h" 8 | 9 | /* Flow Table */ 10 | struct PIAS_Flow_Table ft; 11 | 12 | /* 13 | * The following two functions are related to param_table_operation 14 | * To clear flow table: echo -n clear > /sys/module/pias/parameters/param_table_operation 15 | * To print flow table: echo -n print > /sys/module/pias/parameters/param_table_operation 16 | */ 17 | static int pias_set_operation(const char *val, struct kernel_param *kp); 18 | static int pias_noget(const char *val, struct kernel_param *kp); 19 | module_param_call(param_table_operation, pias_set_operation, pias_noget, NULL, S_IWUSR); //Write permission by owner 20 | 21 | /* param_dev: NIC to operate PIAS */ 22 | char *param_dev = NULL; 23 | MODULE_PARM_DESC(param_dev, "Interface to operate PIAS (NULL=all)"); 24 | module_param(param_dev, charp, 0); 25 | 26 | int param_port __read_mostly = 0; 27 | MODULE_PARM_DESC(param_port, "Port to match (0=all)"); 28 | module_param(param_port, int, 0); 29 | 30 | static int pias_set_operation(const char *val, struct kernel_param *kp) 31 | { 32 | //For debug 33 | //printk(KERN_INFO "PIAS: param_table_operation is set\n"); 34 | //Clear flow table 35 | if (strncmp(val, "clear", 5) == 0) 36 | { 37 | printk(KERN_INFO "PIAS: clear flow table\n"); 38 | PIAS_Clear_Table(&ft); 39 | } 40 | //Print flow table 41 | else if (strncmp(val, "print", 5) == 0) 42 | { 43 | printk(KERN_INFO "PIAS: print flow table\n"); 44 | PIAS_Print_Table(&ft); 45 | } 46 | else 47 | printk(KERN_INFO "PIAS: unrecognized flow table operation\n"); 48 | 49 | return 0; 50 | } 51 | 52 | static int pias_noget(const char *val, struct kernel_param *kp) 53 | { 54 | return 0; 55 | } 56 | 57 | 58 | static int pias_module_init(void) 59 | { 60 | int i = 0; 61 | 62 | //Get interface 63 | if (param_dev) 64 | { 65 | // trim 66 | for (i = 0; i < 32 && param_dev[i] != '\0'; i++) 67 | { 68 | if(param_dev[i] == '\n') 69 | { 70 | param_dev[i] = '\0'; 71 | break; 72 | } 73 | } 74 | } 75 | 76 | //Initialize FlowTable 77 | PIAS_Init_Table(&ft); 78 | 79 | if (PIAS_Params_Init() && PIAS_Netfilter_Init() && PIAS_JProbe_Init()) 80 | { 81 | printk(KERN_INFO "PIAS: start on %s (TCP port %d)\n", param_dev? param_dev:"any interface", param_port); 82 | return 0; 83 | } 84 | else 85 | return -1; 86 | } 87 | 88 | static void pias_module_exit(void) 89 | { 90 | PIAS_JProbe_Exit(); 91 | PIAS_Netfilter_Exit(); 92 | PIAS_Params_Exit(); 93 | PIAS_Exit_Table(&ft); 94 | 95 | printk(KERN_INFO "PIAS: stop working\n"); 96 | } 97 | 98 | module_init(pias_module_init); 99 | module_exit(pias_module_exit); 100 | 101 | MODULE_LICENSE("GPL"); 102 | MODULE_AUTHOR("BAI Wei baiwei0427@gmail.com"); 103 | MODULE_VERSION("1.3"); 104 | MODULE_DESCRIPTION("Linux kernel module for PIAS (Practical Information-Agnostic flow Scheduling)"); 105 | -------------------------------------------------------------------------------- /pias4/netfilter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "netfilter.h" 10 | #include "flow.h" 11 | #include "network.h" 12 | #include "params.h" 13 | 14 | /* Flow Table */ 15 | extern struct PIAS_Flow_Table ft; 16 | /* NIC device name */ 17 | extern char *param_dev; 18 | /* TCP port */ 19 | extern int param_port; 20 | 21 | /* The Netfilter hook for outgoing packets */ 22 | static struct nf_hook_ops pias_nf_hook_out; 23 | /* The Netfilter hook for incoming packets */ 24 | static struct nf_hook_ops pias_nf_hook_in; 25 | 26 | /* Hook function for outgoing packets */ 27 | static unsigned int pias_hook_func_out(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 28 | { 29 | struct iphdr *iph = NULL; //IP header structure 30 | struct tcphdr *tcph = NULL; //TCP header structure 31 | struct PIAS_Flow f; //PIAS flow structure 32 | struct PIAS_Flow *ptr = NULL; //pointer to PIAS flow structure 33 | unsigned long flags; //variable for save current states of irq 34 | int dscp = 0; //DSCP value 35 | u16 payload_len = 0; //TCP payload length 36 | u32 seq = 0; //TCP sequence number 37 | u32 result = 0; //Delete_Table return result 38 | s64 idle_time = 0; 39 | ktime_t now = ktime_get(); //get current time 40 | 41 | if (!out) 42 | return NF_ACCEPT; 43 | 44 | if (param_dev && strncmp(out->name, param_dev, IFNAMSIZ) != 0) 45 | return NF_ACCEPT; 46 | 47 | //Get IP header 48 | iph = ip_hdr(skb); 49 | //The packet is not an IP packet (e.g. ARP or others), return NF_ACCEPT 50 | if (unlikely(!iph)) 51 | return NF_ACCEPT; 52 | 53 | if (iph->protocol == IPPROTO_TCP) 54 | { 55 | tcph = (struct tcphdr *)((__u32 *)iph + iph->ihl); 56 | 57 | if (param_port != 0 && ntohs(tcph->source) != param_port && ntohs(tcph->dest) != param_port) 58 | return NF_ACCEPT; 59 | 60 | PIAS_Init_Flow(&f); 61 | f.local_ip = iph->saddr; 62 | f.remote_ip = iph->daddr; 63 | f.local_port = (u16)ntohs(tcph->source); 64 | f.remote_port = (u16)ntohs(tcph->dest); 65 | 66 | //TCP SYN packet, a new connection 67 | if(tcph->syn) 68 | { 69 | f.info.last_seq = ntohl(tcph->seq); 70 | f.info.last_update_time = now; 71 | //A new Flow entry should be inserted into FlowTable 72 | if (!PIAS_Insert_Table(&ft, &f, GFP_ATOMIC)) 73 | printk(KERN_INFO "PIAS: insert fail\n"); 74 | 75 | dscp = pias_priority(0); 76 | } 77 | //TCP FIN/RST packets, connection will be closed 78 | else if (tcph->fin || tcph->rst) 79 | { 80 | result = PIAS_Delete_Table(&ft, &f); 81 | if (result == 0) 82 | printk(KERN_INFO "PIAS: delete fail\n"); 83 | 84 | dscp = pias_priority(result); 85 | } 86 | else 87 | { 88 | //TCP payload length=Total IP length - IP header length-TCP header length 89 | payload_len = ntohs(iph->tot_len) - (iph->ihl << 2) - (tcph->doff << 2); 90 | seq = (u32)ntohl(tcph->seq); 91 | //Get the sequence number of the last payload byte 92 | if (payload_len >= 1) 93 | seq = seq + payload_len - 1; 94 | 95 | //Update existing Flow entry's information 96 | ptr = PIAS_Search_Table(&ft, &f); 97 | if (ptr) 98 | { 99 | spin_lock_irqsave(&(ptr->lock), flags); 100 | idle_time = ktime_us_delta(now, ptr->info.last_update_time); 101 | //A new TCP packet 102 | if (pias_is_seq_larger(seq, ptr->info.last_seq)) 103 | { 104 | //Update sequence number 105 | ptr->info.last_seq = seq; 106 | //Update bytes sent 107 | ptr->info.bytes_sent += payload_len; 108 | } 109 | //TCP timeout? 110 | else if (idle_time >= PIAS_RTO_MIN && pias_is_seq_larger(ptr->info.last_seq, ptr->info.last_ack)) 111 | { 112 | ptr->info.last_timeout_seq = seq; 113 | //A consecutive' TCP timeout 114 | if (PIAS_TIMEOUT_THRESH == 1 || (PIAS_TIMEOUT_THRESH >= 2 && (pias_seq_gap(seq, ptr->info.last_timeout_seq) <= PIAS_TIMEOUT_SEQ_GAP))) 115 | { 116 | ptr->info.timeouts++; 117 | //If the number of consecutive TCP timeouts is larger than the threshold 118 | if (ptr->info.timeouts >= PIAS_TIMEOUT_THRESH) 119 | { 120 | ptr->info.timeouts = 0; 121 | //Reset bytes sent to zero (highest priority) when aging is enabled 122 | if (PIAS_ENABLE_AGING == 1) 123 | ptr->info.bytes_sent = 0; 124 | if (PIAS_DEBUG_MODE == 1) 125 | printk(KERN_INFO "%d consecutive TCP timeouts are detected!\n", PIAS_TIMEOUT_THRESH); 126 | } 127 | } 128 | //Not a consecutive TCP timeout 129 | else 130 | ptr->info.timeouts = 1; 131 | } 132 | //Update last_update_time of this flow 133 | ptr->info.last_update_time = now; 134 | spin_unlock_irqrestore(&(ptr->lock), flags); 135 | //Calculate priority of this flow based on bytes sent 136 | dscp = pias_priority(ptr->info.bytes_sent); 137 | } 138 | //No such Flow entry. Maybe last few packets of the flow. We need to accelerate flow completion. 139 | else 140 | dscp = pias_priority(0); 141 | } 142 | //Modify DSCP and make the packet ECT 143 | //If DSCP < 0, it suggests that we should not modify this packet 144 | if (dscp >= 0) 145 | { 146 | if (PIAS_DEBUG_MODE == 1) 147 | printk(KERN_INFO "Modify DSCP field to %d (packet size %u)\n", dscp, skb->len); 148 | pias_enable_ecn_dscp(skb, (u8)dscp); 149 | } 150 | } 151 | return NF_ACCEPT; 152 | } 153 | 154 | /* Hook function for incoming packets */ 155 | static unsigned int pias_hook_func_in(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 156 | { 157 | struct iphdr *iph = NULL; //IP header structure 158 | struct tcphdr *tcph = NULL; //TCP header structure 159 | struct PIAS_Flow f; //Flow structure 160 | struct PIAS_Flow* ptr = NULL; //Pointer to structure Information 161 | u32 ack; //TCP ACK number 162 | u16 payload_len = 0; //TCP payload length 163 | unsigned long flags; //variable for save current states of irq 164 | 165 | if (!in) 166 | return NF_ACCEPT; 167 | 168 | if (param_dev && strncmp(in->name, param_dev, IFNAMSIZ) != 0) 169 | return NF_ACCEPT; 170 | 171 | //Get IP header 172 | iph = ip_hdr(skb); 173 | //The packet is not an IP packet (e.g. ARP or others), return NF_ACCEPT 174 | if (unlikely(!iph)) 175 | return NF_ACCEPT; 176 | 177 | if (iph->protocol == IPPROTO_TCP) 178 | { 179 | tcph = (struct tcphdr *)((__u32 *)iph + iph->ihl); 180 | 181 | if (param_port != 0 && ntohs(tcph->source) != param_port && ntohs(tcph->dest) != param_port) 182 | return NF_ACCEPT; 183 | 184 | if (tcph->ack) 185 | { 186 | //TCP payload length=Total IP length - IP header length-TCP header length 187 | payload_len = ntohs(iph->tot_len) - (iph->ihl << 2) - (tcph->doff << 2); 188 | 189 | PIAS_Init_Flow(&f); 190 | f.local_ip = iph->daddr; 191 | f.remote_ip = iph->saddr; 192 | f.local_port = (u16)ntohs(tcph->dest); 193 | f.remote_port = (u16)ntohs(tcph->source); 194 | //Update existing Flow entry's information 195 | ptr = PIAS_Search_Table(&ft, &f); 196 | if (ptr) 197 | { 198 | spin_lock_irqsave(&(ptr->lock), flags); 199 | ack = (u32)ntohl(tcph->ack_seq); 200 | if (pias_is_seq_larger(ack, ptr->info.last_ack)) 201 | ptr->info.last_ack = ack; 202 | spin_unlock_irqrestore(&(ptr->lock), flags); 203 | } 204 | } 205 | } 206 | return NF_ACCEPT; 207 | } 208 | 209 | /* Install Netfilter hooks. Return true if it succeeds */ 210 | bool PIAS_Netfilter_Init(void) 211 | { 212 | //Register outgoing Netfilter hook 213 | pias_nf_hook_out.hook = pias_hook_func_out; 214 | pias_nf_hook_out.hooknum = NF_INET_POST_ROUTING; 215 | pias_nf_hook_out.pf = PF_INET; 216 | pias_nf_hook_out.priority = NF_IP_PRI_FIRST; 217 | if (nf_register_hook(&pias_nf_hook_out)) 218 | { 219 | printk(KERN_INFO "Cannot register Netfilter hook at NF_INET_POST_ROUTING\n"); 220 | return false; 221 | } 222 | 223 | //Register incoming Netfilter hook 224 | pias_nf_hook_in.hook = pias_hook_func_in; 225 | pias_nf_hook_in.hooknum = NF_INET_PRE_ROUTING; 226 | pias_nf_hook_in.pf = PF_INET; 227 | pias_nf_hook_in.priority = NF_IP_PRI_FIRST; 228 | if (nf_register_hook(&pias_nf_hook_in)) 229 | { 230 | printk(KERN_INFO "Cannot register Netfilter hook at NF_INET_PRE_ROUTING\n"); 231 | return false; 232 | } 233 | 234 | return true; 235 | } 236 | 237 | /* Uninstall Netfilter hooks */ 238 | void PIAS_Netfilter_Exit(void) 239 | { 240 | nf_unregister_hook(&pias_nf_hook_out); 241 | nf_unregister_hook(&pias_nf_hook_in); 242 | } 243 | -------------------------------------------------------------------------------- /pias4/netfilter.h: -------------------------------------------------------------------------------- 1 | #ifndef NETFILTER_H 2 | #define NETFILTER_H 3 | 4 | /* Install Netfilter hooks */ 5 | bool PIAS_Netfilter_Init(void); 6 | /* Uninstall Netfilter hooks */ 7 | void PIAS_Netfilter_Exit(void); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /pias4/network.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "network.h" 6 | #include "params.h" 7 | 8 | /* Based on size, return DSCP value of corresponding priority. */ 9 | int pias_priority(u32 size) 10 | { 11 | int i = 0; 12 | 13 | for (i = 0; i < PIAS_PRIO_NUM - 1; i++) 14 | { 15 | if (size <= PIAS_PRIO_THRESH[i]) 16 | return PIAS_PRIO_DSCP[i]; 17 | } 18 | 19 | //By default, return DSCP of the lowest priority 20 | return PIAS_PRIO_DSCP[PIAS_PRIO_NUM - 1]; 21 | } 22 | 23 | /* mark DSCP and enable ECN */ 24 | inline void pias_enable_ecn_dscp(struct sk_buff *skb, u8 dscp) 25 | { 26 | if (likely(skb && skb_make_writable(skb, sizeof(struct iphdr)))) 27 | ipv4_change_dsfield(ip_hdr(skb), 0x00, (dscp << 2)|INET_ECN_ECT_0); 28 | } 29 | 30 | /* Determine whether seq1 is larger than seq2 */ 31 | inline bool pias_is_seq_larger(u32 seq1, u32 seq2) 32 | { 33 | if (likely(seq1 > seq2 && seq1 - seq2 <= 4294900000)) 34 | return true; 35 | else if (seq1 < seq2 && seq2 - seq1 > 4294900000) 36 | return true; 37 | else 38 | return false; 39 | } 40 | 41 | /* Calculate gap between seq1 and seq2 */ 42 | u32 pias_seq_gap(u32 seq1, u32 seq2) 43 | { 44 | //seq1 is larger seq2 45 | if (pias_is_seq_larger(seq1, seq2)) 46 | { 47 | if (likely(seq1 > seq2)) 48 | return seq1-seq2; 49 | else 50 | return 4294967295- (seq2 - seq1); 51 | } 52 | else 53 | { 54 | if (likely(seq2 > seq1)) 55 | return seq2 - seq1; 56 | else 57 | return 4294967295 - (seq1 - seq2); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /pias4/network.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETWORK_H__ 2 | #define __NETWORK_H__ 3 | 4 | #include 5 | #include 6 | 7 | /* Decide priority (DSCP) */ 8 | inline int pias_priority(u32 size); 9 | /* Enable ECN and mark DSCP */ 10 | inline void pias_enable_ecn_dscp(struct sk_buff *skb, u8 dscp); 11 | /* Determine whether seq1 is larger than seq2 */ 12 | inline bool pias_is_seq_larger(u32 seq1, u32 seq2); 13 | /* Calculate gap between seq1 and seq2 */ 14 | inline u32 pias_seq_gap(u32 seq1, u32 seq2); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /pias4/params.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "params.h" 5 | 6 | //Idle time in us 7 | int PIAS_IDLE_TIME = 500; 8 | //RTOmin in us 9 | int PIAS_RTO_MIN = 9 * 1000; 10 | //Threshold of consecutive TCP timeouts to reset priority 11 | int PIAS_TIMEOUT_THRESH = 3; 12 | //Sequence gap in bytes to identify consecutive TCP timeouts 13 | int PIAS_TIMEOUT_SEQ_GAP = 3 * 1448; 14 | //Shall we enable aging to prevent long-term starvation 15 | int PIAS_ENABLE_AGING = 1; 16 | //Shall we enable debug mode 17 | int PIAS_DEBUG_MODE = 0; 18 | 19 | //int PIAS_PRIO_DSCP[PIAS_PRIO_NUM] = {7, 6, 5, 4, 3, 2, 1, 0}; 20 | //int PIAS_PRIO_THRESH[PIAS_PRIO_NUM - 1] = {909*1460, 1329*1460, 1648*1460, 1960*1460, 2143*1460, 2337*1460, 2484*1460}; 21 | //int PIAS_PRIO_THRESH[PIAS_PRIO_NUM - 1] = {745*1460, 1083*1460, 1391*1460, 13689*1460, 14396*1460, 21149*1460, 27245*1460}; 22 | int PIAS_PRIO_DSCP[PIAS_PRIO_NUM] = {0, -1}; 23 | int PIAS_PRIO_THRESH[PIAS_PRIO_NUM - 1] = {100*1024}; 24 | 25 | struct PIAS_Param PIAS_Params[2 * PIAS_PRIO_NUM + 6] = 26 | { 27 | {"idle_time", &PIAS_IDLE_TIME}, 28 | {"rto_min", &PIAS_RTO_MIN}, 29 | {"timeout_thresh", &PIAS_TIMEOUT_THRESH}, 30 | {"timeout_seq_gap", &PIAS_TIMEOUT_SEQ_GAP}, 31 | {"enable_aging", &PIAS_ENABLE_AGING}, 32 | {"debug_mode", &PIAS_DEBUG_MODE} 33 | }; 34 | 35 | struct ctl_table PIAS_Params_Table[2 * PIAS_PRIO_NUM + 6]; 36 | 37 | struct ctl_path PIAS_Params_Path[] = 38 | { 39 | { .procname = "pias" }, 40 | { }, 41 | }; 42 | 43 | struct ctl_table_header *PIAS_Sysctl = NULL; 44 | 45 | /* Intialize parameters and register sysctl */ 46 | bool PIAS_Params_Init(void) 47 | { 48 | int i = 0; 49 | struct ctl_table *entry = NULL; 50 | 51 | memset(PIAS_Params_Table, 0, sizeof(PIAS_Params_Table)); 52 | 53 | /* Initialize PIAS_Params */ 54 | for (i = 0; i < PIAS_PRIO_NUM; i++) 55 | { 56 | snprintf(PIAS_Params[i + 6].name, 63, "prio_dscp_%d", i); 57 | PIAS_Params[i + 6].ptr = &PIAS_PRIO_DSCP[i]; 58 | 59 | /* we have PIAS_PRIO_NUM - 1 demotion thresholds */ 60 | if (i < PIAS_PRIO_NUM - 1) 61 | { 62 | snprintf(PIAS_Params[i + PIAS_PRIO_NUM + 6].name, 63, "prio_thresh_%d", i); 63 | PIAS_Params[i + PIAS_PRIO_NUM + 6].ptr = &PIAS_PRIO_THRESH[i]; 64 | } 65 | } 66 | /* End of the parameters */ 67 | PIAS_Params[2 * PIAS_PRIO_NUM + 6 - 1].ptr = NULL; 68 | 69 | for (i = 0; i < 2 * PIAS_PRIO_NUM + 6; i++) 70 | { 71 | if (PIAS_Params[i].ptr) 72 | { 73 | entry = &PIAS_Params_Table[i]; 74 | /* Initialize entry (ctl_table) */ 75 | entry->procname = PIAS_Params[i].name; 76 | entry->data = PIAS_Params[i].ptr; 77 | entry->mode = 0644; 78 | entry->proc_handler = &proc_dointvec; 79 | entry->maxlen = sizeof(int); 80 | } 81 | } 82 | 83 | PIAS_Sysctl = register_sysctl_paths(PIAS_Params_Path, PIAS_Params_Table); 84 | 85 | if (PIAS_Sysctl) 86 | return true; 87 | else 88 | return false; 89 | } 90 | 91 | /* Unregister sysctl */ 92 | void PIAS_Params_Exit(void) 93 | { 94 | if (PIAS_Sysctl) 95 | unregister_sysctl_table(PIAS_Sysctl); 96 | } 97 | -------------------------------------------------------------------------------- /pias4/params.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARAMS_H__ 2 | #define __PARAMS_H__ 3 | 4 | #include 5 | 6 | #define PIAS_PRIO_NUM 2 //Number of PIAS priorities 7 | 8 | //Idle time in us 9 | extern int PIAS_IDLE_TIME; 10 | //RTOmin in us 11 | extern int PIAS_RTO_MIN; 12 | //Threshold of consecutive TCP timeouts to reset priority 13 | extern int PIAS_TIMEOUT_THRESH; 14 | //Sequence gap in bytes to identify consecutive TCP timeouts 15 | extern int PIAS_TIMEOUT_SEQ_GAP; 16 | //Shall we enable aging to prevent long-term starvation 17 | extern int PIAS_ENABLE_AGING; 18 | //Shall we enable debug mode 19 | extern int PIAS_DEBUG_MODE; 20 | 21 | //DSCP value for different priorities 22 | extern int PIAS_PRIO_DSCP[PIAS_PRIO_NUM]; 23 | //Demotion thresholds in bytes for different priorities 24 | extern int PIAS_PRIO_THRESH[PIAS_PRIO_NUM - 1]; 25 | 26 | struct PIAS_Param 27 | { 28 | char name[64]; 29 | int *ptr; 30 | }; 31 | 32 | extern struct PIAS_Param PIAS_Params[2 * PIAS_PRIO_NUM + 6]; 33 | 34 | /* Intialize parameters and register sysctl. Return true if it succeeds. */ 35 | bool PIAS_Params_Init(void); 36 | /* Unregister sysctl */ 37 | void PIAS_Params_Exit(void); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /sch_pias/Makefile: -------------------------------------------------------------------------------- 1 | obj-m+=sch_pias.o 2 | sch_pias-y :=params.o main.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 6 | 7 | clean: 8 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 9 | 10 | 11 | -------------------------------------------------------------------------------- /sch_pias/params.c: -------------------------------------------------------------------------------- 1 | #include "params.h" 2 | #include 3 | #include 4 | 5 | /* As recommended by DCTCP paper, we use 30KB for 1G network*/ 6 | int PIAS_QDISC_ECN_THRESH_BYTES=30*1024; 7 | 8 | /* Maximum sum of queue lenghs. 1MB should be enough */ 9 | int PIAS_QDISC_MAX_LEN_BYTES=1024*1024; 10 | 11 | /* Bucket size in nanosecond */ 12 | int PIAS_QDISC_BUCKET_NS=2000000; 13 | 14 | /* DSCP values for different priorities */ 15 | int PIAS_QDISC_PRIO_DSCP_1=7; 16 | int PIAS_QDISC_PRIO_DSCP_2=6; 17 | int PIAS_QDISC_PRIO_DSCP_3=5; 18 | int PIAS_QDISC_PRIO_DSCP_4=4; 19 | int PIAS_QDISC_PRIO_DSCP_5=3; 20 | int PIAS_QDISC_PRIO_DSCP_6=2; 21 | int PIAS_QDISC_PRIO_DSCP_7=1; 22 | int PIAS_QDISC_PRIO_DSCP_8=0; 23 | 24 | 25 | /* All parameters that can be configured through sysctl */ 26 | struct PIAS_QDISC_Param PIAS_QDISC_Params[16]={ 27 | {"PIAS_QDISC_ECN_THRESH_BYTES\0", &PIAS_QDISC_ECN_THRESH_BYTES}, 28 | {"PIAS_QDISC_MAX_LEN_BYTES\0", &PIAS_QDISC_MAX_LEN_BYTES}, 29 | {"PIAS_QDISC_BUCKET_NS\0",&PIAS_QDISC_BUCKET_NS}, 30 | {"PIAS_QDISC_PRIO_DSCP_1\0", &PIAS_QDISC_PRIO_DSCP_1}, 31 | {"PIAS_QDISC_PRIO_DSCP_2\0", &PIAS_QDISC_PRIO_DSCP_2}, 32 | {"PIAS_QDISC_PRIO_DSCP_3\0", &PIAS_QDISC_PRIO_DSCP_3}, 33 | {"PIAS_QDISC_PRIO_DSCP_4\0", &PIAS_QDISC_PRIO_DSCP_4}, 34 | {"PIAS_QDISC_PRIO_DSCP_5\0", &PIAS_QDISC_PRIO_DSCP_5}, 35 | {"PIAS_QDISC_PRIO_DSCP_6\0", &PIAS_QDISC_PRIO_DSCP_6}, 36 | {"PIAS_QDISC_PRIO_DSCP_7\0", &PIAS_QDISC_PRIO_DSCP_7}, 37 | {"PIAS_QDISC_PRIO_DSCP_8\0", &PIAS_QDISC_PRIO_DSCP_8}, 38 | {"\0", NULL}, 39 | }; 40 | 41 | struct ctl_table PIAS_QDISC_Params_Table[16]; 42 | struct ctl_path PIAS_QDISC_Params_Path[] = { 43 | { .procname = "sch_pias" }, 44 | { }, 45 | }; 46 | struct ctl_table_header *PIAS_QDISC_Sysctl=NULL; 47 | 48 | int pias_qdisc_params_init(void) 49 | { 50 | int i=0; 51 | memset(PIAS_QDISC_Params_Table, 0, sizeof(PIAS_QDISC_Params_Table)); 52 | 53 | for(i = 0; i < 16; i++) 54 | { 55 | struct ctl_table *entry = &PIAS_QDISC_Params_Table[i]; 56 | //End 57 | if(PIAS_QDISC_Params[i].ptr == NULL) 58 | break; 59 | //Initialize entry (ctl_table) 60 | entry->procname=PIAS_QDISC_Params[i].name; 61 | entry->data=PIAS_QDISC_Params[i].ptr; 62 | entry->mode=0644; 63 | entry->proc_handler=&proc_dointvec; 64 | entry->maxlen=sizeof(int); 65 | } 66 | 67 | PIAS_QDISC_Sysctl=register_sysctl_paths(PIAS_QDISC_Params_Path, PIAS_QDISC_Params_Table); 68 | if(PIAS_QDISC_Sysctl==NULL) 69 | return -1; 70 | else 71 | return 0; 72 | } 73 | 74 | void pias_qdisc_params_exit(void) 75 | { 76 | if(PIAS_QDISC_Sysctl!=NULL) 77 | unregister_sysctl_table(PIAS_QDISC_Sysctl); 78 | } 79 | -------------------------------------------------------------------------------- /sch_pias/params.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARAMS_H__ 2 | #define __PARAMS_H__ 3 | 4 | #include 5 | 6 | /* Our module has at most 8 priority queues */ 7 | #define PIAS_QDISC_MAX_PRIO 8 8 | 9 | /* MTU(1500)+Ethernet header(14) */ 10 | #define PIAS_QDISC_MTU_BYTES 1514 11 | 12 | /* Ethernet packets with less than the minimum 64 bytes (header (14B) + user data + FCS (4B)) are padded to 64 bytes. */ 13 | #define PIAS_QDISC_MIN_PKT_BYTES 64 14 | 15 | /* Per-port ECN marking threshold in bytes */ 16 | extern int PIAS_QDISC_ECN_THRESH_BYTES; 17 | /* Maximum sum of queue lenghs. It's similar to shared buffer per port on switches */ 18 | extern int PIAS_QDISC_MAX_LEN_BYTES; 19 | /* Bucket size in nanosecond */ 20 | extern int PIAS_QDISC_BUCKET_NS; 21 | 22 | /* DSCP value for different priority queues (PIAS_QDISC_PRIO_DSCP_1 is for the highest priority) */ 23 | extern int PIAS_QDISC_PRIO_DSCP_1; 24 | extern int PIAS_QDISC_PRIO_DSCP_2; 25 | extern int PIAS_QDISC_PRIO_DSCP_3; 26 | extern int PIAS_QDISC_PRIO_DSCP_4; 27 | extern int PIAS_QDISC_PRIO_DSCP_5; 28 | extern int PIAS_QDISC_PRIO_DSCP_6; 29 | extern int PIAS_QDISC_PRIO_DSCP_7; 30 | extern int PIAS_QDISC_PRIO_DSCP_8; 31 | 32 | struct PIAS_QDISC_Param { 33 | char name[64]; 34 | int *ptr; 35 | }; 36 | 37 | extern struct PIAS_QDISC_Param PIAS_QDISC_Params[16]; 38 | 39 | /* Intialize parameters and register sysctl */ 40 | int pias_qdisc_params_init(void); 41 | /* Unregister sysctl */ 42 | void pias_qdisc_params_exit(void); 43 | 44 | #endif --------------------------------------------------------------------------------