├── .gitignore ├── controller ├── testevents.txt ├── stdbool.h ├── runandgather.sh ├── lookup3.h ├── logprocess.sh ├── getlogs.sh ├── util.h ├── loguser.h ├── flow.h ├── usecase.h ├── bitmap.h ├── messages.h ├── serverdata.h ├── Makefile ├── flow.c ├── bitmap.c ├── loguser.c ├── util.c ├── eventhandler.h ├── hashmap.h └── tcpserver.c ├── experiments ├── file_usecase │ ├── example.txt │ └── README.md ├── netwide_usecase │ ├── dstmac.txt │ ├── logprocess.sh │ ├── drawneworkwide_doc.m │ ├── README.md │ └── getnetworkwidestats.m ├── matching │ ├── delay2.sh │ ├── delay1_result.sh │ ├── delay2_result.sh │ ├── delay1.sh │ └── README.md ├── flowchunk │ ├── gather.sh │ ├── flowchunk.sh │ └── README.md ├── mirror │ ├── README.sh │ └── mirrorscript.sh ├── burst │ ├── burst_1.sh │ ├── burst.sh │ └── README.md ├── dos │ ├── README.md │ ├── dos1pktscript.sh │ ├── dosscript.sh │ └── dosgarph.m ├── optimizations │ ├── optimizations_1.sh │ ├── optimizations.sh │ ├── runopt.sh │ ├── README.md │ └── lastzerots.patch ├── dospredict │ ├── dospredictscript.sh │ ├── README.md │ └── dosgraph.m ├── burstloss_usecase │ ├── README.md │ └── config.txt ├── feasibility │ ├── README.md │ ├── feasscript.sh │ └── feasscript2.sh ├── base40 │ ├── run40g.sh │ ├── README.md │ └── 40g.sh ├── proportional │ └── README.md ├── base10 │ └── README.md ├── congestion_usecase │ ├── udpthroughputdiagram.m │ └── README.md └── README.md ├── sender ├── dstmac.txt ├── runsender.sh ├── stdbool.h └── Makefile ├── receiver ├── stdbool.h ├── lookup3.h ├── run.sh ├── timehist.h ├── Makefile ├── heap.h ├── matcher.h ├── loguser.h ├── ddostable2.h ├── flow.h ├── bitmap.h ├── messages.h ├── flowentry.c ├── flowentry.h ├── ddostable2.c ├── client.h ├── heap.c ├── flow.c ├── util.h ├── timehist.c ├── bitmap.c ├── loguser.c ├── util.c ├── flatreport.h ├── hashmap.h ├── summary.h ├── matcher.c └── triggertable2.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.log 3 | *.tgz 4 | **/build 5 | **/mine 6 | -------------------------------------------------------------------------------- /controller/testevents.txt: -------------------------------------------------------------------------------- 1 | 10.0.0.1/0,10.0.0.0/8,0/0,0/0,0/0;sum,volume,1000;32,32,8,16,16;10 2 | -------------------------------------------------------------------------------- /experiments/file_usecase/example.txt: -------------------------------------------------------------------------------- 1 | 10.0.0.1/0,10.0.0.0/8,0/0,0/0,0/0;sum,volume,1000;32,32,8,16,16;10 2 | -------------------------------------------------------------------------------- /sender/dstmac.txt: -------------------------------------------------------------------------------- 1 | 68, 05, ca, 1e, a5, e4, 2 | 68, 05, ca, 1e, a5, e5, 3 | 68, 05, ca, 1e, a5, d0, 4 | 68, 05, ca, 1e, a5, d1, 5 | -------------------------------------------------------------------------------- /sender/runsender.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd $1 3 | echo $2 4 | sleep 5; 5 | sudo -E ./build/basicfwd -c 0xaaaa -n4 --file-prefix=sender_ -m 128 -- $2 6 | -------------------------------------------------------------------------------- /experiments/netwide_usecase/dstmac.txt: -------------------------------------------------------------------------------- 1 | 68, 05, ca, 1e, a5, e5, 2 | 68, 05, ca, 1e, a5, e4, 3 | 68, 05, CA, 2C, 35, D0, 4 | 68, 05, ca, 2c, 35, d1, 5 | -------------------------------------------------------------------------------- /experiments/matching/delay2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=1; 3 | t=4096; 4 | for P in 1 4 16 64; 5 | do 6 | sudo -E build/basicfwd -t $t -p $p -P $P -T 1 -l delay2_${1}_${P}; 7 | done 8 | -------------------------------------------------------------------------------- /receiver/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDBOOL_H 2 | #define __STDBOOL_H 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | #define __bool_true_false_are_defined 1 8 | 9 | #endif /* stdbool.h */ -------------------------------------------------------------------------------- /sender/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDBOOL_H 2 | #define __STDBOOL_H 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | #define __bool_true_false_are_defined 1 8 | 9 | #endif /* stdbool.h */ -------------------------------------------------------------------------------- /controller/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDBOOL_H 2 | #define __STDBOOL_H 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | #define __bool_true_false_are_defined 1 8 | 9 | #endif /* stdbool.h */ -------------------------------------------------------------------------------- /experiments/flowchunk/gather.sh: -------------------------------------------------------------------------------- 1 | # the columns will be prefix, # triggers, cycles used for sweeping 2 | 3 | for f in `ls chunk_*_*_0.txt` 4 | do 5 | echo `echo $f|cut -f 2,3 -d_|sed s/_/,/g`,`cat $f|grep mstepticks|cut -f11 -d\ ` 6 | done 7 | -------------------------------------------------------------------------------- /experiments/matching/delay1_result.sh: -------------------------------------------------------------------------------- 1 | # the columns will be # patterns, # triggers, delay per match in ns 2 | 3 | for f in `ls delay1_*_*_0.txt` 4 | do 5 | echo `echo $f|cut -f 2,3 -d_|sed s/_/,/g`,`cat $f | grep 'match delay' | cut -f3 -d\ ` 6 | done 7 | -------------------------------------------------------------------------------- /controller/runandgather.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | user=masoud 3 | RECEIVER_FOLDER=/home/$user/dpdk_r/dpdk/examples/receiver 4 | ssh -n ${user}@$1 "sh -c 'cd \"$RECEIVER_FOLDER\"; \"$2\" \"$3\" > \"$4\" 2>&1'"& 5 | wait 6 | scp ${user}@$1:$RECEIVER_FOLDER/$4 $4 7 | -------------------------------------------------------------------------------- /experiments/matching/delay2_result.sh: -------------------------------------------------------------------------------- 1 | # the columns will be # patterns, # triggers, delay per match in cycles 2 | 3 | for f in `ls delay2_*_*_0.txt` 4 | do 5 | echo `echo $f|cut -f 2,3 -d_|sed s/_/,/g`,`cat $f | grep 'Avg match' | cut -f4 -d\ ` 6 | done 7 | -------------------------------------------------------------------------------- /experiments/mirror/README.sh: -------------------------------------------------------------------------------- 1 | This is the experiment to test the mirroring capability of the NIC. 2 | - set MIRROR and NOWORKER options to 1 in basicfwd.c file in the receiver 3 | - you can use the mirrorscript.sh script in this folder to test the experiment over different packet rate 4 | -------------------------------------------------------------------------------- /experiments/netwide_usecase/logprocess.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #send 1 3 | #query 2 4 | #add 3 5 | #del 4 6 | grep "^[0-9]*:" $1 | sed -e 's/^\([0-9]*\):/\1,/g' -e 's/ send/1,/g' -e 's/ poll/2,/g' -e 's/ add/3,0,/g' -e 's/ del/4,0,/g' -e 's/ time \([0-9]*\)/\1,/g' -e 's/ step \([0-9]*\)/\1,/g' -e 's/ event \([0-9]*\)/\1,/g' -e 's/ seq \([0-9]*\)/\1/g' -e '/[a-zA-Z]/d' 7 | -------------------------------------------------------------------------------- /experiments/burst/burst_1.sh: -------------------------------------------------------------------------------- 1 | # the columns will be burst, run number, total cycles, free cycles, cycles used for sweeping 2 | 3 | for f in `ls burst_*_*_0.txt` 4 | do 5 | echo `echo $f|cut -f 2,3 -d_|sed s/_/,/g`,`cat $f | grep cycles | cut -f3 -d\ | cut -f2 -d:|sed s/,//g`,`cat $f|grep zerots|cut -f6 -d\ |cut -f2 -d:`,`cat $f|grep mstepticks|cut -f11 -d\ ` 6 | done 7 | -------------------------------------------------------------------------------- /experiments/flowchunk/flowchunk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=1; 3 | w=4; 4 | i=10; 5 | a=2000; 6 | t=4096; 7 | r=14880000; 8 | d=0; 9 | f=300; 10 | for t in 1 16 256 4096; 11 | do 12 | let t2=20*r; 13 | ./run.sh "-r $r -t $t2 -p 1 -D $d -l 1 -S 60 -a $a -f $f" "-t $t -p $p -P 1 -n $t2 -d 0.000005 -T 1 -l chunk_${1}_${t} -w $w -i $i"; 14 | sleep 5; 15 | done 16 | -------------------------------------------------------------------------------- /experiments/dos/README.md: -------------------------------------------------------------------------------- 1 | This is the guide to replicate the result of DoS resiliency for Trumpet. 2 | - To get the result for Syn DoS attack copy the dos1pktscript.sh file into the receiver folder and run it 3 | - For the result of DoS attacks that can send more than a threshold run dosscript.sh. 4 | - Now you can get the graph in the paper by running the dosgraph.m matlab script in this folder 5 | -------------------------------------------------------------------------------- /experiments/optimizations/optimizations_1.sh: -------------------------------------------------------------------------------- 1 | # the columns will be prefix, rate, run number, total cycles, free cycles, cycles used for sweeping 2 | 3 | for f in `ls opt_*_*_*_0.txt` 4 | do 5 | echo `echo $f|cut -f 2,3,4 -d_|sed s/_/,/g`,`cat $f | grep cycles | cut -f3 -d\ | cut -f2 -d:|sed s/,//g`,`cat $f|grep zerots|cut -f6 -d\ |cut -f2 -d:`,`cat $f|grep mstepticks|cut -f11 -d\ ` 6 | done 7 | -------------------------------------------------------------------------------- /experiments/matching/delay1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=1; 3 | w=4; 4 | i=10; 5 | a=1000; 6 | t=4096; 7 | r=12000000; 8 | d=0; 9 | f=300; 10 | for P in 1 4 16 64; 11 | do for t in 256 1024 4096 16384; 12 | do 13 | let t2=20*r; 14 | ./run.sh "-r $r -t $t2 -p 1 -D $d -l 1 -S 60 -a $a -f $f" "-t $t -p $p -P $P -n $t2 -d 0.000005 -T 1 -l delay1_${P}_${t} -w $w -i $i"; 15 | sleep 5; 16 | done; 17 | done 18 | -------------------------------------------------------------------------------- /controller/lookup3.h: -------------------------------------------------------------------------------- 1 | #ifndef LOOKUP3_H 2 | #define LOOKUP3_H 1 3 | 4 | #include 5 | #include 6 | 7 | #define hashsize(n) ((uint32_t)1<<(n)) 8 | #define hashmask(n) (hashsize(n)-1) 9 | #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) 10 | 11 | uint32_t hashlittle( const void *key, size_t length, uint32_t initval); 12 | uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval); 13 | 14 | #endif /* lookup3.h */ -------------------------------------------------------------------------------- /receiver/lookup3.h: -------------------------------------------------------------------------------- 1 | #ifndef LOOKUP3_H 2 | #define LOOKUP3_H 1 3 | 4 | #include 5 | #include 6 | 7 | #define hashsize(n) ((uint32_t)1<<(n)) 8 | #define hashmask(n) (hashsize(n)-1) 9 | #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) 10 | 11 | uint32_t hashlittle( const void *key, size_t length, uint32_t initval); 12 | uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval); 13 | 14 | #endif /* lookup3.h */ -------------------------------------------------------------------------------- /experiments/dospredict/dospredictscript.sh: -------------------------------------------------------------------------------- 1 | for p in 8 16 32 64; 2 | do 3 | for d in 0.88652 0.95908 0.98598 1; 4 | do 5 | for l in 10 20 30 40 50 60 70 80 90; 6 | do 7 | t2=$(echo ";10^10/((64*${d}+1500*(1-${d})+20)*8)*20" |bc); 8 | echo $t2; 9 | let t=l*64; 10 | ./run.sh "-t $t2 -p 1 -D $d -l $l" "-t 4096 -p 8 -P $p -n $t2 -d 0.000005 -T $t -l dosp_${p}_${d}_${l}"; 11 | sleep 2; 12 | done; 13 | done; 14 | done 15 | -------------------------------------------------------------------------------- /experiments/burst/burst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=8; 3 | w=4; 4 | i=10; 5 | a=1000; 6 | t=4096; 7 | r=12000000; 8 | d=0; 9 | f=300; 10 | b=1; 11 | for j in `seq 0 9`; 12 | do for b in 1 2 4 8 16 32 64; 13 | do 14 | let t2=20*r; 15 | let t=4096/8*p; 16 | ./run.sh "-r $r -t $t2 -p 1 -D $d -l 1 -S 60 -a $a -f $f -b $b" "-t $t -p $p -P 32 -n $t2 -d 0.000005 -T 1 -l burst_${b}_${j} -w $w -i $i" _${b}_${j}; 17 | sleep 5; 18 | done; 19 | done 20 | -------------------------------------------------------------------------------- /experiments/burstloss_usecase/README.md: -------------------------------------------------------------------------------- 1 | This is the guide to re-run the loss and burst example from the trumpet paper. In this example, we have a sender and receiver connected from a bottleneck line that also has shallow buffer. Making the shallow buffer requires a switch that lets us limit its buffer size. You can refer the config.txt file to see how I did it for ME3600 switch. 2 | 3 | The guide is not complete as this usecase implementation is not complete in this version of trumpet. 4 | -------------------------------------------------------------------------------- /experiments/optimizations/optimizations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=8; 3 | w=4; 4 | i=10; 5 | a=1000; 6 | t=4096; 7 | r=14880000; 8 | d=0; 9 | f=300; 10 | for j in `seq 0 9`; 11 | do for r in 14880000 14000000 12000000 10000000 8000000; 12 | do 13 | let t2=20*r; 14 | let t=4096/8*p; 15 | ./runopt.sh "-r $r -t $t2 -p 1 -D $d -l 1 -S 60 -a $a -f $f" "-t $t -p $p -P 32 -n $t2 -d 0.000005 -T 1 -l opt_${1}_${r}_${j} -w $w -i $i" _${1}_${r}_${j}; 16 | sleep 5; 17 | done; 18 | done 19 | -------------------------------------------------------------------------------- /receiver/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sender=192.168.0.1 3 | senderfolder=/home/ubuntu/trumpet/sender 4 | senderuser=ubuntu 5 | 6 | echo "$1 --> $2" 7 | 8 | sudo -E build/basicfwd -c 0xaaaa -n 4 -- $2 & 9 | ssh -n -f ${senderuser}@${sender} "sh -c 'nohup \"$senderfolder\"/runsender.sh \"$senderfolder\" \"$1\" > \"$senderfolder\"/temp.txt 2>&1 &'" 10 | sleep 40 11 | x=`ps -aef | awk '{print $2,$8;}'| grep build/basicfwd | head -n 1| awk '{print $1;}'` 12 | echo "kill $x" 13 | sudo kill -s 2 $x 14 | -------------------------------------------------------------------------------- /experiments/burst/README.md: -------------------------------------------------------------------------------- 1 | This is the explanation on how to regenerate the experiment for comparing different packet burst rates. 2 | - you need to uncomment the part of the code that counts the CPU Quiescent time. It essentially is uncommenting what is related to lastzerots in lcore_main function of basicfwd.c file in the receiver folder. You may also look at the ../optimizations/lastzerots.patch file. 3 | - copy burst.sh script into receiver folder and run it. 4 | - use burst_1.sh to summarize the result 5 | -------------------------------------------------------------------------------- /experiments/mirror/mirrorscript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=8; 3 | w=4; 4 | i=10; 5 | a=1000; 6 | t=4096; 7 | r=14880000; 8 | d=0; 9 | f=300; 10 | for j in `seq 0 9`; 11 | do for r in 8000000 7750000 7500000 7250000 7000000 6000000; 12 | # do for r in 7440000 7400000 7300000; 13 | do 14 | let t2=20*r; 15 | let t=4096/8*p; 16 | ./run.sh "-r $r -t $t2 -p 1 -D $d -l 1 -S 60 -a $a -f $f" "-t $t -p $p -P 32 -n $t2 -d 0.000005 -T 1 -l mirror_${r}_${j} -w $w -i $i" _${r}_${j}; 17 | sleep 5; 18 | done; 19 | done 20 | -------------------------------------------------------------------------------- /experiments/burstloss_usecase/config.txt: -------------------------------------------------------------------------------- 1 | #login to the terminal and type the following commands 2 | 3 | config terminal 4 | policy-map trumpet_p 5 | class class-default 6 | bandwidth 10000 7 | queue-limit 32768 bytes 8 | exit 9 | exit 10 | policy-map trumpet_p2 11 | class class-default 12 | service-policy trumpet_p 13 | exit 14 | exit 15 | policy-map trumpet_p3 16 | class class-default 17 | service-policy trumpet_p2 18 | exit 19 | exit 20 | interface GigabitEthernet0/1 21 | service-policy output trumpet_p3 22 | exit 23 | exit 24 | 25 | -------------------------------------------------------------------------------- /experiments/feasibility/README.md: -------------------------------------------------------------------------------- 1 | This is the guide for the experiment that finds the feasibilty region of Trumpet in the parameter space. 2 | - make sure you set the IP of sender in the run.sh file in the receiver folder 3 | - run feasscript.sh file in the receiver folder to get the range over different sweep interval, different number of active flows, and different number of triggers per flow. 4 | - run feasscript2.sh to check over different flow arrival rate instead of differetn number of active flows 5 | - you can find the script to summarize the result as comment in each of those folders 6 | -------------------------------------------------------------------------------- /experiments/optimizations/runopt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sender=192.168.0.1 3 | senderfolder=/home/ubuntu/dpdk_r/dpdk/examples/sender 4 | echo "$1 --> $2" 5 | 6 | sudo -E build/basicfwd -c 0xaaaa -n 4 -- $2 & 7 | ssh -n -f ubuntu@${sender} "sh -c 'nohup \"$senderfolder\"/runsender.sh \"$1\" > \"$senderfolder\"/temp.txt 2>&1 &'" 8 | 9 | #reduced the sleep time so that it finishes before receiving all packets (to count spare cycles correclty) 10 | sleep 35 11 | x=`ps -aef | awk '{print $2,$8;}'| grep build/basicfwd | head -n 1| awk '{print $1;}'` 12 | echo "kill $x" 13 | sudo kill -s 2 $x 14 | -------------------------------------------------------------------------------- /controller/logprocess.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #ask 1 3 | #satisfaction 2 4 | #return 3 5 | #add_return 4 6 | #all received 5 7 | #addevent 6 8 | #del event 7 9 | #del return 8 10 | grep "^[0-9]*:" $1 | sed -e '/hello/d' -e 's/^\([0-9]*\):/\1,/g' -e 's/ serverdata \([0-9]*\):/\1,/g' -e "s/ poll /1, /g" -e "s/ sat/2,/g" -e "s/ poll_return/3,/g" -e "s/ add_return/4,/g" -e 's/ all_data/0,5,0,/g' -e 's/ addevent/0,6,0,/g' -e 's/ delevent/0,7,0,/g' -e 's/ del_return/8,/g' -e 's/ time \([0-9]*\)\(.\)/\1,\2/g' -e 's/ event \([0-9]*\)/\1,/g' -e 's/ ctime \([0-9]*\)/\1,/g' -e 's/ \([0-9]*\):\([0-9]*\)//g' 11 | -------------------------------------------------------------------------------- /experiments/base40/run40g.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sender1=192.168.0.1 3 | sender2=192.168.0.3 4 | sender1folder=/home/ubuntu/dpdk_r/dpdk/examples/sender 5 | sender2folder=/home/ubuntu/dpdk_r/dpdk/examples/sender 6 | 7 | echo "$1 --> $2" 8 | 9 | sudo -E build/basicfwd -c 0xaaaa -n 4 -- $2 & 10 | sleep 15; 11 | ssh -n -f ubuntu@${sender1} "sh -c 'nohup \"$sender1folder\"/runsender.sh \"$1\" > \"$sender1folder\"/temp.txt 2>&1 &'" 12 | ssh -n -f ubuntu@${sender2} "sh -c 'nohup /\"$sender2folder\"/runsender.sh \"$1\" > \"$sender2folder\"/temp.txt 2>&1 &'" 13 | sleep 55 14 | x=`ps -aef | awk '{print $2,$8;}'| grep build/basicfwd | head -n 1| awk '{print $1;}'` 15 | echo "kill $x" 16 | sudo kill -s 2 $x 17 | -------------------------------------------------------------------------------- /experiments/flowchunk/README.md: -------------------------------------------------------------------------------- 1 | This is the guide for how to evaluate the benefit of chunking flows when the TPM sweeps over the triggers. 2 | We need to run the base10 experiment two times one with flow-chunks and one without it while changing the number of flows per trigger. 3 | - Run flowchunk.sh script with parameter 0. It runs base10 experiemtn with different number of triggers. Triggers must cover the IP range so their definition will chang, so that the experiment with fewer triggers will have more flows per trigger. 4 | - Then set TRIGGERFLOW_BATCH to 1 in receiver/util.h, compile and run the script again with parameter 1 5 | - Now use the gather.sh script to get the sweep time over the different runs 6 | -------------------------------------------------------------------------------- /controller/getlogs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | logname=$1; 3 | ip1=192.168.0.2 4 | ip2=192.168.0.3 5 | for t in 0 1; 6 | do 7 | for e in 4 16 64 256; 8 | do 9 | ./runandgather.sh $ip1 10 | ./logprocess.sh ${logname}_${e}_${t}.txt ${logname}_${e}_${t}.log; 11 | done; 12 | done 13 | 14 | # use 2 and 3 for the logs on the second server 15 | for t in 0 1; 16 | do 17 | let t2=t+2; 18 | for e in 4 16 64 256; 19 | do 20 | ./runandgather.sh $ip2 21 | ./logprocess.sh ${logname}_${e}_${t}.txt ${logname}_${e}_${t2}.log; 22 | done; 23 | done 24 | 25 | # process the controller logs 26 | for e in 4 16 64 256; 27 | do 28 | ./logprocess.sh ${logname}_${e}.txt > ${logname}_${e}_c.log; 29 | done 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Trumpet 2 | Public code repository for Trumpet. 3 | You may start with the guide in experiments/README.md 4 | 5 | Note that this system is just developed to test the academic idea of resource allocation for software defined measurement and its implementation can be far from a real-world commercial implementation in terms of coding standards, reliability, and performance. Therefore, please use it at your risk. 6 | 7 | Please refer to the following paper if you use the code for any publication. 8 | Masoud Moshref, Minlan Yu, Ramesh Govindan, Amin Vahdat, "Trumpet: Timely and Precise Triggers in Data Centers", SIGCOMM, 2016 9 | 10 | https://nsl.cs.usc.edu/Papers/?action=download&upname=Moshref_16a.pdf 11 | -------------------------------------------------------------------------------- /experiments/dos/dos1pktscript.sh: -------------------------------------------------------------------------------- 1 | for d in 0 0.72254 0.85421 0.90946 0.93985 0.95908 0.97234 0.98204 0.98945 0.99528 1; 2 | do 3 | for l in `seq 1 10`; 4 | do 5 | t2=$(echo ";10^10/((64*${d}+1500*(1-${d})+20)*8)*20" |bc); 6 | echo $t2; 7 | let t=l*64; 8 | ./run.sh "-t $t2 -p 1 -D $d -l 1" "-t 4096 -p 8 -P 32 -n $t2 -d 0.000005 -T $t -l dos1pkt_${d}_${l}"; 9 | sleep 2; 10 | done; 11 | done 12 | 13 | # summarize the result. Columns are dos rate, run number, packet loss, not finished sweeps 14 | for f in `find . -name dos1pkt_\*_\*_0.txt`; do echo `echo $f | cut -f 2,3 -d_ |sed 's/_/,/g'`,`grep 'RX Packets' $f | cut -f 2 -d: | cut -f 2 -d\ | sed 's_/_,_g'`,`grep 'notfinished' $f |cut -f 3 -d\ `; done >ddos1pktmeasure.txt 15 | -------------------------------------------------------------------------------- /experiments/dos/dosscript.sh: -------------------------------------------------------------------------------- 1 | for j in `seq 0 4`; 2 | do 3 | for d in 0.72254 0.85421 0.90946 0.93985 0.95908 0.97234 0.98204 0.98945 0.99528 1; 4 | do 5 | for l in 1 10 20 30 40 50 60; 6 | do 7 | t2=$(echo ";10^10/((64*${d}+1500*(1-${d})+20)*8)*20" |bc); 8 | echo $t2; 9 | let t=l*64; 10 | ./run.sh "-t $t2 -p 1 -D $d -l $l" "-t 4096 -p 8 -P 32 -n $t2 -d 0.000005 -T $t -l dos_${d}_${l}_${j}"; 11 | sleep 2; 12 | done; 13 | done; 14 | done 15 | 16 | #columns will be dos packet ratio, # dos packets per flow, run number 17 | for f in `find . -name dos_\*_\*_\*_0.txt`; do echo `echo $f | cut -f 2,3,4 -d_ |sed 's/_/,/g'`,`grep 'RX Packets' $f | cut -f 2 -d: | cut -f 2 -d\ | sed 's_/_,_g'`,`grep 'notfinished' $f |cut -f 3 -d\ `; done >ddosmeasure.txt 18 | -------------------------------------------------------------------------------- /experiments/base40/README.md: -------------------------------------------------------------------------------- 1 | In my setting, I had two sender machines, each having two 10G ports and the receiver had 4 10G ports. 2 | This is how you can replicate the result in a similar setting: 3 | - Make sure that you have assigned the ports to the DPDK driver 4 | - Make sure that at each sender you edit the dstmac.txt so that it can set the MAC address of the generated packets correctly. 5 | - Make sure that your 10G switch doesn't broadcast the packets. I did that by manually adding the host MAC addresses in its forwarding table. 6 | - copy run40g.sh and 40g.sh files from this folder to the receiver folder 7 | - set the correct IP of the senders at the run40g.sh file 8 | - run 40g.sh 9 | 10 | The 40g.sh will run the experiment multiple times with different packet sizes and at the end shows a summary. 11 | -------------------------------------------------------------------------------- /receiver/timehist.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMEHIST_H 2 | #define TIMEHIST_H 1 3 | #include 4 | #include "heap.h" 5 | #include "stdbool.h" 6 | 7 | struct timehist_bucket{ 8 | uint32_t ts; 9 | uint32_t size; 10 | uint32_t pair; 11 | uint16_t heap_index; 12 | uint16_t next; 13 | uint16_t prev; 14 | }; 15 | 16 | typedef void (*timehist_bucket_apply_func)(struct timehist_bucket * b1, void * aux); 17 | typedef uint32_t (*timehist_pair_func)(struct timehist_bucket * b1, struct timehist_bucket * b2); 18 | 19 | struct timehist{ 20 | struct heap * h; 21 | struct timehist_bucket * buckets; 22 | uint64_t ts; 23 | timehist_pair_func pair_func; 24 | uint16_t size; 25 | uint16_t filled; 26 | uint16_t emptybucket_index; 27 | uint16_t lastbucket_index; 28 | }; 29 | 30 | #endif /* timehist.h */ 31 | -------------------------------------------------------------------------------- /receiver/Makefile: -------------------------------------------------------------------------------- 1 | 2 | ifeq ($(RTE_SDK),) 3 | $(error "Please define RTE_SDK environment variable") 4 | endif 5 | 6 | # Default target, can be overridden by command line or environment 7 | RTE_TARGET ?= x86_64-native-linuxapp-gcc 8 | 9 | include $(RTE_SDK)/mk/rte.vars.mk 10 | 11 | # binary name 12 | APP = basicfwd 13 | 14 | # all source are stored in SRCS-y 15 | #SRCS-y := main.c 16 | SRCS-y := basicfwd.c loguser.c util.c flatreport.c flowentry.c flow.c bitmap.c ddostable2.c hashmap.c lookup3.c triggertable2.c summary.c matcher.c client.c 17 | 18 | CFLAGS += $(WERROR_FLAGS) 19 | 20 | # workaround for a gcc bug with noreturn attribute 21 | # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 22 | ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) 23 | CFLAGS_main.o += -Wno-return-type 24 | endif 25 | 26 | EXTRA_CFLAGS += -O3 -g $(DEF) 27 | #-Wfatal-errors 28 | 29 | include $(RTE_SDK)/mk/rte.extapp.mk 30 | -------------------------------------------------------------------------------- /experiments/proportional/README.md: -------------------------------------------------------------------------------- 1 | This is a guide to replicate the result for proportional resource usage in Trumpet. For this, we need to change the definition of triggers so that they only match part of the set of flows and rerun the experiment. 2 | - The generator is set to generate the flows over 64k different IPs. The recevier also tries to cover the range when it defines the set of triggers. By changing the IP range at the receiver, we can change the definition of triggers to only coveer part of the flow space. Change the iprangesie variable in the flatreport_addtriggers method of flatreport.c file in the receiver. For example setting that to 1<<15, means only 50% of flows will be covered by triggers. 3 | - Compile the code and run the base10 experiment using run.sh script at the receiver 4 | - You can use a script similar to the one in experiments/burst/burst_1.sh to gather CPU Quiescent time and sweep time. 5 | -------------------------------------------------------------------------------- /experiments/base10/README.md: -------------------------------------------------------------------------------- 1 | This is the guide on how to repeat the simplest experiment: sending and receivinng 10G traffic without any DoS attack.Note that you need two machines sender and receiver. 2 | - At the receiver make sure that the options at util.h and basicfwd.c are set correctly (default ones) 3 | - At the receiver, edit run.sh and set sender IP, senderfolder and sender user correctly (Note the IP is different from the receiver IP). 4 | - At the receiver run: ./run.sh "-t 200000000 -S 60" "-t 4096 -p 8 -P 32 -n 200000000 -d 0.000005 -T 1 -w 4 -i 10 -l base10" 5 | 6 | This will set the sender to receive 200M small packets and the receiver to expect 200M packets, forward to 4 workers, report every 10ms and fill its trigger repository with 4k triggers with 32 patterns in a way that every packet may match 8 triggers. 7 | You can see the help of the parameters for the receiver, the sender or the controller usin the -h command. For example, at receiver you can run, sudo ./build/basicfwd -c aaaa -n 4 -- -h 8 | 9 | -------------------------------------------------------------------------------- /experiments/base40/40g.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=8; 3 | w=4; 4 | i=10; 5 | a=1000; 6 | t=4096; 7 | r=14880000; 8 | d=0; 9 | f=300; 10 | s=1500 11 | for j in `seq 0 9`; 12 | do for s in 350 400 450 500 550 600 650 700 750 800 850 900 950 1000; 13 | do 14 | t2=$(echo ";10^10/(${s}+24)/8*20" |bc); 15 | let t240g=4*t2; 16 | ./run40g.sh "-t $t2 -p 3 -D $d -l 1 -S $s -a $a -f $f" "-t $t -p $p -P 32 -n $t240g -d 0.000005 -T 1 -l 40gw_${s}_${j} -w $w -i $i" _${s}_${j}; 17 | sleep 5; 18 | x=`cat 40gw_${s}_${j}_0.txt | grep "notfinished" | head -n 1 | cut -f3 -d\ `; 19 | if [ $x -eq 0 ]; then 20 | break; 21 | fi; 22 | done; 23 | done 24 | 25 | for j in `seq 0 9`; 26 | do for s in 350 400 450 500 550 600 650 700 750 800 850 900 950 1000; 27 | do 28 | echo `echo ${s},${j}`,`cat 40gw_${s}_${j}_0.txt | grep "RX Packet Loss" | head -n 1 | cut -f2 -d:| sed -e 's/ //g'`,`cat 40gw_${s}_${j}_0.txt | grep "notfinished" | head -n 1 | cut -f3,7 -d\ |sed -e 's/ /,/g'`; 29 | done; 30 | done 31 | -------------------------------------------------------------------------------- /receiver/heap.h: -------------------------------------------------------------------------------- 1 | //got first version from https://gist.github.com/martinkunev/1365481 2 | #ifndef HEAP_H 3 | #define HEAP_H 1 4 | #include 5 | #include "stdbool.h" 6 | 7 | typedef void* heap_type; 8 | typedef bool (*heap_cmp_func)(void * a, void * b); 9 | typedef void (*heap_index_func)(void * a, uint16_t index); 10 | 11 | struct heap{ 12 | unsigned int size; // Size of the allocated memory (in number of items) 13 | unsigned int count; // Count of the elements in the heap 14 | heap_cmp_func cmp_func; 15 | heap_index_func index_func; 16 | heap_type data; // Array with the elements 17 | }; 18 | 19 | struct heap * heap_init(uint16_t size, heap_cmp_func cmp_func, heap_index_func index_func); 20 | void heap_finish(struct heap *); 21 | void heap_push(struct heap * h, heap_type value); 22 | heap_type heap_pop(struct heap * h); 23 | heap_type heap_push_pop (struct heap * h, heap_type value); 24 | uint16_t heap_size(struct heap * h); 25 | 26 | void heapify(heap_type data[], unsigned int count); 27 | 28 | #endif /* heap.h */ 29 | -------------------------------------------------------------------------------- /experiments/netwide_usecase/drawneworkwide_doc.m: -------------------------------------------------------------------------------- 1 | clear; 2 | kk=1; 3 | name='netwide'; 4 | events=[4 16 64 256]; 5 | for eventsnum=events; 6 | %for e=[64]; 7 | c=csvread(sprintf('%s_%d_c.log',name,eventsnum)); 8 | for i=1:4, 9 | s{i}=csvread(sprintf('%s_%d_%d.log',name,eventsnum, i-1)); 10 | end; 11 | getnetworkwidestats; 12 | multirunstats{kk}= stats; 13 | multirunstatsm{kk}= statsm; 14 | kk=kk+1; 15 | end 16 | 17 | cols = {'1st Sat-Poll', 'Last ask-1st ask', '1st Sat-Last sat','1st Sat-Poll result'}; 18 | 19 | for i = 1:length(events), 20 | meanvalues(i,:) = mean(multirunstats{i}(:,[3,4])); 21 | stdvalues(i,:) = std(multirunstats{i}(:,[3,4])); 22 | end 23 | figure; 24 | barwitherr(stdvalues(:,2),meanvalues(:,2)); 25 | set(gca,'XTickLabel', arrayfun(@num2str, events, 'unif', 0)); 26 | ylabel('Time (ms)'); 27 | xlabel('# events') 28 | set(findall(gcf,'type','text'),'fontSize',14) 29 | set(findobj(gcf, 'type','axes'),'fontsize',14) 30 | xlim([0.5, 4+0.5]) 31 | set(gcf,'OuterPosition',[500,500,375,360]) 32 | -------------------------------------------------------------------------------- /experiments/dos/dosgarph.m: -------------------------------------------------------------------------------- 1 | x=csvread('dosmeasurenomatch.txt'); 2 | couldrun = x(:,3)>0; 3 | noloss = x(:,4)<100; 4 | nonotfinish = x(:,5)<2; 5 | d = unique(x(:,1)); 6 | clear m; for i = 1:length(d), di = d(i); m(i,:)=[di,min(x(and(x(:,1)==di,and(and(couldrun, noloss),nonotfinish)),2))]; end; 7 | x2=csvread('dosmeasurenomatch1pkt.txt'); 8 | couldrun2 = x2(:,3)>0; 9 | noloss2 = x2(:,4)<100; 10 | nonotfinish2 = x2(:,5)<2; 11 | clear m2; for i = 1:length(d), di = d(i); m2(i,:)=[di,min(x2(and(x2(:,1)==di,and(and(couldrun2, noloss2),nonotfinish2)),2))]; end; 12 | m=[0,1;m]; 13 | m2=[0,1;m2]; 14 | 15 | 16 | figure; 17 | hold all; 18 | m(m(:,1)==1,:)=[]; 19 | m2(m2(:,1)==1,:)=[]; 20 | D2(D2(:,1)==1,:)=[]; 21 | plot(m2(:,2)*64/1000,100*D2(:,1),'-s', 'LineWidth',2) 22 | plot(m(:,2)*64/1000,100*D2(:,1),'-*', 'LineWidth',2) 23 | xlabel('Threshold (KB)'); 24 | ylabel('DoS traffic BW %'); 25 | set(findobj(gcf, 'type','axes'),'fontsize',13) 26 | set(findobj(gcf, 'type','axes'),'fontsize',14) 27 | set(findall(gcf,'type','text'),'fontSize',14') 28 | set(gca,'XTick', [0:4]) 29 | set(gca,'YTick', [0 30 60 90]) 30 | ylim([0 92]); 31 | legend({'1 packet','=threshold'}); 32 | set(gcf,'OuterPosition',[300,300,375,360]) 33 | -------------------------------------------------------------------------------- /controller/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 1 3 | 4 | #include 5 | #include "stdbool.h" 6 | #include "loguser.h" 7 | 8 | #include 9 | 10 | #define MALLOC(s) malloc(s) 11 | #define FREE(p) free(p) 12 | #define MALLOC2(s,n) malloc(s) 13 | 14 | #define BIGMALLOC(s) malloc(s) 15 | #define BIGFREE(p) free(p) 16 | #define BIGMALLOC2(s,n) malloc(s) //posix_memalign is bad 17 | 18 | #define LOG(format, ...) \ 19 | loguser_add(util_lu, format, ##__VA_ARGS__); \ 20 | 21 | 22 | #define HASH_PREFETCH0(p) 23 | 24 | #define rdtscl() (rte_rdtsc()) 25 | 26 | void * myalign(int size, int align); 27 | 28 | bool is_empty2(void *buf2, uint32_t size); 29 | void set_CPU(int cpu); 30 | uint32_t gbp(uint32_t m); 31 | uint16_t entry_size_64(uint16_t m); 32 | //unsigned long long rdtscl(void); 33 | unsigned int countTrailing0M(uint64_t v); 34 | int log2_32 (uint32_t value); 35 | int log2_64 (uint64_t value); 36 | 37 | void shuffle (void * array, size_t n, size_t size); 38 | 39 | extern struct loguser * util_lu; 40 | 41 | #endif /* util.h */ 42 | -------------------------------------------------------------------------------- /receiver/matcher.h: -------------------------------------------------------------------------------- 1 | #ifndef MATCHER_H 2 | #define MATCHER_H 1 3 | #include "flow.h" 4 | #include "hashmap.h" 5 | 6 | /* 7 | * A hash table for filters of triggers as a linkedlist entry 8 | */ 9 | struct table { 10 | struct flow mask; 11 | hashmap_elem e; 12 | struct table * next; 13 | struct hashmap * map; 14 | }; 15 | 16 | 17 | struct matcher { 18 | struct table * tables; 19 | struct hashmap * masktable; 20 | }; 21 | 22 | typedef bool (*matcher_dataequal_func)(void * data1, void * data2); 23 | 24 | //runs func on any match 25 | void matcher_match(struct matcher * m, struct flow * f, void ** dataarr, uint16_t * size); 26 | 27 | //it may add duplicates 28 | bool matcher_add (struct matcher * m, struct flow * f, struct flow * mask, void * data); 29 | 30 | //deletes only one if it finds equal 31 | bool matcher_remove (struct matcher * m, struct flow * f, struct flow * mask, void * data, matcher_dataequal_func func, void ** removed); 32 | 33 | 34 | void matcher_matchmask(struct matcher * m, struct flow * f, struct flow * mask, void ** temptable, uint16_t * num); 35 | 36 | struct matcher * matcher_init(void); 37 | void matcher_finish(struct matcher * m); 38 | 39 | #endif /* matcher.h */ 40 | 41 | -------------------------------------------------------------------------------- /experiments/optimizations/README.md: -------------------------------------------------------------------------------- 1 | This is the explanation on how to regenerate the experiment for comparing different optimizations. 2 | - copy the scripts in this folder to the receiver folder 3 | - you need to uncomment the part of the code that counts the CPU Quiescent time. It essentially is uncommenting what is related to lastzerots in lcore_main function of basicfwd.c file in the receiver folder. You may also look at the lastzerots.patch file in this folder. 4 | - the optimizations.sh script will run the experiment multiple times with different packet rates to find out if it is feasible with a rate or not. 5 | - Workflow: we disable each optimization in util.h file, compile the code and run the optimizations.sh . Each setting can have a prifix, so that later running optimizations_1.sh can gather the result easily. 6 | - The mapping between the optimizations and the option in util.h 7 | - Packet prefetcing: PKT_PREFETCH_ENABLE 8 | - Hashmap prefetching: HASH_PREFETCH_ENABLE 9 | - Prefetching in the sweep phase: SWEEP_PREFETCH_ENABLE 10 | - using hugepages: DPDK_BIG_MALLOC 11 | - putting triggers back to back: TRIGGERTABLE_INLINE_TRIGGER 12 | 13 | Example: 14 | - set PKT_PREFETCH_ENABLE to 0 15 | - compile 16 | - ./optimizations.sh 1 17 | - ./optimizations_1.sh 18 | -------------------------------------------------------------------------------- /experiments/optimizations/lastzerots.patch: -------------------------------------------------------------------------------- 1 | --- test.c 2016-06-30 15:26:47.484320456 -0700 2 | +++ basicfwd.c 2016-06-30 15:26:53.240333739 -0700 3 | @@ -1227,16 +1227,16 @@ 4 | #if !NOMEASURE 5 | if (nb_rx == 0){ 6 | //to measure zerots for optimizations 7 | -/* if (lastzerots > 0 && experiment_isstarted(mt)){ 8 | + if (lastzerots > 0 && experiment_isstarted(mt)){ 9 | uint64_t temp = rte_rdtsc(); //this is required to not include last epoch that packets may have arrived 10 | mt->stat_zerots += temp - lastzerots; 11 | lastzerots = temp; 12 | }else{ 13 | lastzerots = rte_rdtsc(); 14 | - }*/ 15 | + } 16 | break; 17 | } 18 | -// lastzerots = 0; 19 | + lastzerots = 0; 20 | 21 | readpackets(bufs, nb_rx, mt); 22 | #endif 23 | @@ -1264,9 +1264,9 @@ 24 | 25 | //if (todrain < RX_RING_SIZE - 200){ // 2*(5us+1us)*15 26 | if (todrain < 40){ // 2*(5us+1us)*15 27 | -// if (lastzerots == 0 && experiment_isstarted(mt)){ 28 | -// lastzerots = rte_rdtsc(); 29 | -// } 30 | + if (lastzerots == 0 && experiment_isstarted(mt)){ 31 | + lastzerots = rte_rdtsc(); 32 | + } 33 | break; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /receiver/loguser.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGUSER_H 2 | #define LOGUSER_H 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define LOGUSER_GETSIZE(n) (n*64) 13 | #define LOGLINEBUFFER_LEN 252 14 | 15 | struct logfile{ 16 | char filename [100]; 17 | int tid; 18 | FILE *fd; 19 | void * next; 20 | }; 21 | 22 | /* 23 | * The logger that logs lines into a file as a separate thread. 24 | * The thread has dynamic sleep time to save CPU 25 | */ 26 | struct loguser{ 27 | struct rte_ring * ring; 28 | struct rte_mempool * mem; 29 | pthread_t pth __attribute__((aligned(64))); 30 | bool finish __attribute__((aligned(64))); 31 | uint16_t delay; 32 | uint16_t core; 33 | struct logfile * lfh; 34 | bool fullerror; 35 | }; 36 | 37 | struct loguser * loguser_init(uint32_t size, const char * filename, uint16_t core); 38 | void loguser_finish(struct loguser * lu); 39 | 40 | /* 41 | * Add a line to the log. The format is similar to printf 42 | */ 43 | void loguser_add(struct loguser * lu, const char * format, ...); 44 | 45 | /* 46 | * We can have multiple log files. Once a thread registers all loguser_add calls will write to the new file created for that thread 47 | */ 48 | bool loguser_registerthread(struct loguser * lu, const char * filename); 49 | 50 | #endif /* loguser.h */ 51 | -------------------------------------------------------------------------------- /controller/loguser.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGUSER_H 2 | #define LOGUSER_H 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define LOGUSER_GETSIZE(n) (n*64) 13 | #define LOGLINEBUFFER_LEN 252 14 | 15 | struct logfile{ 16 | char filename [100]; 17 | int tid; 18 | FILE *fd; 19 | void * next; 20 | }; 21 | 22 | /* 23 | * The logger that logs lines into a file as a separate thread. 24 | * The thread has dynamic sleep time to save CPU 25 | */ 26 | struct loguser{ 27 | struct rte_ring * ring; 28 | struct rte_mempool * mem; 29 | pthread_t pth __attribute__((aligned(64))); 30 | bool finish __attribute__((aligned(64))); 31 | uint16_t delay; 32 | uint16_t core; 33 | struct logfile * lfh; 34 | bool fullerror; 35 | }; 36 | 37 | struct loguser * loguser_init(uint32_t size, const char * filename, uint16_t core); 38 | void loguser_finish(struct loguser * lu); 39 | 40 | /* 41 | * Add a line to the log. The format is similar to printf 42 | */ 43 | void loguser_add(struct loguser * lu, const char * format, ...); 44 | 45 | /* 46 | * We can have multiple log files. Once a thread registers all loguser_add calls will write to the new file created for that thread 47 | */ 48 | bool loguser_registerthread(struct loguser * lu, const char * filename); 49 | 50 | #endif /* loguser.h */ 51 | -------------------------------------------------------------------------------- /receiver/ddostable2.h: -------------------------------------------------------------------------------- 1 | #ifndef DDOSTABLE2_H 2 | #define DDOSTABLE2_H 1 3 | 4 | #include 5 | #include "stdbool.h" 6 | 7 | struct flatreport; 8 | struct flatreport_pkt; 9 | 10 | /* 11 | * A counterarray table (hashtable of only counter values that collisions just accumulte). 12 | * The counterss will reset every stepperiod and if 128k packets (~10m packets in 10G) are processed. The limit on the number of packets is to throttle checking time. 13 | * Keeps track of size of flows as multiple of 64 14 | */ 15 | struct ddostable2{ 16 | struct flatreport * fr; 17 | uint32_t threshold_1; 18 | uint32_t pktnum; //number of processed packets 19 | uint32_t countarraymask; //bitwise mask due to the size of countarray 20 | uint16_t step; // the current epoch 21 | uint64_t laststeptime; 22 | uint64_t stepperiod; //epoch length 23 | uint16_t bufferstart; //put this at the end 24 | ////////////// DON'T PUT IT! 25 | }; 26 | 27 | /* 28 | * 0 < Threshold < 127*64 29 | * counterarraysize must be power of 2 30 | * Set fr after initialization 31 | */ 32 | struct ddostable2 * ddostable2_init(uint16_t threshold, uint32_t countarraysize); 33 | void ddostable2_finish(struct ddostable2 * dt); 34 | 35 | /* 36 | * Returns true if the flow (with pkt->hash) have sent more than the threshold 37 | */ 38 | bool ddostable2_add(struct ddostable2 * dt, struct flatreport_pkt * pkt); 39 | void ddostable2_incpktnum(struct ddostable2 * dt, int inc); 40 | 41 | #endif /* ddostable2.h */ 42 | 43 | -------------------------------------------------------------------------------- /receiver/flow.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOW_H 2 | #define FLOW_H 1 3 | 4 | #include 5 | #include "stdbool.h" 6 | 7 | #define FLOW_NOFG 0x00000000 8 | 9 | struct flow { 10 | uint32_t srcip; 11 | uint32_t dstip; 12 | uint32_t ports; 13 | uint32_t protocol; //32 bits instead of 8 to avoid not setting the three addtional bytes that are wasted anyway. Now, no need to reset the remaining bytes but can be ignored in 64bits operations 14 | }__attribute__((aligned(8))); 15 | 16 | void flow_fill(struct flow * dst, struct flow * src); 17 | bool flow_equal(struct flow * data1, struct flow * data2); 18 | bool flow_equal3(void* data1, void * data2); 19 | bool flow_equal2(struct flow * data1, uint32_t srcip, uint32_t dstip, uint32_t ports, uint32_t protocol); 20 | uint32_t flow_hash (struct flow * f); 21 | void flow_print(struct flow * f); 22 | void flow_inlineprint(struct flow * f); 23 | void flow_inlineprint2(struct flow * f, char * buf); 24 | void flow_mask(struct flow * dst, struct flow * src, struct flow * maskflow); 25 | 26 | void flow_parseflowgranularity(uint32_t flowgranularity, uint8_t* srcip_len, uint8_t* dstip_len, uint8_t* srcport_len, uint8_t* dstport_len, uint8_t* protocol_len); 27 | uint32_t flow_makeflowgranularity(uint8_t srcip_len, uint8_t dstip_len, uint8_t srcport_len, uint8_t dstport_len, uint8_t protocol_len); 28 | void flow_makemask(struct flow * mask, uint8_t srcip_len, uint8_t dstip_len, uint8_t srcport_len, uint8_t dstport_len, uint8_t protocol_len); 29 | 30 | #endif /* flow.h */ 31 | -------------------------------------------------------------------------------- /controller/flow.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOW_H 2 | #define FLOW_H 1 3 | 4 | #include 5 | #include "stdbool.h" 6 | 7 | #define FLOW_NOFG 0x00000000 8 | 9 | struct flow { 10 | uint32_t srcip; 11 | uint32_t dstip; 12 | uint32_t ports; 13 | uint32_t protocol; //32 bits instead of 8 to avoid not setting the three addtional bytes that are wasted anyway. Now, no need to reset the remaining bytes but can be ignored in 64bits operations 14 | }__attribute__((aligned(8))); 15 | 16 | void flow_fill(struct flow * dst, struct flow * src); 17 | bool flow_equal(struct flow * data1, struct flow * data2); 18 | bool flow_equal3(void* data1, void * data2); 19 | bool flow_equal2(struct flow * data1, uint32_t srcip, uint32_t dstip, uint32_t ports, uint32_t protocol); 20 | uint32_t flow_hash (struct flow * f); 21 | void flow_print(struct flow * f); 22 | void flow_inlineprint(struct flow * f); 23 | void flow_inlineprint2(struct flow * f, char * buf); 24 | void flow_mask(struct flow * dst, struct flow * src, struct flow * maskflow); 25 | 26 | void flow_parseflowgranularity(uint32_t flowgranularity, uint8_t* srcip_len, uint8_t* dstip_len, uint8_t* srcport_len, uint8_t* dstport_len, uint8_t* protocol_len); 27 | uint32_t flow_makeflowgranularity(uint8_t srcip_len, uint8_t dstip_len, uint8_t srcport_len, uint8_t dstport_len, uint8_t protocol_len); 28 | void flow_makemask(struct flow * mask, uint8_t srcip_len, uint8_t dstip_len, uint8_t srcport_len, uint8_t dstport_len, uint8_t protocol_len); 29 | 30 | #endif /* flow.h */ 31 | -------------------------------------------------------------------------------- /controller/usecase.h: -------------------------------------------------------------------------------- 1 | #ifndef USECASE_H 2 | #define USECASE_H 1 3 | 4 | #include "eventhandler.h" 5 | 6 | typedef void (*usecase_atserverjoin_func)(struct usecase * u, struct serverdata * server); 7 | typedef void (*usecase_ateventsatisfaction_func)(struct usecase * u, struct event * e, struct eventhistory * es); 8 | typedef void (*usecase_finish_func)(struct usecase * u); 9 | typedef void (*usecase_start_func)(struct usecase * u); 10 | 11 | struct usecase{ 12 | struct eventhandler * eh; 13 | usecase_atserverjoin_func atserverjoin; 14 | usecase_ateventsatisfaction_func ateventsatisfaction; 15 | usecase_finish_func finish; 16 | usecase_start_func start; 17 | void * u2; 18 | }; 19 | 20 | struct usecase_netwide{ 21 | struct usecase u; 22 | uint16_t targetservers; 23 | uint16_t eventsnum; 24 | uint16_t serversnum; 25 | }; 26 | 27 | struct usecase_congestion{ 28 | struct usecase u; 29 | bool proactive_udpeventon; //a hack to check if the proactive event is added or not 30 | bool reactive_udpeventon; //a hack to see if the udp heavy hitter detection event is on or not. 31 | uint16_t serversnum; 32 | }; 33 | 34 | struct usecase_file{ 35 | struct usecase u; 36 | uint16_t targetservers; 37 | uint16_t serversnum; 38 | uint32_t events_num; 39 | struct event ** events; 40 | char f [128]; 41 | }; 42 | 43 | 44 | struct usecase * usecase_netwide_init(uint16_t targetservers, uint16_t eventsnum); 45 | struct usecase * usecase_congestion_init(void); 46 | struct usecase * usecase_file_init(const char * f, uint16_t targetservers); 47 | 48 | #endif /* usecase.h */ 49 | -------------------------------------------------------------------------------- /experiments/file_usecase/README.md: -------------------------------------------------------------------------------- 1 | This is a guide for how to use the general interface at the controller to add events from a file. The usecase is impelemented in usecase.c file 2 | 3 | The file format is as follows: 4 | - There are five fields separated by semicolon (;) per line. Each filed may have multiple items that are separated by comma. Here are the fields in order: 5 | - Filter: A prefix based filter on 5-tuples (srcip, dstip, protocol, srcport, dstport). Tuple fields are separeted by comma, and each field must have a prefix length. For example, 10.0.0.1/32,10.1.1.0/24,0/0,0/0,0/0 means that the event will match source IP 10.0.0.1, and all destination IPs in prefix 10.1.1.0/24 on any source port, destination port and protocol. 6 | - Predicate: The items are aggregate function, per-packet variable, and threshold. For now, Trumpet controller only supports summation aggregation function, and volume and packet as packet variables. 7 | - Flow granularity: It has 5 items, each specifying the flow granularity for the corresponding field in the filter. 8 | - Time interval: in millisecond and a multiple of 10. 9 | 10 | To run the controller with this usecase, 11 | - edit the controller/testevents.txt file with your events 12 | - At the controller run: sudo -E ./build/tcpserver -c 0x5555 -n 4 --file-prefix=controller_ -m 128 -- -s 1 -l file -u 3 13 | - At receiver run: : sudo -E build/basicfwd -c 0xaaaa -n 4 -- -t 0 -p 0 -P 32 -n 200000000 -d 0.000005 -c 192.168.0.1 -l file, where 192.168.0.1 is the controller IP 14 | - Send the traffic to the receiver (may be using the provided sender) 15 | -------------------------------------------------------------------------------- /controller/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef BITMAP_H 2 | #define BITMAP_H 1 3 | #include 4 | #include "stdbool.h" 5 | 6 | #define BITMAP_ENTRY_SIZE 64 7 | #define BITMAP_ENTRY_SIZE_LOG 6 8 | #define BITMAP_ENTRY_SIZE_MOD 0x003F 9 | #define BITMAP_MAX_ENTRY(x) ((x >> BITMAP_ENTRY_SIZE_LOG) + (((x & BITMAP_ENTRY_SIZE_MOD) > 0) ? 1 : 0)) 10 | #define BITMAP_SIZE(x) (sizeof(struct bitmap)+(BITMAP_MAX_ENTRY(x)-1)*BITMAP_ENTRY_SIZE/8) 11 | 12 | typedef void (*bitmap_apply_func)(uint32_t id, void * aux); 13 | 14 | struct bitmap{ 15 | uint32_t maxid; 16 | uint32_t filled; 17 | bool hasbuffer; 18 | uint64_t data;//must be last 19 | }; 20 | 21 | struct bitmap_iterator{ 22 | struct bitmap * bm; 23 | uint64_t mask; 24 | uint32_t id; 25 | }; 26 | 27 | bool bitmap_set(struct bitmap * bm, uint32_t id); 28 | bool bitmap_unset(struct bitmap * bm, uint32_t id); 29 | bool bitmap_get(struct bitmap * bm, uint32_t id); 30 | void bitmap_print(struct bitmap * bm); 31 | void bitmap_apply(struct bitmap * bm, bitmap_apply_func func, void * aux); 32 | int bitmap_getfirstzero(struct bitmap * bm, uint32_t size, uint32_t* id); 33 | uint32_t bitmap_getfilled(struct bitmap * bm); 34 | 35 | struct bitmap_iterator * bitmap_iterator_init(struct bitmap * bm, struct bitmap_iterator * bi); 36 | bool bitmap_iterator_next(struct bitmap_iterator * bi, uint32_t* id); 37 | 38 | struct bitmap * bitmap_init(uint32_t maxid, uint8_t * buffer); 39 | void bitmap_finish(struct bitmap * bm); 40 | void bitmap_clear(struct bitmap * bm); 41 | void bitmap_setall(struct bitmap * bm); 42 | 43 | #endif /* bitmap.h */ 44 | -------------------------------------------------------------------------------- /receiver/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef BITMAP_H 2 | #define BITMAP_H 1 3 | #include 4 | #include "stdbool.h" 5 | 6 | #define BITMAP_ENTRY_SIZE 64 7 | #define BITMAP_ENTRY_SIZE_LOG 6 8 | #define BITMAP_ENTRY_SIZE_MOD 0x003F 9 | #define BITMAP_MAX_ENTRY(x) ((x >> BITMAP_ENTRY_SIZE_LOG) + (((x & BITMAP_ENTRY_SIZE_MOD) > 0) ? 1 : 0)) 10 | #define BITMAP_SIZE(x) (sizeof(struct bitmap)+(BITMAP_MAX_ENTRY(x)-1)*BITMAP_ENTRY_SIZE/8) 11 | 12 | typedef void (*bitmap_apply_func)(uint32_t id, void * aux); 13 | 14 | struct bitmap{ 15 | uint32_t maxid; 16 | uint32_t filled; 17 | bool hasbuffer; 18 | uint64_t data;//must be last 19 | }; 20 | 21 | struct bitmap_iterator{ 22 | struct bitmap * bm; 23 | uint64_t mask; 24 | uint32_t id; 25 | }; 26 | 27 | bool bitmap_set(struct bitmap * bm, uint32_t id); 28 | bool bitmap_unset(struct bitmap * bm, uint32_t id); 29 | bool bitmap_get(struct bitmap * bm, uint32_t id); 30 | void bitmap_print(struct bitmap * bm); 31 | void bitmap_apply(struct bitmap * bm, bitmap_apply_func func, void * aux); 32 | int bitmap_getfirstzero(struct bitmap * bm, uint32_t size, uint32_t* id); 33 | uint32_t bitmap_getfilled(struct bitmap * bm); 34 | 35 | struct bitmap_iterator * bitmap_iterator_init(struct bitmap * bm, struct bitmap_iterator * bi); 36 | bool bitmap_iterator_next(struct bitmap_iterator * bi, uint32_t* id); 37 | 38 | struct bitmap * bitmap_init(uint32_t maxid, uint8_t * buffer); 39 | void bitmap_finish(struct bitmap * bm); 40 | void bitmap_clear(struct bitmap * bm); 41 | void bitmap_setall(struct bitmap * bm); 42 | 43 | #endif /* bitmap.h */ 44 | -------------------------------------------------------------------------------- /experiments/feasibility/feasscript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=8; 3 | w=4; 4 | i=10; 5 | a=1000; 6 | t=4096; 7 | r=14880000; 8 | d=0; 9 | f=300; 10 | for j in `seq 0 9`; 11 | do for i in 20 10 5 1; 12 | do for f in 150 300 600 1200; 13 | do for p in 4 8 12 16; 14 | do for r in 14880000 14500000 14000000 13500000 13000000 12500000 12000000 11500000 11000000 10500000 10000000 9500000 9000000 8500000 8000000 7500000 7000000 6500000 6000000 5000000; 15 | do 16 | let t2=20*r; 17 | let t=4096/8*p; 18 | ./run.sh "-r $r -t $t2 -p 1 -D $d -l 1 -S 60 -a $a -f $f" "-t $t -p $p -P 32 -n $t2 -d 0.000005 -T 1 -l feas_${i}_${f}_${p}_${r}_${j} -w $w -i $i" _${i}_${f}_${p}_${r}_${j}; 19 | sleep 5; 20 | x=`cat feas_${i}_${f}_${p}_${r}_${j}_0.txt | grep "notfinished" | cut -f3 -d\ `; 21 | if [ $x -eq 0 ]; then 22 | break; 23 | fi; 24 | done; 25 | done; 26 | done; 27 | done; 28 | done 29 | 30 | #the script to summarize the result 31 | #for j in `seq 0 9`; 32 | # do for i in 20 10 5 1; 33 | # do for f in 150 300 600 1200; 34 | # do for p in 4 8 12 16; 35 | # do for r in 14880000 14500000 14000000 13500000 13000000 12500000 12000000 11500000 11000000 10500000 10000000 9500000 9000000 8500000 8000000 7500000 7000000 6500000 6000000 5000000; 36 | # do 37 | 38 | # echo `echo ${i},${f},${p},${r},${j}`,`cat feas_${i}_${f}_${p}_${r}_${j}_0.txt | grep "RX Packet Loss" | cut -f2 -d:| sed -e 's/ //g'`,`cat feas_${i}_${f}_${p}_${r}_${j}_0.txt | grep "notfinished" | cut -f3,7 -d\ |sed -e 's/ /,/g'`; 39 | # done; 40 | # done; 41 | # done; 42 | # done; 43 | -------------------------------------------------------------------------------- /experiments/matching/README.md: -------------------------------------------------------------------------------- 1 | This is the guide on how to replicate the result on matching delay. 2 | - enable the matching time evaluation script 3 | - uncomment the following lines in checkflow method of receiver/flatreport.c 4 | - uint64_t s = rte_rdtsc(); 5 | - fr->stat_matchdelay += rte_rdtsc() - s; 6 | - compile 7 | - run the matching delay1.sh script provided in this folder in the receiver folder 8 | - You can gather the result using delay1_result.sh 9 | 10 | Now we compare the matching delay for four different ways of defining triggers: 11 | - comment the following lines in receiver/basicfwd.c 12 | - flatreport_addtriggers(mt->fr, g.trigger_num, g.trigger_perpkt, g.trigger_patterns, types, 3); 13 | - and add the following line for each of the triggers instead of the above definition choices 14 | - No matching: flatreport_makenotmatchingtriggers(mt->fr, g.trigger_num, g.trigger_patterns, types[0]); 15 | - Mathing on 8: 16 | - flatreport_makeallmatchingtriggers(mt->fr, 8, types[0]); 17 | - if (g.trigger_num > 8){ 18 | - flatreport_makenotmatchingtriggers(mt->fr, g.trigger_num-8, g.trigger_patterns, types[0]); 19 | - } 20 | - 8 equal triggers: flatreport_makeperpktmatchingtriggers(mt->fr, g.trigger_num, g.trigger_patterns, types[0]); 21 | - 8 diff patterns: flatreport_makeperpktpatterntriggers(mt->fr, g.trigger_num, g.trigger_patterns, types[0]); 22 | - Uncomment the following lines in the beginneing of lcore_main method in receiver/basicfwd.c 23 | - flatreport_profilematching(mt->fr); 24 | - flatreport_finish(mt->fr); 25 | - return 0; 26 | - Compile 27 | - Now you can use delay2.sh to run the experiment. Pass a parameter like "equaltrigger" to separate each config logs. Use delay2_result.sh to gather the result 28 | -------------------------------------------------------------------------------- /receiver/messages.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGES_H 2 | #define MESSAGES_H 1 3 | #include 4 | #include "flow.h" 5 | 6 | #define MESSAGE_BUFSIZE 8 //make sure the maxsize is correct 7 | #define MESSAGE_MAXSIZE 64 8 | 9 | enum messagetype{ 10 | mt_hello, 11 | mt_addtrigger, 12 | mt_addtrigger_return, 13 | mt_deltrigger, 14 | mt_deltrigger_return, 15 | mt_triggersatisfaction, 16 | mt_triggerquery, 17 | mt_triggerquery_return, 18 | mt_bye 19 | }; 20 | 21 | struct messageheader{ 22 | enum messagetype type; 23 | uint16_t length; 24 | }; 25 | 26 | struct message_hello{ 27 | uint32_t id; 28 | uint32_t time; 29 | }; 30 | 31 | struct message_addtrigger{ 32 | struct flow f; 33 | struct flow mask; 34 | uint32_t eventid; 35 | uint32_t flowgranularity; 36 | uint16_t timeinterval; 37 | char buf[MESSAGE_BUFSIZE]; 38 | }; 39 | 40 | struct message_deltrigger{ 41 | struct flow f; 42 | struct flow mask; 43 | uint32_t eventid; 44 | }; 45 | 46 | struct message_deltrigger_return{ 47 | uint32_t time; 48 | uint16_t eventid; 49 | bool success; 50 | }; 51 | 52 | struct message_addtrigger_return{ 53 | uint32_t time; 54 | uint16_t eventid; 55 | bool success; 56 | }; 57 | 58 | struct message_triggersatisfaction{ 59 | struct flow f; 60 | uint32_t time; 61 | uint16_t eventid; 62 | uint16_t code; 63 | char buf [MESSAGE_BUFSIZE]; 64 | }; 65 | 66 | struct message_triggerquery{ 67 | struct flow f; 68 | struct flow mask; 69 | uint16_t eventid; 70 | uint16_t time; 71 | }; 72 | 73 | #endif /* messages.h */ 74 | -------------------------------------------------------------------------------- /controller/messages.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGES_H 2 | #define MESSAGES_H 1 3 | #include 4 | #include "flow.h" 5 | 6 | #define MESSAGE_BUFSIZE 8 //make sure the maxsize is correct 7 | #define MESSAGE_MAXSIZE 64 8 | 9 | enum messagetype{ 10 | mt_hello, 11 | mt_addtrigger, 12 | mt_addtrigger_return, 13 | mt_deltrigger, 14 | mt_deltrigger_return, 15 | mt_triggersatisfaction, 16 | mt_triggerquery, 17 | mt_triggerquery_return, 18 | mt_bye 19 | }; 20 | 21 | struct messageheader{ 22 | enum messagetype type; 23 | uint16_t length; 24 | }; 25 | 26 | struct message_hello{ 27 | uint32_t id; 28 | uint32_t time; 29 | }; 30 | 31 | struct message_addtrigger{ 32 | struct flow f; 33 | struct flow mask; 34 | uint32_t eventid; 35 | uint32_t flowgranularity; 36 | uint16_t timeinterval; 37 | char buf[MESSAGE_BUFSIZE]; 38 | }; 39 | 40 | struct message_deltrigger{ 41 | struct flow f; 42 | struct flow mask; 43 | uint32_t eventid; 44 | }; 45 | 46 | struct message_deltrigger_return{ 47 | uint32_t time; 48 | uint16_t eventid; 49 | bool success; 50 | }; 51 | 52 | struct message_addtrigger_return{ 53 | uint32_t time; 54 | uint16_t eventid; 55 | bool success; 56 | }; 57 | 58 | struct message_triggersatisfaction{ 59 | struct flow f; 60 | uint32_t time; 61 | uint16_t eventid; 62 | uint16_t code; 63 | char buf [MESSAGE_BUFSIZE]; 64 | }; 65 | 66 | struct message_triggerquery{ 67 | struct flow f; 68 | struct flow mask; 69 | uint16_t eventid; 70 | uint16_t time; 71 | }; 72 | 73 | #endif /* messages.h */ 74 | -------------------------------------------------------------------------------- /experiments/feasibility/feasscript2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | p=8; 3 | w=4; 4 | i=10; 5 | a=1000; 6 | t=4096; 7 | r=14880000; 8 | d=0; 9 | f=300; 10 | 11 | for j in `seq 0 4`; 12 | do for i in 20 10 5 1; 13 | do for a in 16000 32000 64000; 14 | do for p in 4 8 12 16; 15 | do for r in 14880000 14500000 14000000 13500000 13000000 12500000 12000000 11500000 11000000 10500000 10000000 9500000 9000000 8500000 8000000 7500000 7000000 6500000 6000000 5000000; 16 | do 17 | let t2=20*r; 18 | let t=4096/8*p; 19 | ./run.sh "-r $r -t $t2 -p 1 -D $d -l 1 -S 60 -a $a -f $f" "-t $t -p $p -P 32 -n $t2 -d 0.000005 -T 1 -l feas_${i}_${a}_${p}_${r}_${j} -w $w -i $i" _${i}_${a}_${p}_${r}_${j}; 20 | sleep 5; 21 | x=`cat feas_${i}_${a}_${p}_${r}_${j}_0.txt | grep "notfinished" | cut -f3 -d\ `; 22 | if [ $x -eq 0 ]; then 23 | break; 24 | fi; 25 | done; 26 | done; 27 | done; 28 | done; 29 | done 30 | 31 | # use to summarize the result 32 | #for j in `seq 0 4`; 33 | # do for i in 20 10 5 1; 34 | # do for a in 16000 32000 64000; 35 | # do for p in 4 8 12 16; 36 | # do for r in 14880000 14500000 14000000 13500000 13000000 12500000 12000000 11500000 11000000 10500000 10000000 9500000 9000000 8500000 8000000 7500000 7000000 6500000 6000000 5000000; 37 | # do 38 | # echo `echo ${i},${a},${p},${r},${j}`,`cat feas_${i}_${a}_${p}_${r}_${j}_0.txt | grep "RX Packet Loss" | cut -f2 -d:| sed -e 's/ //g'`,`cat feas_${i}_${a}_${p}_${r}_${j}_0.txt | grep "notfinished" | cut -f3,7 -d\ |sed -e 's/ /,/g'`; 39 | # done; 40 | # done; 41 | # done; 42 | # done; 43 | #done 44 | -------------------------------------------------------------------------------- /receiver/flowentry.c: -------------------------------------------------------------------------------- 1 | #include "flowentry.h" 2 | #include 3 | #include 4 | #include 5 | 6 | void flowentry_print(void * data); 7 | 8 | struct flowentry * flowentry_init(void){ 9 | struct flowentry * fe = (struct flowentry *) malloc (sizeof(struct flowentry)); 10 | memset(fe, 0, sizeof(struct flowentry)); 11 | return fe; 12 | } 13 | 14 | void flowentry_finish(struct flowentry * fe){ 15 | free(fe); 16 | } 17 | 18 | bool flowentry_print2(uint16_t id __attribute__((unused)), void * data, void * aux __attribute__((unused))){ 19 | struct flowentry * fe = (struct flowentry *) data; 20 | flow_inlineprint(&fe->f); 21 | printf(" %x\n", fe->summaries); 22 | /* printf(" volume: %llu, counter: %d, loss: ", (long long unsigned)fe->volume, fe->counter); 23 | losslisthead_apply(&fe->loss, losslist_print, NULL); 24 | printf(" burst: "); 25 | burstlisthead_apply(&fe->burst, burstlist_print, NULL); 26 | printf("\n");*/ 27 | return true; 28 | } 29 | 30 | void flowentry_print(void * data){ 31 | struct flowentry * fe = (struct flowentry *) data; 32 | flow_print(&fe->f); 33 | } 34 | 35 | inline bool flowentry_equal(void * data1, void * data2, void * aux __attribute__((unused))){ 36 | struct flowentry * fe1 = (struct flowentry *) data1; 37 | struct flowentry * fe2 = (struct flowentry *) data2; 38 | return flow_equal(&fe1->f, &fe2->f); 39 | } 40 | 41 | bool flowflowentry_equal(void * data, void * data2, void * aux __attribute__((unused))){ 42 | return flow_equal(&((struct flowentry *)data2)->f, (struct flow *)data); 43 | } 44 | 45 | void flowflowentry_init(void * data, void * data2, void * aux __attribute__((unused))){ 46 | // memset(data2, 0, sizeof(struct flowentry)); assume it is clean 47 | flow_fill(&((struct flowentry *)data2)->f, (struct flow *)data); 48 | } 49 | 50 | 51 | inline bool flowentry_isobsolete(struct flowentry * fe __attribute__((unused)), uint32_t step __attribute__((unused))){ 52 | #if TRIGGERTABLE_SWEEP 53 | //return step > 1000 && fe->lastupdate < step - 1000; 54 | return fe->lastupdate < step - 1 && step > 0; 55 | #endif 56 | return false; 57 | } 58 | -------------------------------------------------------------------------------- /receiver/flowentry.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOWENTRY_H 2 | #define FLOWENTRY_H 1 3 | #include 4 | #include "flow.h" 5 | #include "hashmap.h" 6 | #include "stdbool.h" 7 | #include "util.h" 8 | 9 | #define FLOWENTRY_TRIGGER_SIZE 16 10 | #define FLOWENTRY_BURST_SIZE 16 11 | #define FLOWENTRY_BURST_TS_THRESHOLD 5000 12 | #define FLOWENTRY_BURST_NUM_THRESHOLD 4 13 | #define LOSSLIST_BLOCK 32 14 | #define BURSTLIST_BLOCK 32 15 | 16 | #if TRIGGERTABLE_SWEEP 17 | #define FLOWENTRY_BUF_SIZE 87 // 128 - 16 - 8 - 8 - 1 - 8 18 | #else 19 | #define FLOWENTRY_BUF_SIZE 127 // 192 - 16 - 8 - 1 - 8 - 16*2 20 | #endif 21 | 22 | struct trigger; 23 | typedef uint16_t flowkey_t; 24 | 25 | typedef uint8_t summarymask_t; 26 | #define SUMMARIES_NUM 8 //note size of give byte size not bit size 27 | 28 | struct flowentry{ 29 | struct flow f; 30 | hashmap_elem e; //make sure e is in the first cache line 31 | #if TRIGGERTABLE_SWEEP 32 | uint32_t lastupdate; 33 | uint32_t lastreset; 34 | summarymask_t summaries; 35 | uint8_t summary_pos[SUMMARIES_NUM]; 36 | char buf[FLOWENTRY_BUF_SIZE]; 37 | #else 38 | summarymask_t summaries; 39 | uint8_t summary_pos[SUMMARIES_NUM]; 40 | char buf[FLOWENTRY_BUF_SIZE]; //putting this before triggers reduces cache miss alot 41 | uint16_t triggers[FLOWENTRY_TRIGGER_SIZE]; 42 | #endif 43 | }; 44 | 45 | struct flowentry * flowentry_init(void); 46 | 47 | /* 48 | * if the flow entry is already inside the flow table use flatreport_flowentry_finish 49 | */ 50 | void flowentry_finish (struct flowentry * fe); 51 | 52 | /* 53 | * if two flow entries are equal 54 | */ 55 | bool flowentry_equal(void * data1, void * data2, void * aux); 56 | 57 | /* 58 | */ 59 | bool flowentry_print2(uint16_t id, void * data, void * aux); 60 | 61 | /* 62 | * to compare a flow and a flowentry 63 | */ 64 | bool flowflowentry_equal(void * newdata, void * data2, void * aux); 65 | 66 | /* 67 | * To init a flowentry (data2) using a flow (newdata) 68 | */ 69 | void flowflowentry_init(void * newdata, void * data2, void * aux); 70 | bool flowentry_isobsolete(struct flowentry * fe, uint32_t step); 71 | 72 | #endif /* flowentry.h */ 73 | -------------------------------------------------------------------------------- /experiments/dospredict/README.md: -------------------------------------------------------------------------------- 1 | This guide explains how to replicate the data for DoS threshold prediction graph in the paper. 2 | For this we run an experiment with different threshold and percentage of DoS traffic and different number of patterns for trigger filters (matching complexity). Then, we also profile the TPM to get some statistics on how long it takes to do some basic steps such as matching. Finally we use a matlab script to predict the threshold and compare the prediction with the result from experiments. 3 | - To run the experiment, run dospredictscript.sh script provided in this folder in the receiver folder in the same setup as experiments/base10 4 | - We need three types of statistics: 5 | - For matching time, look at how to get it from experiments/matching. You can get it for the 4 different number of wildcard patterns. You also need the stat for the case that a flow comes in and doesn't match with any of the triggers (used for DoS traffic). Use -s 1 paramter for the sender (first param of run.sh) to shift the generated traffic to not match the triggers. 6 | - for free cycles just after processing packets: 7 | - uncomment the following lines in receiver/basicfwd.c in lcore_main method 8 | - runForZerots(mt); 9 | - return 0; 10 | - uncomment the following line in receiver/flatreport.c in checkflow method 11 | - fr->lastpktisddos = true; return NULL; 12 | - compile and run the experiments/base10. You can get the number of free cycles in 20s experiment by `grep zertos log_0.txt` 13 | - for sweep time (cycles used to process trigger-flow pair). For this you need change receiver/triggertable2.c to add the right counters to gather the time used for sweeping in total and the number of flows swept. You can do that with global variables and update them in triggertable_finishsweep. Just gather type->ticksperupdate and type->tickperupdate_num. Then print them in triggertable_finish. 14 | - To predict the threshold and draw the comparison diagram, run dosgraph.m provided in this folder. You may need to download columnlegend from https://www.mathworks.com/matlabcentral/fileexchange/27389-columnlegend 15 | - put the zerots numbers you got for 4 different dos traffic fraction in budget variable 16 | - put the matching and not matching cycles overhead in nomatch and matcch fields 17 | - put the sweep cycle overhea din sweep variable 18 | -------------------------------------------------------------------------------- /controller/serverdata.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVERDATA_H 2 | #define SERVERDATA_H 1 3 | #include 4 | #include 5 | #include "stdbool.h" 6 | #include "eventhandler.h" 7 | #include "messages.h" 8 | 9 | #define SERVERDATA_BUFSIZE 1500 10 | 11 | /* 12 | * The struct that is responsible for interacting witht he server 13 | * It is implemented as a polling loop that reads out of the server and if no data is available it will write any message in the queue to the server. So each serverdata will use a core 14 | * The queue is implemented as a ring that can be written by multiple threads. 15 | * If a thread sees a full thread, it will cause a flush to the output socket (spending its own cycles). 16 | * This uses non-blocking sockets. 17 | */ 18 | struct serverdata{ 19 | struct eventhandler * eh; 20 | struct rte_ring * outring; 21 | struct rte_mempool * outmem; 22 | pthread_mutex_t sendsocket_mutex;//need the mutex because of unexpected flushes 23 | uint32_t id; 24 | int fd; //socket handle 25 | uint32_t joiningtime; 26 | uint16_t inbuf_head; 27 | uint16_t inbuf_tail; 28 | bool finish; 29 | uint8_t core; 30 | struct sockaddr_in addr; 31 | char input_buffer[SERVERDATA_BUFSIZE]; 32 | char output_buffer[SERVERDATA_BUFSIZE]; 33 | }; 34 | 35 | struct serverdata * serverdata_init(struct eventhandler * eh, int childfd, struct sockaddr_in clientaddr, uint32_t id, uint8_t core); 36 | void serverdata_finish(struct serverdata * server); 37 | 38 | /* 39 | * Send add trigger message to the server 40 | */ 41 | void serverdata_addtrigger(struct serverdata * server, struct event * e, struct trigger * t); 42 | 43 | /* 44 | * Send delete trigger message to the server 45 | */ 46 | void serverdata_deltrigger(struct serverdata * server, struct event * e, struct trigger * t); 47 | 48 | /* 49 | * Query a server about an event at a specific time 50 | */ 51 | void serverdata_triggerquery(struct serverdata * server, struct event * e, uint32_t time, struct flow * f); 52 | 53 | bool serverdata_equal(struct serverdata * server1, struct serverdata * server2); 54 | 55 | /* 56 | * Convert server epoch num to the controller epoch number 57 | */ 58 | uint32_t serverdata_s2ctime(struct serverdata * server, uint32_t time); 59 | 60 | /* 61 | * Convert controller epoch number to the server epoch number 62 | */ 63 | uint32_t serverdata_c2stime(struct serverdata * server, uint32_t time); 64 | 65 | #endif /* serverdata.h */ 66 | -------------------------------------------------------------------------------- /sender/Makefile: -------------------------------------------------------------------------------- 1 | # BSD LICENSE 2 | # 3 | # Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions 8 | # are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Intel Corporation nor the names of its 17 | # contributors may be used to endorse or promote products derived 18 | # from this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | ifeq ($(RTE_SDK),) 33 | $(error "Please define RTE_SDK environment variable") 34 | endif 35 | 36 | # Default target, can be overridden by command line or environment 37 | RTE_TARGET ?= x86_64-native-linuxapp-gcc 38 | 39 | include $(RTE_SDK)/mk/rte.vars.mk 40 | 41 | # binary name 42 | APP = basicfwd 43 | 44 | # all source are stored in SRCS-y 45 | SRCS-y := basicfwd.c 46 | 47 | CFLAGS += $(WERROR_FLAGS) 48 | 49 | # workaround for a gcc bug with noreturn attribute 50 | # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 51 | ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) 52 | CFLAGS_main.o += -Wno-return-type 53 | endif 54 | 55 | EXTRA_CFLAGS += -O3 -g 56 | 57 | include $(RTE_SDK)/mk/rte.extapp.mk 58 | -------------------------------------------------------------------------------- /controller/Makefile: -------------------------------------------------------------------------------- 1 | # BSD LICENSE 2 | # 3 | # Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions 8 | # are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Intel Corporation nor the names of its 17 | # contributors may be used to endorse or promote products derived 18 | # from this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | ifeq ($(RTE_SDK),) 33 | $(error "Please define RTE_SDK environment variable") 34 | endif 35 | 36 | # Default target, can be overridden by command line or environment 37 | RTE_TARGET ?= x86_64-native-linuxapp-gcc 38 | 39 | include $(RTE_SDK)/mk/rte.vars.mk 40 | 41 | # binary name 42 | APP = tcpserver 43 | 44 | # all source are stored in SRCS-y 45 | SRCS-y := tcpserver.c util.c eventhandler.c serverdata.c hashmap.c bitmap.c flow.c lookup3.c loguser.c usecase.c 46 | 47 | CFLAGS += $(WERROR_FLAGS) 48 | 49 | # workaround for a gcc bug with noreturn attribute 50 | # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 51 | ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) 52 | CFLAGS_main.o += -Wno-return-type 53 | endif 54 | 55 | EXTRA_CFLAGS += -O3 -g 56 | 57 | include $(RTE_SDK)/mk/rte.extapp.mk 58 | -------------------------------------------------------------------------------- /experiments/dospredict/dosgraph.m: -------------------------------------------------------------------------------- 1 | %columns in the script are #patterns, dospackets fraction, threshold, #packets, #loss, #unfinished sweeps 2 | x=csvread('dosmeasure3.txt'); 3 | d = unique(x(:,1)); 4 | d2 = unique(x(:,2)); 5 | d2(d2==1)=[]; 6 | couldrun = x(:,4)>0; 7 | noloss = x(:,5)<10e4; 8 | nonotfinish = x(:,6)<2; 9 | clear m; for i = 1:length(d), for j = 1:length(d2), di = d(i); d2i = d2(j); m(i,j,:)=[di,d2i,min(x(and(and(x(:,1)==di,x(:,2)==d2i),and(and(couldrun, noloss),nonotfinish)),3))]; end; end; 10 | 11 | budget = [31772834447 23302599043 16409706978.5 10280450287]/20; % todrain, for different % of dos traffic 12 | sweep = 100; 13 | nomatch = [376 570 942 1884];% for different # patterns 14 | match = [607 906 1446 2456]; %from run 15 | flowlen = 10; 16 | matchperflow = 8; 17 | f2 = 1.5; 18 | clear t; 19 | for i = 1:length(d), 20 | for j = 1:length(d2), 21 | di = d(i); 22 | d2i = d2(j); 23 | rate = 10^10/((64*d2i+1500 *(1-d2i)+20)*8); 24 | % solve for t: b == match(i) *(d2i*rate/t + (1 - d2i)*rate/flowlen) 25 | % + 1.5 *matchperflow*sweep*(1 - d2i)*rate/flowlen 26 | %solve for t: b == match(i) *(d2i*rate/t + (1 - d2i)*rate/flowlen) + 1.5*n*sweep*(1 - d2i)*rate/flowlen 27 | %t = (d2i * flowlen* rate* (match(i) + 1.5 *matchperflow* sweep))/(budget * flowlen - rate * match(i)* (1-d2i) - 1.5*(1-d2i)*rate*matchperflow* sweep); 28 | t = d2i *flowlen *match(i) *rate/(budget(j) *flowlen - rate *((1-d2i) *match(i) + 1.5*(1-d2i) * matchperflow * sweep)); 29 | %pktnum = rate * 20; 30 | %flownum = d2i*pktnum/20 + (1-d2i)*pktnum/10; 31 | threshold(i,j,:) = [di, d2i, ceil(t)]; 32 | end 33 | end 34 | 35 | marks={'-vb','-^g','-sr','-ok'}; 36 | marks2={'--vb','--^g','--sr','--ok'}; 37 | figure; hold all; 38 | for i2=1:size(m,2), 39 | i=size(m,2)-i2+1; 40 | plot(d, m(:,i,3)*64/1000,marks{i},'LineWidth',2); 41 | end 42 | for i2=1:size(m,2), 43 | i=size(m,2)-i2+1; 44 | plot(d, threshold(:,i,3)*64/1000, marks2{i},'LineWidth',2); 45 | end 46 | % mean(mean(m(:,:,3)- threshold(:,:,3))*64/1000) 47 | % for i=1:size(m,2) 48 | % mean(m(:,i,3)- threshold(:,i,3))*64/1000 49 | % end 50 | 51 | set(gca,'xscale','log') 52 | set(gca,'XTick', [8 16 32 64]) 53 | xlim([7,68]); 54 | xlabel('# patterns'); 55 | ylabel('Threshold (KB)'); 56 | set(findobj(gcf, 'type','axes'),'fontsize',14) 57 | set(findall(gcf,'type','text'),'fontSize',14') 58 | set(gcf,'OuterPosition',[500,500,375,360]) 59 | l=columnlegend(2,[{'75'};{'50'};{'25'};{'75 p'};{'50 p'};{'25 p'}],'Location','NorthWest', 'fontsize',12); 60 | -------------------------------------------------------------------------------- /receiver/ddostable2.c: -------------------------------------------------------------------------------- 1 | #include "ddostable2.h" 2 | #include "util.h" 3 | #include "flatreport.h" 4 | #include "stdlib.h" 5 | #include "stdio.h" 6 | #include 7 | 8 | #define COUNTERMASK 0XFE00 //7 bits for counters, so this cannot keep any counter > 127 9 | #define STEPMAX 0x0200 10 | #define STEPMASK 0x01ff //9 bits for step. Reducing the number of bits for step will increase false-positivies 11 | 12 | 13 | inline void ddostable2_incpktnum(struct ddostable2 * dt, int inc){ 14 | if (unlikely(((dt->pktnum + inc) & 0x1ffff) < (dt->pktnum & 0x1ffff))){//if processed 128k pkts to throttle time checking overhead 15 | uint64_t time = rte_rdtsc(); 16 | if ((time - dt->laststeptime > dt->stepperiod)){ 17 | dt->step = (dt->step + 1) & STEPMASK; //Ignore the first 5 bits 18 | dt->laststeptime = time; 19 | } 20 | } 21 | 22 | dt->pktnum += inc; 23 | } 24 | 25 | bool ddostable2_add(struct ddostable2 * dt, struct flatreport_pkt * pkt){ 26 | uint16_t * buffer = (&dt->bufferstart) + (pkt->hash & dt->countarraymask); 27 | 28 | //check step 29 | int16_t stepdiff = (int16_t)dt->step - (*buffer & STEPMASK); 30 | if (stepdiff > 1 || (stepdiff < 0 && (stepdiff + STEPMAX) > 1)){ //every two epoch 31 | *buffer &= STEPMASK; //reset counter 32 | } 33 | 34 | //update step 35 | *buffer = (*buffer & COUNTERMASK) | dt->step; 36 | 37 | //update counter, first check then update to avoid overloading the counter because of collisions 38 | if (*buffer >= dt->threshold_1){ 39 | return true; 40 | } 41 | //increment counter 42 | *buffer += STEPMAX * (pkt->length/64 + (pkt->length%64 > 0?1:0)); 43 | return false; 44 | } 45 | 46 | //countarraysize must be power of 2 47 | struct ddostable2 * ddostable2_init(uint16_t threshold, uint32_t countarraysize){ 48 | threshold = threshold/64 + (threshold%64 > 0?1:0); 49 | if (threshold > COUNTERMASK/STEPMAX || threshold == 0){ 50 | fprintf(stderr, "too large ddos threshold or 0 threshold\n"); 51 | exit(1); 52 | } 53 | struct ddostable2 * dt = BIGMALLOC (sizeof(struct ddostable2) + sizeof(uint16_t) * (countarraysize-1));// -1 is becuase bufferstart is already got space in ddostable2 struct 54 | memset(&dt->bufferstart, 0, countarraysize); 55 | dt->countarraymask = countarraysize - 1; 56 | dt->threshold_1 = (threshold-1) * STEPMAX; //-1 because increment is done after condition check 57 | dt->pktnum = 0; 58 | dt->step = 0; 59 | dt->stepperiod = 10 * (uint64_t)rte_get_tsc_hz()/1e3; 60 | dt->laststeptime = rte_rdtsc(); 61 | 62 | return dt; 63 | } 64 | 65 | void ddostable2_finish(struct ddostable2 * dt){ 66 | BIGFREE(dt); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /experiments/netwide_usecase/README.md: -------------------------------------------------------------------------------- 1 | This is the guide on how to replicate the experiment for the network-wide usecase. 2 | In this usecase, there are two servers that connect to the controller. 3 | Each seerver has two 10G NICs and runs two parallel TPMs, each for a port. 4 | We have a sender machine that sends traffic to those four ports using a single port 5 | This is the workflow of the experiment: 6 | - Upon joining of a TPM, the controller installs x events. The events are just packet counting with low threshold, so they will be satisfied every epoch 7 | - Upon satisfaction at each TPM, the TPM sends a message to the controller. 8 | - The controller polls all other TPMs 9 | - The TPM reply to the poll and the controller pocesses them. 10 | - The controller and the TPMs create logs, which will be processed and gathered at the controller with a script. 11 | 12 | To run the experiment: 13 | - change the following flags at the receiver/basicfwd.c and compile 14 | - NOWORKER to 1 15 | - MEASUREMENTTHREAD_NUM to 2 16 | - MULTIPORT to 1 17 | - Make sure you configured both ports at each TPM to use DPDK driver 18 | - The generator will use four different queues at the NIC to send to those four ports at the TPMs. Set MULTIPORT to 0 in sender/basicfwd.c and compile it. 19 | - I assume the controller IP is 192.168.0.1. Note that this means we are using out of band controller. but you can use in-band controller connection too, by enabling the receiver to use KNI (look at the congestion usecase). You can run the controller at the sender machine. 20 | - I assume we want 16 events. You need to run the experiment for 4, 16, 64 and 256 events to get the result in the paper. 21 | - At controller run: e=16; sudo -E ./build/tcpserver -c 0x5555 -n 4 --file-prefix=controller_ -m 128 -- -s 4 -l netwide_$e -e $e -u 2 22 | - At both receivers run: sudo -E build/basicfwd -c 0xaaaa -n 4 -- -t 0 -p 0 -P 32 -n 297610000 -d 0.000005 -c 192.168.0.1 -l netwide_16 23 | - At sender you need to set the MAC address of the four ports at servers in the dstmac.txt. I used the dstmac.txt file provided in this folder 24 | - At sender run: sudo -E build/basicfwd -c 0xaaaa -n 4 --file-prefix=sender_ -m 128 -- -t 800000 -p 15 25 | 26 | Once the experiment finishes for all four different number of events, you can process and gather the logs at the controller using the following script. 27 | - At controller to gather logs 28 | - copy logprocess.sh from this folder to the receiver folder at the servers 29 | - make sure you update the IP addresses in getlogs.sh, and update folder and username at runandgather.sh files in the controller folder 30 | - run ./getlogs.sh netwide 31 | - The output log files will have the timestamps for reciving and sending all messages in the controller and TPMs. You can process the logs and generate the graph in the paper using the matlab script in dranetworkwide_doc.m file in this folder 32 | 33 | At the end, make ssure you bring back the options in the receiver and the sender to the default one and compile 34 | -------------------------------------------------------------------------------- /receiver/client.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIENT_H 2 | #define CLIENT_H 1 3 | #include 4 | #include 5 | #include "stdbool.h" 6 | #include "triggertable2.h" 7 | #include "messages.h" 8 | 9 | #define CLIENT_BUFSIZE 1500 10 | #define REQUESTLIST_BUFSIZE 10 11 | 12 | struct flatreport; 13 | 14 | /* 15 | * Keeps a batch of unanswered polls (polls for an epoch that came before the epoch finishes because of synchronization issues across end-hosts) 16 | * Each requestlist has a time (epoch number), and they are stored in a sorted linked list 17 | */ 18 | struct requestlist{ 19 | uint32_t time; 20 | struct message_triggerquery buf[REQUESTLIST_BUFSIZE]; 21 | uint16_t filled; 22 | struct requestlist * next; 23 | }; 24 | 25 | /* 26 | * This struct handles the communication with the controller. 27 | * It runs in synchronized mode that handles controller commands (read/write) by reading/writing 28 | * a buffer using unblocking system calls given some free CPU cycles and a time-budget 29 | */ 30 | struct client{ 31 | struct flatreport * fr; 32 | struct requestlist * rl; 33 | struct requestlist * freerl; 34 | int rl_lastindex; 35 | int fd; 36 | uint16_t inbuf_tail; 37 | uint16_t inbuf_head; 38 | uint16_t outbuf_tail; 39 | uint16_t reportinterval; 40 | bool finish; 41 | bool hasdatatoread; 42 | uint8_t readseqnum; // for debug message to optimize poll time & to know if client actually checked the input buffer 43 | char input_buffer[CLIENT_BUFSIZE]; // buffer for messages from the controller 44 | char output_buffer[CLIENT_BUFSIZE];// buffer for messages to the controller 45 | }; 46 | /* 47 | * instantiates the client object and connects to the server. 48 | */ 49 | struct client * client_init(char * ip, uint16_t port, uint16_t reportinterval); 50 | 51 | void client_finish(struct client * c); 52 | 53 | /* 54 | * creates the message in a buffer to be sent later if client_readsync got free cycles 55 | */ 56 | void client_sendtriggersync(struct client * c, struct trigger *t, uint32_t time, bool satisfaction_or_query); 57 | 58 | /* 59 | * if onlysync is false, creates a message out for saatissfaction of a trigger for the controller and schedules that to be sent. 60 | */ 61 | void client_sendtriggerasync(struct client * c, struct trigger * t, uint32_t time); 62 | 63 | void client_test(struct client * c); 64 | 65 | /* 66 | * The main method that tells the client to take the CPU core to send/receive messages to/from the controller. 67 | */ 68 | void client_readsync(struct client * c, uint64_t timebudget, uint64_t start); 69 | 70 | /* 71 | * Sends hello message to the controller and blocks until it is sent 72 | */ 73 | void client_hello(struct client * c, uint32_t id, uint32_t time); 74 | 75 | /* 76 | * waits until it receives a hello reply from the controller. Note that the client should have said hello first 77 | */ 78 | void client_waitforhello(struct client * c); 79 | 80 | /* 81 | * sends satisfaction of a trigger to the controller and waits until it is sent (no buffer or wait till readsync is called during free cycles) 82 | */ 83 | void client_sendsatisfactionsync(struct client * c, struct trigger *t, uint32_t time); 84 | #endif /* client.c */ 85 | -------------------------------------------------------------------------------- /experiments/congestion_usecase/udpthroughputdiagram.m: -------------------------------------------------------------------------------- 1 | clear; 2 | 3 | % #ask 1 4 | % #satisfaction 2 5 | % #return 3 6 | % #add return 4 7 | % #all received 5 8 | % #add event 6 9 | % #del event 7 10 | % #del return 8 11 | %c cols: time, server, message type, server epoch, event, epoch 12 | %send 1 13 | %query 2 14 | %add 3 15 | %del 4 16 | %s cols: time, type, time, step, event 17 | name='proudp'; 18 | c=csvread(sprintf('udp/%s_c.log',name)); 19 | s{1}=csvread(sprintf('udp/%s_0.log',name)); 20 | s{2}=csvread(sprintf('udp/%s_1.log',name)); 21 | s{3}=csvread(sprintf('udp/%s_2.log',name)); 22 | 23 | c3 = c; 24 | c3(:,1)=(c(:,1)-min(c(:,1)))/2.6e6; 25 | logudp = (10736234033676071-c(1,1))/2.6e6; 26 | left = logudp-70; 27 | right = logudp+300; 28 | 29 | figure; 30 | hold all; 31 | xlim([min(c3(:,1))-1, max(c3(:,1))]+1); 32 | ee = unique(c(:,5)); 33 | marks = {'^b','vk','xr','og'}; 34 | for e2 = 1:length(ee); %0:5, 35 | e = ee(e2); 36 | c2 = c3(c3(:,5)==e,:); 37 | 38 | for i=1:size(c2,1) 39 | c2i = c2(i,:); 40 | if (c2i(3)~=2) %not a satisfaction 41 | continue; 42 | end 43 | 44 | y = c2i(2); 45 | if (e>2) 46 | pattern = marks{4}; 47 | plot(c2i(1)-left, y, pattern, 'MarkerSize',8, 'LineWidth', 2); 48 | else 49 | pattern = marks{y+1}; 50 | plot(c2i(1)-left, y, pattern, 'MarkerSize',9, 'LineWidth', 2); 51 | end 52 | 53 | end 54 | end 55 | 56 | x=csvread(sprintf('udp/%s_trace2.txt',name)); 57 | x(x(:,2)==3,:)=[]; 58 | timemin = min(x(:,1)); 59 | timemax = max(x(:,1)); 60 | t=[timemin:0.01:(timemax+0.2)]; 61 | 62 | %figure; 63 | %hold all; 64 | 65 | server=1; proto=6; 66 | y=x(and(x(:,2)==server, x(:,4)==proto),:); 67 | for i=2:length(t), 68 | ti1 = t(i-1); 69 | ti2 = t(i); 70 | m1(i)=sum(x(and(y(:,1)>=ti1,y(:,1)=ti1,y(:,1)=ti1,y(:,1)tools/setup.sh file to set it up 8 | - Compile: On linux and 64-bit machines, type number 14 for "x86_64-native-linuxapp-gcc" 9 | - Install NIC driver module: type number 17 for "Insert IGB UIO module" 10 | - Install KNI module: type number 19 for "Insert KNI module" 11 | - hugepages: type number 21 for "Setup hugepage mappings for NUMA systems" 12 | - Add NICs to IGB driver: 13 | - Type 23 "Bind Ethernet device to IGB UIO module" and you will get the list of NICs in the machine 14 | - Each line represents a port. A line may be like "0000:82:00.1 '82599 10 Gigabit TN Network Connection' if=eth7 drv=ixgbe unused=igb_uio" 15 | - type the PCI address. For the above example it is 0000:82:00.1 16 | - Now add the following lines at the end of .bashrc file in your home folder. Replace with the path of where you put the dpdk folder 17 | - export RTE_SDK= 18 | - export RTE_TARGET=x86_64-native-linuxapp-gcc 19 | - To make sure bash reads the config again you may make a new terminal or just run bash command. 20 | - Now we need to isolate CPU cores for Trumpet from other processes. We can do that by adding the following line into /etc/default/grub. 21 | - This command isolates cores with odd number (cores on CPU 1 on a NUMA architecture). Add it to the file. GRUB_CMDLINE_LINUX="iommu=pt intel_iommu=on isolcpus=1,3,5,7,9,11,13,15,17,19" 22 | - If you are using a NUMA architecture, you first need to find out to which CPU the NIC is connected. Processing the packets on the CPU that is directly connected to the NIC is faster. For this run "cat /sys/class/net/eth6/device/numa_node" assuming the NIC is eth6. If it is CPU 0, you also need to update the core mask in the dpdk parameter list passed inside run.sh. 23 | - run sudo grub-update, and reboot. 24 | - Also make sure that you have sudo access 25 | - Make sure you can get sudo access without the need to type password. For this you need to add the following line in the sudoers file. run "sudo visudo". Then add the "masoud ALL=(ALL:ALL) NOPASSWD: ALL". Replace masoud with your username. Push ctrl+x and choose yes to save and exit. 26 | - You either need to pass password to the ssh command or setup public/private key authentication for that. To use public/private key use the steps here: https://help.ubuntu.com/community/SSH/OpenSSH/Keys. If you choose a passphrase for the key pair, you may want to use the ssh-agent to remember it. Look at http://rabexc.org/posts/using-ssh-agent. So after this you should be able to ssh from the receiver machine to the sender without using the password. 27 | - There are three components in this package provided in separate folders: receiver, sender and controller. Make sure you can compile all three. Each component has a -h commandline that shows the commandline parameter help. 28 | 29 | Done. 30 | You can reverse the config by running the tools/setup.sh again and 31 | - Unbind nics: 29 for "Unbind NICs from IGB UIO or VFIO driver". You may be asked to type the name of the driver to put the port back to it. For the above exxample it is ixgbe 32 | - Unload IGB and KNI using 30 and 32 33 | - Remove huge pages using number 33 34 | 35 | 36 | You may start with the experiments/base10. 37 | -------------------------------------------------------------------------------- /experiments/netwide_usecase/getnetworkwidestats.m: -------------------------------------------------------------------------------- 1 | % #ask 1 2 | % #satisfaction 2 3 | % #return 3 4 | % #add 4 5 | % #all received 5 6 | %c cols: time, server, message type, server epoch, event, epoch 7 | %function [statsm,t]=getnetworkwidestats(c,s) 8 | clear statsm statse stats ce ct s2 ee t tt 9 | 10 | ee = unique(c(:,5)); 11 | stats = []; 12 | statsm = []; 13 | statse = []; 14 | start = min(c(c(:,3)==2,1)); 15 | for e2 = 1:length(ee), 16 | e = ee(e2); 17 | ce = c(c(:,5)==e,:); 18 | ce(:,1)=(ce(:,1)-start)/2.6e6; 19 | s2 = s; 20 | for i=1:length(s) 21 | s2{i}(:,1)=(s2{i}(:,1)-s2{i}(1,1))/2.3e6; 22 | s2{i} = s2{i}(s2{i}(:,5)==e,:); 23 | end 24 | tt = unique(ce(:,6)); 25 | k=1; 26 | for i = 1:length(tt) 27 | ti = tt(i); 28 | ct = ce(ce(:,6)==ti,:); 29 | if (sum(ct(:,3)==2,1)==0) 30 | continue; 31 | end 32 | t{e2}(k)=ti; 33 | k=k+1; 34 | end 35 | k = length(t{e2}); 36 | satnum = zeros(k,1); 37 | firstsat = zeros(k,1); 38 | lastsat = zeros(k,1); 39 | firstask = zeros(k,1); 40 | resultready = zeros(k,1); 41 | pollend = zeros(k,1); 42 | lastask = zeros(k,1); 43 | for i = 1:k 44 | ti = t{e2}(i); 45 | ct = ce(ce(:,6)==ti,:); 46 | satnum(i) = sum(ct(:,3)==2,1); 47 | if (satnum(i) < 4) 48 | continue; 49 | end 50 | firstsat(i)= min(ct(ct(:,3)==2, 1)); 51 | lastsat(i)= max(ct(ct(:,3)==2, 1)); 52 | firstask(i)= min(ct(ct(:,3)==1, 1)); 53 | lastask(i)= max(ct(ct(:,3)==1, 1)); 54 | try 55 | resultready(i)= min(ct(ct(:,3)==5,1)); %with rwlock, there can be multiple! 56 | pollend(i)= max(ct(ct(:,3)==3, 1)); 57 | catch 58 | display(sprintf('%d error event %d at %d',i,e,ti)); 59 | satnum(i) =0; 60 | end 61 | 62 | end 63 | index = satnum == 4; 64 | stats=[stats; firstask(index)- firstsat(index), lastask(index)- firstsat(index), lastsat(index)- firstsat(index), pollend(index)- firstsat(index)]; 65 | statsm{e2}=[t{e2}(index)', firstsat(index), lastsat(index), pollend(index)]; 66 | t{e2}=t{e2}(index); 67 | end 68 | 69 | % figure; hold all; for i=1:size(stats,2),[h, hx]=hist(stats(:,i),1000); 70 | % plot(hx, cumsum(h)/sum(h), 'LineWidth', 2); end; 71 | % legend({'1st Sat-Poll', 'Last ask-1st ask', '1st Sat-Last sat','1st Sat-Poll result'}); 72 | % set(findall(gcf,'type','text'),'fontSize',14') 73 | % set(findobj(gcf, 'type','axes'),'fontsize',14) 74 | % xlabel('Time(ms)'); 75 | % ylabel('CDF'); 76 | % 77 | % 78 | % figure; 79 | % barwitherr(std(stats), mean(stats)) 80 | % ylabel('Time (ms)'); 81 | % set(gca,'XTickLabel', {'1st Sat-Poll', 'Last ask-1st ask', '1st Sat-Last sat','1st Sat-Poll result'}); 82 | % set(findobj(gcf, 'type','axes'),'fontsize',14) 83 | % set(findall(gcf,'type','text'),'fontSize',14') 84 | % 85 | % color = jet(101); 86 | % figure; 87 | % hold all; 88 | % mmin=1000; 89 | % mmax=0; 90 | % for i=1:length(statsm), 91 | % mmin=min(mmin, min(statsm{i}(:,4)-statsm{i}(:,2))); 92 | % mmax=max(mmax, max(statsm{i}(:,4)-statsm{i}(:,2))); 93 | % end 94 | % range = mmax - mmin; 95 | % for i=1:length(statsm), 96 | % for j=1:size(statsm{i},1), 97 | % col=color(floor((statsm{i}(j,4)-statsm{i}(j,2)-mmin)/range*100+1),:); 98 | % plot(statsm{i}(j,1),i,'.', 'Color',col); 99 | % end; 100 | % % plot(statsm{i}(:,1),i+statsm{i}(:,4)-statsm{i}(:,2)); 101 | % end 102 | %end -------------------------------------------------------------------------------- /receiver/heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "heap.h" 7 | 8 | // TODO: may do optimizations from http://stackoverflow.com/questions/6531543/efficient-implementation-of-binary-heaps 9 | 10 | // Prepares the heap for use 11 | struct heap * heap_init(uint16_t size, heap_cmp_func cmp_func, heap_index_func index_func){ 12 | struct heap * h = (struct heap *) malloc (sizeof (struct heap) + sizeof(heap_type)*(size-1)); 13 | h->size = size; 14 | h->count = 0; 15 | h->cmp_func = cmp_func; 16 | h->index_func = index_func; 17 | h->data = NULL; 18 | return h; 19 | } 20 | 21 | void heap_finish(struct heap * h){ 22 | free(h); 23 | } 24 | 25 | // Inserts element to the heap 26 | void heap_push(struct heap * h, heap_type value){ 27 | unsigned int index, parent; 28 | if (h->count >= h->size){ //check size 29 | return; 30 | } 31 | 32 | // Find out where to put the element and put it 33 | heap_type * data = &h->data; 34 | for (index = h->count++; index; index = parent){ 35 | parent = (index - 1) >> 1; 36 | if (h->cmp_func(data[parent], value)) { 37 | break; 38 | } 39 | data[index] = data[parent]; 40 | h->index_func(data[index], index); 41 | } 42 | data[index] = value; 43 | h->index_func(data[index], index); 44 | } 45 | 46 | void reorder(struct heap * h, heap_type candidate, uint16_t index){ 47 | uint16_t swap, other; 48 | heap_type * data = &h->data; 49 | // Reorder the elements 50 | for(; 1; index = swap){ 51 | // Find the child to swap with 52 | swap = (index << 1) + 1; 53 | if (swap >= h->count) { // If there are no children, the heap is reordered 54 | break; 55 | } 56 | other = swap + 1; 57 | if ((other < h->count) && h->cmp_func(data[other], data[swap])) { //pick the best child to become parent 58 | swap = other; 59 | } 60 | if (h->cmp_func(candidate, data[swap])) { // If the bigger child is less than or equal to its parent, the heap is reordered 61 | break; 62 | } 63 | data[index] = data[swap]; 64 | h->index_func(data[index], index); 65 | } 66 | data[index] = candidate; 67 | h->index_func(data[index], index); 68 | } 69 | 70 | void heap_replace(struct heap * h, heap_type value, uint16_t oldIndex){ 71 | reorder(h, value, oldIndex); 72 | } 73 | 74 | // avoid heapify twice 75 | heap_type heap_push_pop (struct heap * h, heap_type value){ 76 | if (h->cmp_func(value, h->data) || h->count == 0){ 77 | return value; //no need to add, new value is already min 78 | } 79 | //replace value instead of the root element 80 | heap_type output = h->data; 81 | reorder(h, value, 0); 82 | return output; 83 | } 84 | 85 | // Removes the root element from the heap 86 | heap_type heap_pop(struct heap * h){ 87 | // Remove the root element 88 | heap_type output = h->data; 89 | heap_type * data = &h->data; 90 | reorder(h, data[--h->count], 0); 91 | return output; 92 | } 93 | 94 | uint16_t heap_size(struct heap * h){ 95 | return h->count; 96 | } 97 | 98 | bool num_less_func(void * a, void * b){ 99 | return (*((uint32_t *)a)) <= (*((uint32_t *)b)); 100 | } 101 | 102 | bool num_less_func2(void * a, void * b){ 103 | return (((uint32_t *)a)) <= (((uint32_t *)b)); 104 | } 105 | 106 | void void_index_func(void * a, uint16_t index){ 107 | } 108 | 109 | /*int main(int argc, char **argv) { 110 | int size = 128; 111 | int num = 1000000; 112 | if (argc>1){ 113 | size = atoi(argv[1]); 114 | if (argc>2){ 115 | num = atoi(argv[2]); 116 | } 117 | } 118 | printf("%d: ", size); 119 | struct heap * h = heap_init(size, num_less_func, void_index_func); 120 | srand(0x1238f2a9); 121 | uint32_t data0[num]; 122 | int i; 123 | { 124 | for (i=0; icount); 147 | uint64_t sum=0; 148 | while (h->count>0){ 149 | sum+=*((uint32_t *)heap_pop(h)); 150 | } 151 | printf("%llu\n", (long long unsigned)sum); 152 | 153 | heap_finish(h); 154 | }*/ 155 | -------------------------------------------------------------------------------- /controller/flow.c: -------------------------------------------------------------------------------- 1 | #include "flow.h" 2 | #include "lookup3.h" 3 | #include 4 | #include 5 | 6 | inline bool flow_equal(struct flow * f1, struct flow * f2){ 7 | return *(((uint64_t *)f1)) == *(((uint64_t *)f2)) && *(((uint64_t *)f1) +1) == *(((uint64_t *)f2) +1); 8 | } 9 | 10 | inline bool flow_equal3(void * d1, void * d2){ 11 | return *(((uint64_t *)d1)) == *(((uint64_t *)d2)) && *(((uint64_t *)d1) +1) == *(((uint64_t *)d2) +1); 12 | /* struct flow * f1 = (struct flow *) d1; 13 | struct flow * f2 = (struct flow *) d2; 14 | return f1->srcip == f2->srcip && f1->dstip == f2->dstip && f1->ports == f2->ports && f1->protocol == f2->protocol;*/ 15 | } 16 | 17 | inline uint32_t flow_hash (struct flow * f){ 18 | // return ntohl(f->dstip); 19 | // return ntohl(f->srcip^f->dstip)^f->ports; 20 | // return ntohl(f->srcip)+ntohl(f->dstip)+f->ports; 21 | return jhash_3words(f->srcip, f->dstip, f->ports, 0x13572468); 22 | } 23 | 24 | inline void flow_fill(struct flow * dst, struct flow * src){ 25 | *((uint64_t *)dst) = *((uint64_t *)src); 26 | *(((uint64_t *)dst) + 1) = *(((uint64_t *)src) +1); 27 | /* dst->srcip = src->srcip; 28 | dst->dstip = src->dstip; 29 | dst->ports = src->ports; 30 | dst->protocol = src->protocol;*/ 31 | } 32 | 33 | inline bool flow_equal2(struct flow * f1, uint32_t srcip, uint32_t dstip, uint32_t ports, uint32_t protocol){ 34 | return f1->srcip == srcip && f1->dstip == dstip && f1->ports == ports && f1->protocol == protocol; 35 | } 36 | 37 | void flow_print(struct flow * f){ 38 | flow_inlineprint(f); 39 | printf("\n"); 40 | } 41 | 42 | void flow_inlineprint2(struct flow * f, char * buf){ 43 | struct in_addr srcip; 44 | struct in_addr dstip; 45 | srcip.s_addr = f->srcip; 46 | dstip.s_addr = f->dstip; 47 | 48 | sprintf(buf,"%s:%u, ", inet_ntoa(srcip), ntohs(f->ports>>16)); 49 | sprintf(buf+strlen(buf)-1,"%s:%u", inet_ntoa(dstip), ntohs(f->ports & 0xFFFF)); 50 | } 51 | 52 | void flow_inlineprint(struct flow * f){ 53 | struct in_addr srcip; 54 | struct in_addr dstip; 55 | srcip.s_addr = f->srcip; 56 | dstip.s_addr = f->dstip; 57 | 58 | printf("%s:%u, ", inet_ntoa(srcip), ntohs(f->ports>>16)); 59 | printf("%s:%u", inet_ntoa(dstip), ntohs(f->ports & 0xFFFF)); 60 | } 61 | 62 | 63 | inline void flow_mask(struct flow * dst, struct flow * src, struct flow * maskflow){ 64 | *((uint64_t *)dst) = *((uint64_t *)src) & *(((uint64_t *)maskflow)); 65 | *(((uint64_t *)dst) + 1) = *(((uint64_t *)src) +1) & *(((uint64_t *)maskflow) +1); 66 | /* dst->srcip = src->srcip & maskflow->srcip; 67 | dst->dstip = src->dstip & maskflow->dstip; 68 | dst->ports = src->ports & maskflow->ports; 69 | dst->protocol = src->protocol && maskflow->protocol; */ 70 | } 71 | 72 | void flow_parseflowgranularity(uint32_t flowgranularity, uint8_t* srcip_len, uint8_t* dstip_len, uint8_t* srcport_len, uint8_t* dstport_len, uint8_t* protocol_len){ 73 | *protocol_len = flowgranularity & 0x3f; 74 | if (*protocol_len > 8){ 75 | *protocol_len = 8; 76 | } 77 | flowgranularity >>= 6; 78 | *dstport_len = flowgranularity & 0x3f; 79 | if (*dstport_len > 16){ 80 | *dstport_len = 16; 81 | } 82 | flowgranularity >>= 6; 83 | *srcport_len = flowgranularity & 0x3f; 84 | if (*srcport_len > 16){ 85 | *srcport_len = 16; 86 | } 87 | flowgranularity >>= 6; 88 | *dstip_len = flowgranularity & 0x3f; 89 | if (*dstip_len > 32){ 90 | *dstip_len = 32; 91 | } 92 | flowgranularity >>= 6; 93 | *srcip_len = flowgranularity & 0x3f; 94 | if (*srcip_len > 32){ 95 | *srcip_len = 32; 96 | } 97 | } 98 | 99 | 100 | uint32_t flow_makeflowgranularity(uint8_t srcip_len, uint8_t dstip_len, uint8_t srcport_len, uint8_t dstport_len, uint8_t protocol_len){ 101 | return (((((((srcip_len<<6) | dstip_len)<<6) | srcport_len)<<6) | dstport_len)<<6) | protocol_len; 102 | } 103 | 104 | void flow_makemask(struct flow * mask, uint8_t srcip_len, uint8_t dstip_len, uint8_t srcport_len, uint8_t dstport_len, uint8_t protocol_len){ 105 | mask->srcip = 0x00ffffffffUL << (32-srcip_len); 106 | mask->dstip = 0x00ffffffffUL << (32-dstip_len); 107 | mask->ports = ((0x00000000ffffUL << (32-srcport_len))&0xffff0000) | ((0x0000ffff << (16-dstport_len)) & 0x0000ffff); 108 | mask->protocol = (0x000000ff <<(8-protocol_len)) & 0x000000ff; 109 | 110 | mask->srcip = ntohl(mask->srcip); 111 | mask->dstip = ntohl(mask->dstip); 112 | mask->ports = (ntohs(mask->ports>>16)<<16)|ntohs(mask->ports & 0xffff); 113 | } 114 | -------------------------------------------------------------------------------- /receiver/flow.c: -------------------------------------------------------------------------------- 1 | #include "flow.h" 2 | #include "lookup3.h" 3 | #include 4 | #include 5 | 6 | inline bool flow_equal(struct flow * f1, struct flow * f2){ 7 | return *(((uint64_t *)f1)) == *(((uint64_t *)f2)) && *(((uint64_t *)f1) +1) == *(((uint64_t *)f2) +1); 8 | } 9 | 10 | inline bool flow_equal3(void * d1, void * d2){ 11 | return *(((uint64_t *)d1)) == *(((uint64_t *)d2)) && *(((uint64_t *)d1) +1) == *(((uint64_t *)d2) +1); 12 | /* struct flow * f1 = (struct flow *) d1; 13 | struct flow * f2 = (struct flow *) d2; 14 | return f1->srcip == f2->srcip && f1->dstip == f2->dstip && f1->ports == f2->ports && f1->protocol == f2->protocol;*/ 15 | } 16 | 17 | inline uint32_t flow_hash (struct flow * f){ 18 | // return ntohl(f->dstip); 19 | // return ntohl(f->srcip^f->dstip)^f->ports; 20 | // return ntohl(f->srcip)+ntohl(f->dstip)+f->ports; 21 | return jhash_3words(f->srcip, f->dstip, f->ports, 0x13572468); 22 | } 23 | 24 | inline void flow_fill(struct flow * dst, struct flow * src){ 25 | *((uint64_t *)dst) = *((uint64_t *)src); 26 | *(((uint64_t *)dst) + 1) = *(((uint64_t *)src) +1); 27 | /* dst->srcip = src->srcip; 28 | dst->dstip = src->dstip; 29 | dst->ports = src->ports; 30 | dst->protocol = src->protocol;*/ 31 | } 32 | 33 | inline bool flow_equal2(struct flow * f1, uint32_t srcip, uint32_t dstip, uint32_t ports, uint32_t protocol){ 34 | return f1->srcip == srcip && f1->dstip == dstip && f1->ports == ports && f1->protocol == protocol; 35 | } 36 | 37 | void flow_print(struct flow * f){ 38 | flow_inlineprint(f); 39 | printf("\n"); 40 | } 41 | 42 | void flow_inlineprint2(struct flow * f, char * buf){ 43 | struct in_addr srcip; 44 | struct in_addr dstip; 45 | srcip.s_addr = f->srcip; 46 | dstip.s_addr = f->dstip; 47 | 48 | sprintf(buf,"%s:%u, ", inet_ntoa(srcip), ntohs(f->ports>>16)); 49 | sprintf(buf+strlen(buf)-1,"%s:%u", inet_ntoa(dstip), ntohs(f->ports & 0xFFFF)); 50 | } 51 | 52 | void flow_inlineprint(struct flow * f){ 53 | struct in_addr srcip; 54 | struct in_addr dstip; 55 | srcip.s_addr = f->srcip; 56 | dstip.s_addr = f->dstip; 57 | 58 | printf("%s:%u, ", inet_ntoa(srcip), ntohs(f->ports>>16)); 59 | printf("%s:%u", inet_ntoa(dstip), ntohs(f->ports & 0xFFFF)); 60 | } 61 | 62 | 63 | inline void flow_mask(struct flow * dst, struct flow * src, struct flow * maskflow){ 64 | *((uint64_t *)dst) = *((uint64_t *)src) & *(((uint64_t *)maskflow)); 65 | *(((uint64_t *)dst) + 1) = *(((uint64_t *)src) +1) & *(((uint64_t *)maskflow) +1); 66 | /* dst->srcip = src->srcip & maskflow->srcip; 67 | dst->dstip = src->dstip & maskflow->dstip; 68 | dst->ports = src->ports & maskflow->ports; 69 | dst->protocol = src->protocol && maskflow->protocol; */ 70 | } 71 | 72 | void flow_parseflowgranularity(uint32_t flowgranularity, uint8_t* srcip_len, uint8_t* dstip_len, uint8_t* srcport_len, uint8_t* dstport_len, uint8_t* protocol_len){ 73 | *protocol_len = flowgranularity & 0x3f; 74 | if (*protocol_len > 8){ 75 | *protocol_len = 8; 76 | } 77 | flowgranularity >>= 6; 78 | *dstport_len = flowgranularity & 0x3f; 79 | if (*dstport_len > 16){ 80 | *dstport_len = 16; 81 | } 82 | flowgranularity >>= 6; 83 | *srcport_len = flowgranularity & 0x3f; 84 | if (*srcport_len > 16){ 85 | *srcport_len = 16; 86 | } 87 | flowgranularity >>= 6; 88 | *dstip_len = flowgranularity & 0x3f; 89 | if (*dstip_len > 32){ 90 | *dstip_len = 32; 91 | } 92 | flowgranularity >>= 6; 93 | *srcip_len = flowgranularity & 0x3f; 94 | if (*srcip_len > 32){ 95 | *srcip_len = 32; 96 | } 97 | } 98 | 99 | 100 | uint32_t flow_makeflowgranularity(uint8_t srcip_len, uint8_t dstip_len, uint8_t srcport_len, uint8_t dstport_len, uint8_t protocol_len){ 101 | return (((((((srcip_len<<6) | dstip_len)<<6) | srcport_len)<<6) | dstport_len)<<6) | protocol_len; 102 | } 103 | 104 | void flow_makemask(struct flow * mask, uint8_t srcip_len, uint8_t dstip_len, uint8_t srcport_len, uint8_t dstport_len, uint8_t protocol_len){ 105 | mask->srcip = 0x00ffffffffUL << (32-srcip_len); 106 | mask->dstip = 0x00ffffffffUL << (32-dstip_len); 107 | mask->ports = ((0x00000000ffffUL << (32-srcport_len))&0xffff0000) | ((0x0000ffff << (16-dstport_len)) & 0x0000ffff); 108 | mask->protocol = (0x000000ff <<(8-protocol_len)) & 0x000000ff; 109 | 110 | mask->srcip = ntohl(mask->srcip); 111 | mask->dstip = ntohl(mask->dstip); 112 | mask->ports = (ntohs(mask->ports>>16)<<16)|ntohs(mask->ports & 0xffff); 113 | } 114 | -------------------------------------------------------------------------------- /receiver/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 1 3 | 4 | #include 5 | #include "stdbool.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "loguser.h" 11 | 12 | #define LOG(format, ...) \ 13 | loguser_add(util_lu, format, ##__VA_ARGS__); \ 14 | 15 | 16 | /* 17 | * The strawman approach that updates triggers instead of the flow table 18 | */ 19 | #ifndef PACKETHISTORY 20 | #define PACKETHISTORY 0 21 | #endif 22 | 23 | #if PACKETHISTORY 24 | #define PKT_PREFETCH_ENABLE 0 25 | #define HASH_PREFETCH_ENABLE 0 26 | #define SWEEP_PREFETCH_ENABLE 0 27 | #define TRIGGERTABLE_SWEEP 0 28 | #define MULTISTEP 0 29 | #define DPDK_MALLOC 0 30 | #define DPDK_BIG_MALLOC 0 31 | #define TRIGGERTABLE_INLINE_TRIGGER 0 32 | #define FLATREPORT_PKT_BURST 64 33 | #define DDOS_TABLE 0 34 | #endif 35 | 36 | /* 37 | * disable or enable the DDoS table 38 | */ 39 | #ifndef DDOS_TABLE 40 | #define DDOS_TABLE 1 41 | #endif 42 | 43 | /* 44 | * Shall we use huge pages for any malloc? 45 | */ 46 | #ifndef DPDK_MALLOC 47 | #define DPDK_MALLOC 0 48 | #endif 49 | 50 | /* 51 | * Shall we use huge pages for mallocs of big data structures 52 | */ 53 | #ifndef DPDK_BIG_MALLOC 54 | #define DPDK_BIG_MALLOC 1 55 | #endif 56 | 57 | /* 58 | * Shalll we put triggers backtoback in a buffer or just keep track of their pointers 59 | */ 60 | #ifndef TRIGGERTABLE_INLINE_TRIGGER 61 | #define TRIGGERTABLE_INLINE_TRIGGER 1 62 | #endif 63 | 64 | /* 65 | * How many packets to process in a batch. This affects prefetchig 66 | */ 67 | #ifndef FLATREPORT_PKT_BURST 68 | #define FLATREPORT_PKT_BURST 32 // smaller than 32 69 | #endif 70 | 71 | /* 72 | * Shall we sweep over triggers or sweep over flows 73 | */ 74 | #ifndef TRIGGERTABLE_SWEEP 75 | #define TRIGGERTABLE_SWEEP 1 76 | #endif 77 | 78 | /* 79 | * Shall we break the sweep into multiple steps? 80 | */ 81 | #ifndef MULTISTEP 82 | #define MULTISTEP 1 83 | #endif 84 | 85 | /* 86 | * Shall we prefetch packets 87 | */ 88 | #ifndef PKT_PREFETCH_ENABLE 89 | #define PKT_PREFETCH_ENABLE 1 90 | #endif 91 | 92 | /* 93 | * Shall we prefetch flow table entries 94 | */ 95 | #ifndef HASH_PREFETCH_ENABLE 96 | #define HASH_PREFETCH_ENABLE 1 97 | #endif 98 | 99 | /* 100 | * Shall we use prefetching during the sweep process. Ex. prefetch triggers or flow entries explicitly 101 | */ 102 | #ifndef SWEEP_PREFETCH_ENABLE 103 | #define SWEEP_PREFETCH_ENABLE 1 104 | #endif 105 | 106 | /* 107 | * How many flow entries for each trigger must be batched together to avoid pointer jumping during aggregation of statistics in sweeping 108 | */ 109 | #ifndef TRIGGERFLOW_BATCH 110 | #define TRIGGERFLOW_BATCH 64 111 | #endif 112 | 113 | 114 | #if PKT_PREFETCH_ENABLE 115 | #define PKT_PREFETCH0(p) rte_prefetch0(p) 116 | #define PKT_PREFETCH1(p) rte_prefetch1(p) 117 | #else 118 | #define PKT_PREFETCH0(p) 119 | #define PKT_PREFETCH1(p) 120 | #endif 121 | 122 | #if SWEEP_PREFETCH_ENABLE 123 | #define SWEEP_PREFETCH0(p) rte_prefetch0(p) 124 | #else 125 | #define SWEEP_PREFETCH0(p) 126 | #endif 127 | 128 | 129 | 130 | #define HASH_PREFETCH0(p) rte_prefetch0(p) 131 | 132 | #if DPDK_MALLOC 133 | #define MALLOC(s) rte_malloc(NULL, s, 0) 134 | #define FREE(p) rte_free(p) 135 | #define MALLOC2(s,n) rte_malloc(NULL, s, n) 136 | #else 137 | #define MALLOC(s) malloc(s) 138 | #define FREE(p) free(p) 139 | #define MALLOC2(s,n) malloc(s) 140 | #endif 141 | 142 | #if DPDK_BIG_MALLOC 143 | #define BIGMALLOC(s) rte_malloc(NULL, s, 0) 144 | #define BIGFREE(p) rte_free(p) 145 | #define BIGMALLOC2(s,n) rte_malloc(NULL, s, n) 146 | #else 147 | #define BIGMALLOC(s) malloc(s) 148 | #define BIGFREE(p) free(p) 149 | #define BIGMALLOC2(s,n) malloc(s) //posix_memalign is bad 150 | #endif 151 | 152 | 153 | void * myalign(int size, int align); 154 | bool is_empty2(void *buf2, uint32_t size); 155 | void set_CPU(int cpu); 156 | 157 | /* 158 | * return most significant bit of m. returns 0 for 0 159 | */ 160 | uint32_t gbp(uint32_t m); 161 | uint16_t entry_size_64(uint16_t m); 162 | unsigned long long rdtscl(void); 163 | unsigned int countTrailing0M(uint64_t v); 164 | int log2_32 (uint32_t value); 165 | int log2_64 (uint64_t value); 166 | void shuffle (void * array, size_t n, size_t size); 167 | 168 | extern struct loguser * util_lu; 169 | 170 | #endif /* util.h */ 171 | -------------------------------------------------------------------------------- /receiver/timehist.c: -------------------------------------------------------------------------------- 1 | #include "timehist.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define ONE_BW_NS 8 9 | 10 | uint32_t timehist_bucket_sum_pairfunc(struct timehist_bucket * b1, struct timehist_bucket * b2){ 11 | return b1->size + b2->size; 12 | } 13 | 14 | bool timehist_bucket_paircmp(void * a, void * b){ 15 | return ((struct timehist_bucket *)a)->pair<=((struct timehist_bucket *)b)->pair; 16 | } 17 | 18 | void timehist_bucket_index(void * a, uint16_t index){ 19 | ((struct timehist_bucket *)a)->heap_index = index; 20 | } 21 | 22 | struct timehist * timehist_init(uint16_t size){ 23 | struct timehist * th = malloc(sizeof (struct timehist)); 24 | th->h = heap_init(size, timehist_bucket_paircmp, timehist_bucket_index); 25 | th->buckets = malloc (sizeof(struct timehist_bucket)*(size+1)); //one for m+1 26 | th->ts = 0; 27 | th->pair_func = timehist_bucket_sum_pairfunc; 28 | th->size = size; 29 | th->filled = 0; 30 | th->emptybucket_index = 0; 31 | th->lastbucket_index = 0; 32 | return th; 33 | } 34 | 35 | void timehist_finish(struct timehist * th){ 36 | heap_finish(th->h); 37 | free(th->buckets); 38 | free(th); 39 | } 40 | 41 | void timehist_add(struct timehist * th, uint64_t ts, uint16_t size){ 42 | if (size == 0){ 43 | return; 44 | } 45 | th->filled++;//must be before anything else 46 | 47 | if (th->filled == 1){ 48 | th->ts = ts - size * ONE_BW_NS; 49 | } 50 | 51 | struct timehist_bucket * b_new = &th->buckets[th->emptybucket_index]; 52 | b_new->ts = ts - th->ts; 53 | b_new->size = size; 54 | b_new->pair = 0; 55 | b_new->next = 0x0000FFFF; 56 | b_new->prev = 0x0000FFFF; 57 | b_new->heap_index = 0x0000FFFF; 58 | if (th->filled == 1){ 59 | th->lastbucket_index = th->emptybucket_index; 60 | th->emptybucket_index++; 61 | return; 62 | } 63 | 64 | struct timehist_bucket * b_last = &th->buckets[th->lastbucket_index]; 65 | b_last->pair = th->pair_func(b_last, b_new); 66 | b_last->next = th->emptybucket_index; 67 | b_new->prev = th->lastbucket_index; 68 | if (th->filled <= th->size){ 69 | heap_push(th->h, b_last);//b_new doesn't need to be in heap 70 | th->lastbucket_index = th->emptybucket_index; 71 | th->emptybucket_index++; 72 | }else{//two buckets must merge 73 | struct timehist_bucket * bm1 = (struct timehist_bucket *)heap_push_pop(th->h, b_last); 74 | struct timehist_bucket * bm2 = &th->buckets[bm1->next]; 75 | bm1->size += bm2->size; 76 | bm1->ts = bm2->ts; 77 | uint16_t nextempty = bm1->next; //bm2 address 78 | bm1->next = bm2->next; 79 | if (bm2->next<0x0000FFFF){ //Otherwise, it wasn't in the heap, because the last entry has no pair 80 | struct timehist_bucket * bm3 = &th->buckets[bm2->next]; 81 | bm1->pair = th->pair_func(bm1, bm3); 82 | bm3->prev = bm2->prev; 83 | heap_replace(th->h, bm1, bm2->heap_index);//bm1 will replace bm2 84 | } 85 | if (bm1->prev<0x0000FFFF){ 86 | struct timehist_bucket * bm_1 = &th->buckets[bm1->prev]; 87 | bm_1->pair = th->pair_func(bm_1, bm1); 88 | //bm_1->next = bm2->prev; no need for this 89 | heap_replace(th->h, bm_1, bm_1->heap_index); 90 | } 91 | if (th->emptybucket_index != nextempty){ 92 | th->lastbucket_index = th->emptybucket_index; 93 | th->emptybucket_index = nextempty; 94 | } 95 | 96 | th->filled--;//do it at last 97 | } 98 | } 99 | 100 | void timehist_bucket_print(struct timehist_bucket * b, void * aux){ 101 | printf("ts: %lu, size: %lu, pair %lu, prev: %u, next: %u\n", (long unsigned)b->ts, (long unsigned)b->size, (long unsigned) b->pair, 102 | (unsigned)b->prev, (unsigned)b->next); 103 | } 104 | 105 | void timehist_apply(struct timehist * th, timehist_bucket_apply_func apply_func, void * aux){ 106 | if (th->filled == 0){ 107 | return; 108 | } 109 | struct timehist_bucket * b = &th->buckets[0];//if we pushback bm1, 0 is always there 110 | while (true){ 111 | apply_func(b, aux); 112 | if (b->next<0x0000FFFF){ 113 | b = &th->buckets[b->next]; 114 | }else{ 115 | break; 116 | } 117 | } 118 | } 119 | 120 | int main(int argc, char **argv) { 121 | int i; 122 | int num = 100000; 123 | struct timehist * th = timehist_init(32); 124 | uint64_t ts = 0; 125 | srand(0x1238f2a9); 126 | struct timeval tic, toc, tdiff; 127 | gettimeofday(&tic, NULL); 128 | for (i=0; i>16; 131 | } 132 | gettimeofday(&toc, NULL); 133 | timersub(&toc, &tic, &tdiff); 134 | double f = tdiff.tv_sec*1e6+tdiff.tv_usec; 135 | printf("%f\n", f/num); 136 | 137 | timehist_apply(th, timehist_bucket_print , NULL); 138 | timehist_finish(th); 139 | } 140 | -------------------------------------------------------------------------------- /controller/bitmap.c: -------------------------------------------------------------------------------- 1 | #include "bitmap.h" 2 | #include 3 | #include 4 | #include 5 | #include "util.h" 6 | 7 | #define MASK_1 ((uint64_t)0x0000000000000001) 8 | 9 | uint64_t * getdata(struct bitmap * bm, int i); 10 | 11 | inline uint64_t * getdata(struct bitmap * bm, int i){ 12 | return (&bm->data) + i; 13 | } 14 | 15 | 16 | bool bitmap_set(struct bitmap * bm, uint32_t id){ 17 | if (id >= bm->maxid){ 18 | printf("Too large id %u vs %u\n", id, bm->maxid); 19 | return false; 20 | }else{ 21 | uint64_t mask = MASK_1<<(id & BITMAP_ENTRY_SIZE_MOD); 22 | uint64_t * entry = getdata(bm, id >> BITMAP_ENTRY_SIZE_LOG); 23 | bool out = (*entry) & mask; 24 | if (!out){ 25 | bm->filled++; 26 | } 27 | *entry |= mask; 28 | return out; 29 | } 30 | } 31 | 32 | 33 | bool bitmap_unset(struct bitmap * bm, uint32_t id){ 34 | if (id >= bm->maxid){ 35 | printf("Too large id %u vs %u\n", id, bm->maxid); 36 | }else{ 37 | uint64_t mask = MASK_1<<(id & BITMAP_ENTRY_SIZE_MOD); 38 | uint64_t * entry = getdata(bm, id >> BITMAP_ENTRY_SIZE_LOG); 39 | bool out = (*entry) & mask; 40 | if (out){ 41 | bm->filled--; 42 | } 43 | *entry &= ~mask; 44 | return out; 45 | } 46 | return false; 47 | } 48 | 49 | bool bitmap_get(struct bitmap * bm, uint32_t id){ 50 | if (id > bm->maxid){ 51 | printf("Too large id %u vs %u\n", id, bm->maxid); 52 | return false; 53 | }else{ 54 | return (*getdata(bm, id >> BITMAP_ENTRY_SIZE_LOG)) & (MASK_1<<(id & BITMAP_ENTRY_SIZE_MOD)); 55 | } 56 | } 57 | 58 | void bitmap_print(struct bitmap * bm){ 59 | int max = BITMAP_MAX_ENTRY(bm->maxid); 60 | int i; 61 | for (i = max-1; i >= 0; i--){ 62 | printf("%016llx", (long long unsigned)*getdata(bm, i)); 63 | if (i%64==0){ 64 | printf("\n"); 65 | } 66 | } 67 | printf("\n"); 68 | } 69 | 70 | // start must be multiple of 64 71 | int bitmap_getfirstzero(struct bitmap * bm, uint32_t start, uint32_t* id){ 72 | uint32_t i; 73 | 74 | for (i = (start >> BITMAP_ENTRY_SIZE_LOG); i < BITMAP_MAX_ENTRY(bm->maxid); i++){ 75 | uint64_t * entry = getdata(bm, i); 76 | if (*entry < 0xFFFFFFFFFFFFFFFF){ 77 | *id = (i<maxid; i++){ 91 | if ((*getdata(bm, i)) & mask){ 92 | func(id++, aux); 93 | } 94 | mask <<= 1; 95 | } 96 | } 97 | 98 | struct bitmap_iterator * bitmap_iterator_init(struct bitmap * bm, struct bitmap_iterator * bi){ 99 | bi->bm = bm; 100 | bi->id = 0; 101 | bi->mask = 1; 102 | return bi; 103 | } 104 | 105 | bool bitmap_iterator_next(struct bitmap_iterator * bi, uint32_t * id){ 106 | //skip zero maps 107 | if (bi->mask == 1){ 108 | while (bi->id < bi->bm->maxid && *getdata(bi->bm, bi->id >> BITMAP_ENTRY_SIZE_LOG) == 0){ 109 | bi->id += BITMAP_ENTRY_SIZE; 110 | } 111 | } 112 | while (bi->id < bi->bm->maxid){ 113 | if (*getdata(bi->bm, bi->id >> BITMAP_ENTRY_SIZE_LOG) & bi->mask){ 114 | *id = bi->id; 115 | bi->id++; 116 | bi->mask <<= 1; 117 | if (bi->mask == 0){ 118 | bi->mask = 1; 119 | } 120 | return true; 121 | } 122 | bi->id++; 123 | bi->mask <<= 1; 124 | if (bi->mask == 0){ 125 | bi->mask = 1; 126 | } 127 | } 128 | return false; 129 | } 130 | 131 | uint32_t bitmap_getfilled(struct bitmap * bm){ 132 | return bm->filled; 133 | } 134 | 135 | void bitmap_clear(struct bitmap * bm){ 136 | int max = BITMAP_MAX_ENTRY(bm->maxid); 137 | max *= BITMAP_ENTRY_SIZE / 8; 138 | memset(&bm->data, 0, max); 139 | bm->filled = 0; 140 | } 141 | 142 | void bitmap_setall(struct bitmap * bm){ 143 | int max = BITMAP_MAX_ENTRY(bm->maxid); 144 | max *= BITMAP_ENTRY_SIZE / 8; 145 | memset(&bm->data, 0xff, max); 146 | bm->filled = bm->maxid; 147 | } 148 | 149 | struct bitmap * bitmap_init(uint32_t maxid, uint8_t * buffer){ 150 | int max = BITMAP_MAX_ENTRY(maxid); 151 | struct bitmap * bm; 152 | if (buffer == NULL){ 153 | if (maxid > 1<<14){ 154 | bm = (struct bitmap *) BIGMALLOC2 (sizeof(struct bitmap) + (max - 1) * BITMAP_ENTRY_SIZE/8, 8); 155 | }else{ 156 | bm = (struct bitmap *) MALLOC2 (sizeof(struct bitmap) + (max - 1) * BITMAP_ENTRY_SIZE/8, 8); 157 | } 158 | }else{ 159 | bm = (struct bitmap *) buffer; 160 | } 161 | bm->hasbuffer = buffer != NULL; 162 | bm->maxid = maxid; 163 | bitmap_clear(bm); 164 | return bm; 165 | } 166 | void bitmap_finish(struct bitmap * bm){ 167 | if (!bm->hasbuffer){ 168 | if (bm->maxid > 1<<14){ 169 | BIGFREE(bm); 170 | }else{ 171 | FREE(bm); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /receiver/bitmap.c: -------------------------------------------------------------------------------- 1 | #include "bitmap.h" 2 | #include 3 | #include 4 | #include 5 | #include "util.h" 6 | 7 | #define MASK_1 ((uint64_t)0x0000000000000001) 8 | 9 | uint64_t * getdata(struct bitmap * bm, int i); 10 | 11 | inline uint64_t * getdata(struct bitmap * bm, int i){ 12 | return (&bm->data) + i; 13 | } 14 | 15 | 16 | bool bitmap_set(struct bitmap * bm, uint32_t id){ 17 | if (id >= bm->maxid){ 18 | printf("Too large id %u vs %u\n", id, bm->maxid); 19 | return false; 20 | }else{ 21 | uint64_t mask = MASK_1<<(id & BITMAP_ENTRY_SIZE_MOD); 22 | uint64_t * entry = getdata(bm, id >> BITMAP_ENTRY_SIZE_LOG); 23 | bool out = (*entry) & mask; 24 | if (!out){ 25 | bm->filled++; 26 | } 27 | *entry |= mask; 28 | return out; 29 | } 30 | } 31 | 32 | 33 | bool bitmap_unset(struct bitmap * bm, uint32_t id){ 34 | if (id >= bm->maxid){ 35 | printf("Too large id %u vs %u\n", id, bm->maxid); 36 | }else{ 37 | uint64_t mask = MASK_1<<(id & BITMAP_ENTRY_SIZE_MOD); 38 | uint64_t * entry = getdata(bm, id >> BITMAP_ENTRY_SIZE_LOG); 39 | bool out = (*entry) & mask; 40 | if (out){ 41 | bm->filled--; 42 | } 43 | *entry &= ~mask; 44 | return out; 45 | } 46 | return false; 47 | } 48 | 49 | bool bitmap_get(struct bitmap * bm, uint32_t id){ 50 | if (id > bm->maxid){ 51 | printf("Too large id %u vs %u\n", id, bm->maxid); 52 | return false; 53 | }else{ 54 | return (*getdata(bm, id >> BITMAP_ENTRY_SIZE_LOG)) & (MASK_1<<(id & BITMAP_ENTRY_SIZE_MOD)); 55 | } 56 | } 57 | 58 | void bitmap_print(struct bitmap * bm){ 59 | int max = BITMAP_MAX_ENTRY(bm->maxid); 60 | int i; 61 | for (i = max-1; i >= 0; i--){ 62 | printf("%016llx", (long long unsigned)*getdata(bm, i)); 63 | if (i%64==0){ 64 | printf("\n"); 65 | } 66 | } 67 | printf("\n"); 68 | } 69 | 70 | // start must be multiple of 64 71 | int bitmap_getfirstzero(struct bitmap * bm, uint32_t start, uint32_t* id){ 72 | uint32_t i; 73 | 74 | for (i = (start >> BITMAP_ENTRY_SIZE_LOG); i < BITMAP_MAX_ENTRY(bm->maxid); i++){ 75 | uint64_t * entry = getdata(bm, i); 76 | if (*entry < 0xFFFFFFFFFFFFFFFF){ 77 | *id = (i<maxid; i++){ 91 | if ((*getdata(bm, i)) & mask){ 92 | func(id++, aux); 93 | } 94 | mask <<= 1; 95 | } 96 | } 97 | 98 | struct bitmap_iterator * bitmap_iterator_init(struct bitmap * bm, struct bitmap_iterator * bi){ 99 | bi->bm = bm; 100 | bi->id = 0; 101 | bi->mask = 1; 102 | return bi; 103 | } 104 | 105 | bool bitmap_iterator_next(struct bitmap_iterator * bi, uint32_t * id){ 106 | //skip zero maps 107 | if (bi->mask == 1){ 108 | while (bi->id < bi->bm->maxid && *getdata(bi->bm, bi->id >> BITMAP_ENTRY_SIZE_LOG) == 0){ 109 | bi->id += BITMAP_ENTRY_SIZE; 110 | } 111 | } 112 | while (bi->id < bi->bm->maxid){ 113 | if (*getdata(bi->bm, bi->id >> BITMAP_ENTRY_SIZE_LOG) & bi->mask){ 114 | *id = bi->id; 115 | bi->id++; 116 | bi->mask <<= 1; 117 | if (bi->mask == 0){ 118 | bi->mask = 1; 119 | } 120 | return true; 121 | } 122 | bi->id++; 123 | bi->mask <<= 1; 124 | if (bi->mask == 0){ 125 | bi->mask = 1; 126 | } 127 | } 128 | return false; 129 | } 130 | 131 | uint32_t bitmap_getfilled(struct bitmap * bm){ 132 | return bm->filled; 133 | } 134 | 135 | void bitmap_clear(struct bitmap * bm){ 136 | int max = BITMAP_MAX_ENTRY(bm->maxid); 137 | max *= BITMAP_ENTRY_SIZE / 8; 138 | memset(&bm->data, 0, max); 139 | bm->filled = 0; 140 | } 141 | 142 | void bitmap_setall(struct bitmap * bm){ 143 | int max = BITMAP_MAX_ENTRY(bm->maxid); 144 | max *= BITMAP_ENTRY_SIZE / 8; 145 | memset(&bm->data, 0xff, max); 146 | bm->filled = bm->maxid; 147 | } 148 | 149 | struct bitmap * bitmap_init(uint32_t maxid, uint8_t * buffer){ 150 | int max = BITMAP_MAX_ENTRY(maxid); 151 | struct bitmap * bm; 152 | if (buffer == NULL){ 153 | if (maxid > 1<<14){ 154 | bm = (struct bitmap *) BIGMALLOC2 (sizeof(struct bitmap) + (max - 1) * BITMAP_ENTRY_SIZE/8, 8); 155 | }else{ 156 | bm = (struct bitmap *) MALLOC2 (sizeof(struct bitmap) + (max - 1) * BITMAP_ENTRY_SIZE/8, 8); 157 | } 158 | }else{ 159 | bm = (struct bitmap *) buffer; 160 | } 161 | bm->hasbuffer = buffer != NULL; 162 | bm->maxid = maxid; 163 | bitmap_clear(bm); 164 | return bm; 165 | } 166 | void bitmap_finish(struct bitmap * bm){ 167 | if (!bm->hasbuffer){ 168 | if (bm->maxid > 1<<14){ 169 | BIGFREE(bm); 170 | }else{ 171 | FREE(bm); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /controller/loguser.c: -------------------------------------------------------------------------------- 1 | #include "loguser.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "util.h" 9 | 10 | #define DELAY_MAX_US 500 11 | #define DELAY_INC_US 10 12 | #define DELAY_DIVIDE_US 2 13 | 14 | void * loguser_report(void * data); 15 | 16 | struct logline{ 17 | int tid; 18 | char buffer[LOGLINEBUFFER_LEN]; 19 | }; 20 | 21 | bool loguser_registerthread(struct loguser * lu, const char * filename){ 22 | struct logfile * lf = MALLOC(sizeof(struct logfile)); 23 | lf->next = lu->lfh; 24 | lu->lfh = lf; 25 | snprintf(lf->filename, 100, "%s.txt", filename); 26 | lf->tid = (int) pthread_self(); 27 | lf->fd = fopen(lf->filename, "w+"); 28 | if (lf->fd == NULL){ 29 | fprintf(stderr, "cannot write to log file %s\n", lf->filename); 30 | return false; 31 | } 32 | return true; 33 | } 34 | 35 | /* 36 | * The thread that logs into files 37 | */ 38 | void * loguser_report(void * data){ //for two threads 39 | struct loguser * lu = (struct loguser * ) data; 40 | set_CPU(lu->core); 41 | int n, len; 42 | struct logline * m = NULL; 43 | struct logfile * lf; 44 | while (true){ 45 | n = rte_ring_sc_dequeue(lu->ring, (void **)&m); 46 | if (n >= 0){ 47 | if (m == NULL){continue;} 48 | //find logfile in a linear fashion. TODO: make hashtable 49 | for (lf = lu->lfh; lf->next != NULL && lf->tid != m->tid; lf = lf->next); //last is the default 50 | 51 | len = strnlen(m->buffer, LOGLINEBUFFER_LEN); 52 | fwrite(m->buffer, 1, len, lf->fd); 53 | if (lu->delay > DELAY_INC_US){ //AIMD 54 | lu->delay /= DELAY_DIVIDE_US; 55 | } 56 | rte_mempool_put(lu->mem, m); 57 | }else{ 58 | if (lu->finish){ 59 | for (lf = lu->lfh; lf != NULL; lf = lf->next){ 60 | fflush(lf->fd); //this lets empty ring before finish 61 | } 62 | break; 63 | } 64 | usleep(lu->delay); 65 | if (lu->delay < DELAY_MAX_US){ //AIMD 66 | lu->delay += DELAY_INC_US; 67 | } 68 | 69 | for (lf = lu->lfh; lf != NULL; lf = lf->next){ 70 | fflush(lf->fd); //this lets empty ring before finish 71 | } 72 | } 73 | } 74 | return NULL; 75 | } 76 | 77 | struct loguser * loguser_init(uint32_t size, const char * filename, uint16_t core){ 78 | struct loguser * lu = MALLOC (sizeof(struct loguser)); 79 | struct logfile * lfh = MALLOC(sizeof(struct logfile)); 80 | lu->lfh = lfh; 81 | lfh->next = NULL; 82 | snprintf(lfh->filename, 100, "%s.txt", filename); 83 | lfh->tid = 0; 84 | lfh->fd = fopen(lfh->filename, "w+"); 85 | lu->fullerror = false; 86 | if (lfh->fd == NULL){ 87 | fprintf(stderr, "cannot write to log file %s\n",lfh->filename); 88 | return lu; 89 | } 90 | 91 | lu->ring = rte_ring_create("logring", size, rte_socket_id(), RING_F_SC_DEQ); 92 | if (lu->ring == NULL) { 93 | rte_panic("Cannot create ring for client\n"); 94 | } 95 | lu->mem = rte_mempool_create("log mem", 96 | size, 97 | sizeof(struct logline), 98 | 32, 99 | 0, 100 | NULL, NULL, 101 | NULL, NULL, 102 | rte_socket_id(), 0); 103 | 104 | lu->delay = DELAY_MAX_US; 105 | lu->core = core; 106 | lu->finish = false; 107 | pthread_create(&lu->pth, NULL, loguser_report, lu); 108 | return lu; 109 | } 110 | 111 | void loguser_finish(struct loguser * lu){ 112 | lu->finish = true; 113 | pthread_join(lu->pth, NULL); 114 | struct logfile * lf2; 115 | for (; lu->lfh != NULL; lu->lfh = lf2){ 116 | lf2 = lu->lfh->next; 117 | fclose (lu->lfh->fd); 118 | free(lu->lfh); 119 | } 120 | //rte_mempool_finish 121 | rte_ring_free(lu->ring); 122 | FREE(lu); 123 | } 124 | 125 | void loguser_add(struct loguser * lu, const char * format, ...){ 126 | struct logline * m; 127 | va_list argptr; 128 | va_start(argptr, format); 129 | int ret0 = rte_mempool_get(lu->mem, (void **) &m); 130 | if (ret0 != 0 ){ 131 | char buf [LOGLINEBUFFER_LEN]; 132 | vsnprintf(buf, LOGLINEBUFFER_LEN, format, argptr); 133 | va_end(argptr); 134 | fprintf(stderr, "loguser cannot get memory for a message: %s\n", buf); 135 | return; 136 | } 137 | vsnprintf(m->buffer, LOGLINEBUFFER_LEN, format, argptr); 138 | va_end(argptr); 139 | m->tid = (int)pthread_self(); 140 | int ret1 = rte_ring_enqueue(lu->ring, m); 141 | if (ret1 != 0){ 142 | if (!lu->fullerror){ 143 | lu->fullerror = true; 144 | fprintf(stderr, "loguser ring is full\n"); 145 | } 146 | rte_mempool_put(lu->mem, m); 147 | return; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /receiver/loguser.c: -------------------------------------------------------------------------------- 1 | #include "loguser.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "util.h" 9 | 10 | #define DELAY_MAX_US 500 11 | #define DELAY_INC_US 10 12 | #define DELAY_DIVIDE_US 2 13 | 14 | void * loguser_report(void * data); 15 | 16 | struct logline{ 17 | int tid; 18 | char buffer[LOGLINEBUFFER_LEN]; 19 | }; 20 | 21 | bool loguser_registerthread(struct loguser * lu, const char * filename){ 22 | struct logfile * lf = MALLOC(sizeof(struct logfile)); 23 | lf->next = lu->lfh; 24 | lu->lfh = lf; 25 | snprintf(lf->filename, 100, "%s.txt", filename); 26 | lf->tid = (int) pthread_self(); 27 | lf->fd = fopen(lf->filename, "w+"); 28 | if (lf->fd == NULL){ 29 | fprintf(stderr, "cannot write to log file %s\n", lf->filename); 30 | return false; 31 | } 32 | return true; 33 | } 34 | 35 | /* 36 | * The thread that logs into files 37 | */ 38 | void * loguser_report(void * data){ //for two threads 39 | struct loguser * lu = (struct loguser * ) data; 40 | set_CPU(lu->core); 41 | int n, len; 42 | struct logline * m = NULL; 43 | struct logfile * lf; 44 | while (true){ 45 | n = rte_ring_sc_dequeue(lu->ring, (void **)&m); 46 | if (n >= 0){ 47 | if (m == NULL){continue;} 48 | //find logfile in a linear fashion. TODO: make hashtable 49 | for (lf = lu->lfh; lf->next != NULL && lf->tid != m->tid; lf = lf->next); //last is the default 50 | 51 | len = strnlen(m->buffer, LOGLINEBUFFER_LEN); 52 | fwrite(m->buffer, 1, len, lf->fd); 53 | if (lu->delay > DELAY_INC_US){ //AIMD 54 | lu->delay /= DELAY_DIVIDE_US; 55 | } 56 | rte_mempool_put(lu->mem, m); 57 | }else{ 58 | if (lu->finish){ 59 | for (lf = lu->lfh; lf != NULL; lf = lf->next){ 60 | fflush(lf->fd); //this lets empty ring before finish 61 | } 62 | break; 63 | } 64 | usleep(lu->delay); 65 | if (lu->delay < DELAY_MAX_US){ //AIMD 66 | lu->delay += DELAY_INC_US; 67 | } 68 | 69 | for (lf = lu->lfh; lf != NULL; lf = lf->next){ 70 | fflush(lf->fd); //this lets empty ring before finish 71 | } 72 | } 73 | } 74 | return NULL; 75 | } 76 | 77 | struct loguser * loguser_init(uint32_t size, const char * filename, uint16_t core){ 78 | struct loguser * lu = MALLOC (sizeof(struct loguser)); 79 | struct logfile * lfh = MALLOC(sizeof(struct logfile)); 80 | lu->lfh = lfh; 81 | lfh->next = NULL; 82 | snprintf(lfh->filename, 100, "%s.txt", filename); 83 | lfh->tid = 0; 84 | lfh->fd = fopen(lfh->filename, "w+"); 85 | lu->fullerror = false; 86 | if (lfh->fd == NULL){ 87 | fprintf(stderr, "cannot write to log file %s\n",lfh->filename); 88 | return lu; 89 | } 90 | 91 | lu->ring = rte_ring_create("logring", size, rte_socket_id(), RING_F_SC_DEQ); 92 | if (lu->ring == NULL) { 93 | rte_panic("Cannot create ring for client\n"); 94 | } 95 | lu->mem = rte_mempool_create("log mem", 96 | size, 97 | sizeof(struct logline), 98 | 32, 99 | 0, 100 | NULL, NULL, 101 | NULL, NULL, 102 | rte_socket_id(), 0); 103 | 104 | lu->delay = DELAY_MAX_US; 105 | lu->core = core; 106 | lu->finish = false; 107 | pthread_create(&lu->pth, NULL, loguser_report, lu); 108 | return lu; 109 | } 110 | 111 | void loguser_finish(struct loguser * lu){ 112 | lu->finish = true; 113 | pthread_join(lu->pth, NULL); 114 | struct logfile * lf2; 115 | for (; lu->lfh != NULL; lu->lfh = lf2){ 116 | lf2 = lu->lfh->next; 117 | fclose (lu->lfh->fd); 118 | free(lu->lfh); 119 | } 120 | //rte_mempool_finish 121 | rte_ring_free(lu->ring); 122 | FREE(lu); 123 | } 124 | 125 | void loguser_add(struct loguser * lu, const char * format, ...){ 126 | struct logline * m; 127 | va_list argptr; 128 | va_start(argptr, format); 129 | int ret0 = rte_mempool_get(lu->mem, (void **) &m); 130 | if (ret0 != 0 ){ 131 | char buf [LOGLINEBUFFER_LEN]; 132 | vsnprintf(buf, LOGLINEBUFFER_LEN, format, argptr); 133 | va_end(argptr); 134 | fprintf(stderr, "loguser cannot get memory for a message: %s\n", buf); 135 | return; 136 | } 137 | vsnprintf(m->buffer, LOGLINEBUFFER_LEN, format, argptr); 138 | va_end(argptr); 139 | m->tid = (int)pthread_self(); 140 | int ret1 = rte_ring_enqueue(lu->ring, m); 141 | if (ret1 != 0){ 142 | if (!lu->fullerror){ 143 | lu->fullerror = true; 144 | fprintf(stderr, "loguser ring is full\n"); 145 | } 146 | rte_mempool_put(lu->mem, m); 147 | return; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /receiver/util.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include //cpu_set_t , CPU_SET 3 | #include "util.h" 4 | #include 5 | #include 6 | #include "stdbool.h" 7 | 8 | struct loguser * util_lu = NULL; 9 | 10 | // from http://stackoverflow.com/questions/1493936/faster-approach-to-checking-for-an-all-zero-buffer-in-c 11 | inline bool is_empty2(void *buf2, uint32_t size) 12 | { 13 | char * buf = (char *) buf2; 14 | return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1); 15 | } 16 | 17 | //from http://stackoverflow.com/questions/21413565/create-a-mask-that-marks-the-most-significant-set-bit-using-only-bitwise-operat 18 | uint32_t gbp(uint32_t m) { 19 | // return most significant bit of m 20 | //uint32_t m; 21 | //m = n; 22 | m = m | m >> 1; 23 | m = m | m >> 2; 24 | m = m | m >> 4; 25 | m = m | m >> 8; 26 | m = m | m >> 16; 27 | m = m & (~m >> 1); 28 | return m; 29 | } 30 | 31 | 32 | // from http://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers 33 | 34 | int log2_32 (uint32_t value){ 35 | static const int tab32[32] = { 36 | 0, 9, 1, 10, 13, 21, 2, 29, 37 | 11, 14, 16, 18, 22, 25, 3, 30, 38 | 8, 12, 20, 28, 15, 17, 24, 7, 39 | 19, 27, 23, 6, 26, 5, 4, 31}; 40 | value |= value >> 1; 41 | value |= value >> 2; 42 | value |= value >> 4; 43 | value |= value >> 8; 44 | value |= value >> 16; 45 | return tab32[(uint32_t)(value*0x07C4ACDD) >> 27]; 46 | } 47 | 48 | int log2_64(uint64_t n){ 49 | static const int table[64] = { 50 | 0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61, 51 | 51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62, 52 | 57, 46, 52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56, 53 | 45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5, 63 }; 54 | 55 | n |= n >> 1; 56 | n |= n >> 2; 57 | n |= n >> 4; 58 | n |= n >> 8; 59 | n |= n >> 16; 60 | n |= n >> 32; 61 | 62 | return table[(n * 0x03f6eaf2cd271461) >> 58]; 63 | } 64 | 65 | //return 0 for both 0 and 1 66 | //find first bit that equals to 1 67 | unsigned int countTrailing0M(uint64_t v) { 68 | static const char multiplyDeBruijnBitPosition[64] = { 69 | 0, 1, 2, 56, 3, 32, 57, 46, 29, 4, 20, 33, 7, 58, 11, 47, 70 | 62, 30, 18, 5, 16, 21, 34, 23, 53, 8, 59, 36, 25, 12, 48, 39, 71 | 63, 55, 31, 45, 28, 19, 6, 10, 61, 17, 15, 22, 52, 35, 24, 38, 72 | 54, 44, 27, 9, 60, 14, 51, 37, 43, 26, 13, 50, 42, 49, 41, 40 73 | }; 74 | return multiplyDeBruijnBitPosition[((uint64_t)((v & -v) * 0x26752B916FC7B0DULL)) >> 58]; 75 | } 76 | 77 | unsigned long long rdtscl(void){ 78 | unsigned long long int lo, hi; 79 | __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 80 | return lo|( hi<<32 ); 81 | } 82 | 83 | uint16_t entry_size_64(uint16_t m){ 84 | uint32_t entry_size = gbp(m); 85 | if (entry_size64){ 89 | entry_size+=64; 90 | } 91 | return entry_size; 92 | } 93 | 94 | void set_CPU(int cpu ){ 95 | cpu_set_t cpuset; 96 | 97 | //the CPU we whant to use 98 | 99 | CPU_ZERO(&cpuset); //clears the cpuset 100 | CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset 101 | 102 | 103 | /* 104 | * cpu affinity for the calling thread 105 | * first parameter is the pid, 0 = calling thread 106 | * second parameter is the size of your cpuset 107 | * third param is the cpuset in which your thread will be 108 | * placed. Each bit represents a CPU 109 | */ 110 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 111 | } 112 | 113 | void * myalign(int size, int align){ 114 | void * ptr; 115 | if (posix_memalign(&ptr, align, size)){ 116 | fprintf(stderr, "util:cannot allocate memory\n"); 117 | return NULL; 118 | } 119 | return ptr; 120 | } 121 | 122 | #define NELEMS(x) (sizeof(x) / sizeof(x[0])) 123 | //from http://stackoverflow.com/questions/6127503/shuffle-array-in-c 124 | 125 | /* arrange the N elements of ARRAY in random order. 126 | * Only effective if N is much smaller than RAND_MAX; 127 | * if this may not be the case, use a better random 128 | * number generator. */ 129 | void shuffle(void *array, size_t n, size_t size) { 130 | char tmp[size]; 131 | char *arr = array; 132 | size_t stride = size * sizeof(char); 133 | srand(0x23a82bc0); 134 | if (n > 1) { 135 | size_t i; 136 | for (i = 0; i < n - 1; ++i) { 137 | size_t rnd = (size_t) rand(); 138 | size_t j = i + rnd / (RAND_MAX / (n - i) + 1); 139 | 140 | memcpy(tmp, arr + j * stride, size); 141 | memcpy(arr + j * stride, arr + i * stride, size); 142 | memcpy(arr + i * stride, tmp, size); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /controller/util.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include //cpu_set_t , CPU_SET 3 | #include "util.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "stdbool.h" 9 | 10 | struct loguser * util_lu = NULL; 11 | 12 | // from http://stackoverflow.com/questions/1493936/faster-approach-to-checking-for-an-all-zero-buffer-in-c 13 | inline bool is_empty2(void *buf2, uint32_t size){ 14 | char * buf = (char *) buf2; 15 | return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1); 16 | } 17 | 18 | //from http://stackoverflow.com/questions/21413565/create-a-mask-that-marks-the-most-significant-set-bit-using-only-bitwise-operat 19 | uint32_t gbp(uint32_t m) { 20 | // return most significant bit of n 21 | //uint32_t m; 22 | //m = n; 23 | m = m | m >> 1; 24 | m = m | m >> 2; 25 | m = m | m >> 4; 26 | m = m | m >> 8; 27 | m = m | m >> 16; 28 | m = m & (~m >> 1); 29 | return m; 30 | } 31 | 32 | 33 | 34 | // from http://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers 35 | 36 | int log2_32 (uint32_t value){ 37 | static const int tab32[32] = { 38 | 0, 9, 1, 10, 13, 21, 2, 29, 39 | 11, 14, 16, 18, 22, 25, 3, 30, 40 | 8, 12, 20, 28, 15, 17, 24, 7, 41 | 19, 27, 23, 6, 26, 5, 4, 31}; 42 | value |= value >> 1; 43 | value |= value >> 2; 44 | value |= value >> 4; 45 | value |= value >> 8; 46 | value |= value >> 16; 47 | return tab32[(uint32_t)(value*0x07C4ACDD) >> 27]; 48 | } 49 | 50 | int log2_64(uint64_t n){ 51 | static const int table[64] = { 52 | 0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61, 53 | 51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62, 54 | 57, 46, 52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56, 55 | 45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5, 63 }; 56 | 57 | n |= n >> 1; 58 | n |= n >> 2; 59 | n |= n >> 4; 60 | n |= n >> 8; 61 | n |= n >> 16; 62 | n |= n >> 32; 63 | 64 | return table[(n * 0x03f6eaf2cd271461) >> 58]; 65 | } 66 | 67 | //return 0 for both 0 and 1 68 | //find first bit that equals to 1 69 | unsigned int countTrailing0M(uint64_t v) { 70 | static const char multiplyDeBruijnBitPosition[64] = { 71 | 0, 1, 2, 56, 3, 32, 57, 46, 29, 4, 20, 33, 7, 58, 11, 47, 72 | 62, 30, 18, 5, 16, 21, 34, 23, 53, 8, 59, 36, 25, 12, 48, 39, 73 | 63, 55, 31, 45, 28, 19, 6, 10, 61, 17, 15, 22, 52, 35, 24, 38, 74 | 54, 44, 27, 9, 60, 14, 51, 37, 43, 26, 13, 50, 42, 49, 41, 40 75 | }; 76 | return multiplyDeBruijnBitPosition[((uint64_t)((v & -v) * 0x26752B916FC7B0DULL)) >> 58]; 77 | } 78 | 79 | /*unsigned long long rdtscl(void){ 80 | unsigned long long int lo, hi; 81 | __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 82 | return lo|( hi<<32 ); 83 | }*/ 84 | 85 | uint16_t entry_size_64(uint16_t m){ 86 | uint32_t entry_size = gbp(m); 87 | if (entry_size64){ 91 | entry_size+=64; 92 | } 93 | return entry_size; 94 | } 95 | 96 | void set_CPU(int cpu ){ 97 | cpu_set_t cpuset; 98 | 99 | //the CPU we whant to use 100 | 101 | CPU_ZERO(&cpuset); //clears the cpuset 102 | CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset 103 | 104 | 105 | /* 106 | * cpu affinity for the calling thread 107 | * first parameter is the pid, 0 = calling thread 108 | * second parameter is the size of your cpuset 109 | * third param is the cpuset in which your thread will be 110 | * placed. Each bit represents a CPU 111 | */ 112 | sched_setaffinity(0, sizeof(cpuset), &cpuset); 113 | } 114 | 115 | void * myalign(int size, int align){ 116 | void * ptr; 117 | if (posix_memalign(&ptr, align, size)){ 118 | fprintf(stderr, "util:cannot allocate memory\n"); 119 | return NULL; 120 | } 121 | return ptr; 122 | } 123 | 124 | #define NELEMS(x) (sizeof(x) / sizeof(x[0])) 125 | //from http://stackoverflow.com/questions/6127503/shuffle-array-in-c 126 | 127 | /* arrange the N elements of ARRAY in random order. 128 | * Only effective if N is much smaller than RAND_MAX; 129 | * if this may not be the case, use a better random 130 | * number generator. */ 131 | void shuffle(void *array, size_t n, size_t size) { 132 | char tmp[size]; 133 | char *arr = array; 134 | size_t stride = size * sizeof(char); 135 | srand(0x23a82bc0); 136 | if (n > 1) { 137 | size_t i; 138 | for (i = 0; i < n - 1; ++i) { 139 | size_t rnd = (size_t) rand(); 140 | size_t j = i + rnd / (RAND_MAX / (n - i) + 1); 141 | 142 | memcpy(tmp, arr + j * stride, size); 143 | memcpy(arr + j * stride, arr + i * stride, size); 144 | memcpy(arr + i * stride, tmp, size); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /experiments/congestion_usecase/README.md: -------------------------------------------------------------------------------- 1 | This is the guide for replicating the result for the congestion root cause detection usecase in the paper. 2 | We use two machines as traffic generators, called A and B, and one as receiver and controller, called C. Running both the receiver and the controller at the same server allows us to avoid time synchronization error for the diagrams. 3 | The scenario is as follows: C installs the Congestion detection triggers at A and B. A and B will send TCP traffic to C. A also sends UDP traffic after a few seconds. As soon as the UDP traffic starts, A and B see congestion and inform the controller at C. The controller installs another event at C to detect the UDP traffic reactively. 4 | This is called the reactive scenario becasue the controller waits for the congestion event from A and B to install the third event. We also test it a proactive scenario that the controller installs the third event, to detect heavy UDP, from the beginning. We run both cases in one usecase because we need to compare the latency of reactive and proactive detection in one diagram. 5 | 6 | - Use htb to limit the rate at C 7 | - sudo modprobe ifb 8 | - sudo modprobe act_mirred 9 | - ext_ingress=ifb0 10 | - sudo ifconfig $ext_ingress up 11 | - sudo tc qdisc add dev $ext_ingress root handle 1: htb default 1 12 | - sudo tc class add dev $ext_ingress parent 1: classid 1:1 htb rate 100mbit 13 | - At receiver/basicfwd.c 14 | - set the USEKNI option to 1. 15 | - Uncomment the following lines in receiver/flatreport.c, in the checkflow method. This is to print the time for the first time the receiver sees a flow. We will explain it later, when we draw the diagram. 16 | - char buf[100]; 17 | - flow_inlineprint2(&pkt->f, buf); 18 | - LOG("match %s %"PRIu64"\n", buf, rte_rdtsc()); 19 | - Compile. You should use this code on all the three servers. 20 | - Start the controller: sudo -E build/tcpserver -c 0x5555 -n 4 --file-prefix=controller_ -m 128 -- -s 2 -l proudp -e 1 -u 1 21 | - I assume the IP of the controller at C is 192.168.0.1 22 | - Run the receiver code at the three servers: 23 | - A: sudo -E build/basicfwd -c 0xaaaa -n 4 -- -t 0 -p 0 -P 32 -n 297610000 -d 0.000005 -c 192.168.0.1 -l proudp 24 | - B: sudo -E build/basicfwd -c 0xaaaa -n 4 -- -t 0 -p 0 -P 32 -n 297610000 -d 0.000005 -c 192.168.0.1 -l proudp 25 | - C: sudo -E build/basicfwd -c 0xaaaa -n 4 --file-prefix=receiver_ -m 128 -- -t 0 -p 0 -P 32 -n 297610000 -d 0.000005 -c 192.168.0.1 -l proudp 26 | - Forward the traffic received at C on the KNI interface to the rate limiter: sudo ifconfig vEth0 192.168.1.3/24; sleep 5; ext=vEth0; ext_ingress=ifb0; sudo tc qdisc add dev $ext handle ffff: ingress; sudo tc filter add dev $ext parent ffff: protocol all u32 match u32 0 0 action mirred egress redirect dev $ext_ingress 27 | - Run iper at the receiver (C): iperf -s -p 2500 & iperf -s -u -p 2501 & 28 | - Run tcp dump at the receiver (C): sudo tcpdump -i vEth0 -w proudp.dump 29 | - Run Iperf at the centers for TCP and UDP traffic. Try to run these two commands at the same time: 30 | - A: sudo ifconfig vEth0 192.168.1.1/24; sleep 5; iperf -c 192.168.1.3 -t 20 -p 2500 & sleep 15; iperf -c 192.168.1.3 -b 100m -n 512k -p 2501 31 | - B: sudo ifconfig vEth0 192.168.1.2/24; sleep 5; iperf -c 192.168.1.3 -t 20 -p 2500 32 | - Wait about a minute until the experiment finishes. Then stop the tcpdump at C 33 | 34 | Now we gather the logs and convert the tcpdump trace. 35 | - At machine C, assuming that the IP of A and B are 192.168.0.2 and 192.168.0.3, run the following in the controller folder. Make sure you set the user and the receiver folder right in the runandgather.sh file 36 | - copy experiments/netwide_usecase/logprocess.sh into the receiveer folder on all servers 37 | - fname=proudp 38 | - ./logprocess.sh ${fname}.txt > ${fname}_c.log 39 | - ./runandgather.sh 192.168.0.2 ./logprocess.sh ${fname}_0.txt ${fname}_1.log; 40 | - ./runandgather.sh 192.168.0.3 ./logprocess.sh ${fname}_0.txt ${fname}_0.log; 41 | - ./runandgather.sh 192.168.0.1 ./logprocess.sh ${fname}_0.txt ${fname}_2.log; 42 | - Now we use tshark to convert the tcpdump file and get the throughput data from each connection. 43 | - Install wireshark on the controller 44 | - tshark -T fields -n -r udp/${fname}.dump -E separator=, -e frame.time_relative -e ip.src -e frame.len -e ip.proto > ${fname}_trace.txt 45 | - grep 192.168.1 ${fname}_trace.txt | sed -e 's/192.168.1.1/1/g' -e 's/192.168.1.2/2/g' -e 's/192.168.1.3/3/g' > ${fname}_trace2.txt 46 | 47 | - To draw the diagram in the paper you need the four log files generated above: proudp_c.log, proudp_0.log, proudp_1.log, proudp_2.log and the throughput data proudp_trace2.txt 48 | - You also need a kind of base for synchronizing the log files and the throughput data from tcpdump. For this we use the time that the receiver (C) got the udp data. 49 | - Remember we made the change receiver folder to print the time, the TPM sees a flow for the first time. Now we get that for the UDP flow. Run the following at the receiver folder at machine C 50 | - grep 'match .*,192.168.1.3:2501' proudp_0.txt 51 | - Now open the udpthroughputdiagram.m file in this folder. Copy the timestamp from the above command to logudp variable. 52 | - Run udpthroughputdiagram.m matlab script. You may edit the file to pass the four log files and the trace file. 53 | -------------------------------------------------------------------------------- /receiver/flatreport.h: -------------------------------------------------------------------------------- 1 | #ifndef FLATREPORT_H 2 | #define FLATREPORT_H 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include "hashmap.h" 8 | #include "triggertable2.h" 9 | #include "flowentry.h" 10 | #include "ddostable2.h" 11 | #include "client.h" 12 | 13 | #define ANYMATCH_MAX 32 14 | 15 | struct flatreport_pkt{ 16 | struct flow f; 17 | uint32_t ts; 18 | uint32_t seq; 19 | uint32_t ack; 20 | uint32_t hash; 21 | uint16_t length; 22 | bool sameaslast; 23 | }; 24 | 25 | struct flatreport{ 26 | //per packet 27 | uint32_t stat_pktnum; 28 | uint32_t step; //epoch number 29 | uint8_t pkt_q; //how many packets are in the queue for cache prefetching 30 | bool lastpktisddos; 31 | struct ddostable2 * dt; 32 | struct flowentry * last_flowentry; 33 | struct hashmap * ft1; 34 | struct summary_table * st; 35 | uint64_t epoch_ts; //the base timestamp for whole packets in a batch 36 | struct flatreport_pkt pkts [FLATREPORT_PKT_BURST]; 37 | //per match 38 | struct summary * pktnum_summary; //the summary that keeps track of # packets per flow 39 | struct triggertable * tt; 40 | uint64_t stat_matchdelay; 41 | uint32_t stat_flownum; 42 | uint8_t anymatchfilternum; 43 | struct flow anymatchfilter[ANYMATCH_MAX]; 44 | struct flow anymatchfiltermask[ANYMATCH_MAX]; 45 | ////////////////////////////////sweep 46 | bool sweepfinished; 47 | bool sweep_removedentry; //if last sweep step over flowtable, removed an entry 48 | uint32_t ticksperentrysweep; //if we sweep flowtable, how long it took to sweep each entry in average 49 | uint32_t minsweepticks; 50 | struct hashmap_iterator sweep_iterator; 51 | //rare 52 | // report 53 | struct client * c; 54 | //init 55 | struct lossfinder * lf; 56 | 57 | }; 58 | 59 | /* 60 | * prefetches the corresponding entry in the flow table into cache 61 | */ 62 | void flatreport_readpacket_prefetch(struct flatreport * fr, struct flatreport_pkt * pkt); 63 | 64 | /* 65 | * processes a batch of packets same as flatreport_process 66 | */ 67 | void flatreport_batchprocess(struct flatreport * fr); 68 | void flatreport_process(struct flatreport * fr, struct flatreport_pkt * pkt); 69 | 70 | /* 71 | * Start the periodic phase 72 | */ 73 | void flatreport_startsweep(struct flatreport * fr); 74 | 75 | /* 76 | * Run a step for the periodic step 77 | */ 78 | void flatreport_sweep(struct flatreport * fr, uint64_t sweeptime, uint64_t start); 79 | 80 | /* 81 | * Are we done with the periodic phase? 82 | */ 83 | bool flatreport_issweepfinished(struct flatreport * fr); 84 | 85 | /* 86 | * The default function to add a set of triggers at the server without the controller 87 | */ 88 | void flatreport_addtriggers(struct flatreport * fr, uint16_t trigger_num, uint16_t trigger_perpkt, uint16_t patterns, struct triggertype ** types, int types_num); 89 | 90 | /* 91 | * Add the default types 92 | */ 93 | void flatreport_addtypes(struct flatreport * fr, struct triggertype ** types, int num); 94 | 95 | /* 96 | * Get the flow entry in the flow table that matches the flow or return null 97 | */ 98 | struct flowentry * flatreport_getflowentry(struct flatreport * fr, struct flow * f); 99 | void flatreport_setminsweepticks(struct flatreport * fr, uint64_t minsweepticks); 100 | 101 | /* 102 | * Remove the entry from the flow table and reset its memory 103 | */ 104 | bool flatreport_flowentry_finish(void * data, void * aux); 105 | 106 | /* 107 | * Send trigger satisfaction for a trigger right now 108 | */ 109 | void flatreport_report(struct flatreport * fr, struct trigger * t); 110 | 111 | /* 112 | * Find all flow table entries that match a trigger! 113 | */ 114 | void flatreport_matchforatrigger(struct flatreport * fr, struct trigger * t); 115 | 116 | /* 117 | * Just the naive sweep assuming that trigger stats are updated (for packet history strawman) 118 | */ 119 | void flatreport_naivesweep(struct flatreport * fr); 120 | 121 | /* 122 | * process packet history as a strawman 123 | */ 124 | void flatreport_historyprocess(struct flatreport * fr); 125 | 126 | struct summary_table * flatreport_getsummarytable(struct flatreport * fr); 127 | 128 | void flatreport_profilematching(struct flatreport * fr); 129 | 130 | // a bunch of different ways to define triggers (use to profile matching) 131 | void flatreport_makenotmatchingtriggers(struct flatreport * fr, uint32_t triggernum, uint32_t patterns, struct triggertype * type); 132 | void flatreport_makeallpatternsmatchingtriggers(struct flatreport * fr, uint32_t triggernum, uint32_t patterns, struct triggertype * type); 133 | void flatreport_makeperpktmatchingtriggers(struct flatreport * fr, uint32_t triggernum, uint32_t patterns, struct triggertype * type); 134 | void flatreport_makeperpktpatterntriggers(struct flatreport * fr, uint32_t triggernum, uint32_t patterns, struct triggertype * type); 135 | void flatreport_makeallmatchingtriggers(struct flatreport * fr, uint32_t triggernum, struct triggertype * type); 136 | 137 | /* 138 | * Client c can be null 139 | */ 140 | struct flatreport * flatreport_init(struct ddostable2 * dt, struct client * c); 141 | void flatreport_finish(struct flatreport * fr); 142 | 143 | #endif /* flatreport.h */ 144 | -------------------------------------------------------------------------------- /controller/eventhandler.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENTHANDLER_H 2 | #define EVENTHANDLER_H 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include "flow.h" 8 | #include "stdbool.h" 9 | #include "hashmap.h" 10 | 11 | #define MAX_SERVERS 4 12 | #define MAX_EVENTHISTORY 4 13 | #define EPOCH_NS 10000000 14 | 15 | 16 | struct serverdata; 17 | struct usecase; 18 | struct eventhandler; 19 | 20 | enum dc_param_type{ 21 | dcpt_num, 22 | dcpt_pointer, 23 | }; 24 | 25 | //carry a number or a pointer as parameter to a dc function 26 | struct dc_param{ 27 | union{ 28 | uint64_t num; 29 | void * pointer; 30 | }; 31 | enum dc_param_type type; 32 | }; 33 | 34 | typedef void (*dc_func)(struct eventhandler * eh, struct dc_param * param); 35 | 36 | /* 37 | * The data structure to represent a delayed command. 38 | * The command action is specified by its type. The general one dtc_func can run any function 39 | * with a param. A simple improvement could be to remove the type and just use the function. 40 | */ 41 | struct delayedcommand{ 42 | uint64_t timeus; 43 | void * next; 44 | dc_func func; 45 | struct dc_param param; 46 | }; 47 | 48 | 49 | struct trigger{ 50 | struct serverdata * server; // unique among triggers of an event 51 | hashmap_elem elem; //not used 52 | uint32_t threshold; //triggers inside an event can have different thresholds 53 | }; 54 | 55 | struct eventhistory; 56 | 57 | struct event{ 58 | hashmap_elem elem; 59 | struct flow f; 60 | struct flow mask; 61 | struct flow fgmask; 62 | uint32_t id; //unique among events 63 | uint32_t threshold; 64 | struct hashmap * eventhistory_map; 65 | // struct eventhistory * eventhistory_head; // a link list of the event occurances 66 | struct trigger triggers [MAX_SERVERS]; //keep a trigger position for each server. it is filled if the server ponter is not null. A simple & fast implementation just as a prototype, it could be a hashmap in production 67 | pthread_rwlock_t lock; // The lock is used for accessing the eventhistory linked list 68 | uint32_t flowgranularity; //check flow.c 69 | uint16_t timeinterval; 70 | uint8_t type; 71 | }; 72 | 73 | struct triggerhistory{ 74 | uint32_t value; 75 | bool valuereceived; 76 | }; 77 | 78 | struct eventhistory{ 79 | uint32_t time; 80 | struct eventhistory * next; 81 | struct eventhistory * prev; 82 | struct trigger * inittrigger; // which triggeer was the first one that made us create this event history 83 | struct triggerhistory triggersmap [MAX_SERVERS]; //a triggerhisotry per server (as a prototype) 84 | }; 85 | 86 | struct eventhistorychain{ 87 | hashmap_elem elem; //only first in the chain should need this (chain is not long anyway) 88 | struct flow f; 89 | struct event * e; 90 | struct eventhistory es; 91 | }; 92 | 93 | struct eventhandler{ 94 | struct hashmap * eventsmap; 95 | struct timespec inittime; // the initiation time of the controller. All epochs at the controller must be calculated based ont this initiation time 96 | pthread_mutex_t global_mutex; //To coontrol the access to eventsmapping and delayed commands 97 | struct serverdata * servers[MAX_SERVERS]; //An array of servers just for prototype. An entry could be null if the server with that ID is not yet contacted the controller. 98 | struct usecase * u; 99 | struct delayedcommand * dc; //a sorted linked ist of delayed commands 100 | pthread_t dc_pth; // just runs delayed commands 101 | sem_t dc_sem; // to wake up the delay command thread 102 | uint16_t events_num; 103 | bool dc_finish; //tell the delaycommand thread to stop 104 | }; 105 | 106 | struct delayedcommand * delayedcommand_init(uint64_t timeus); 107 | void delayedcommand_finish(struct delayedcommand * dc); 108 | 109 | struct eventhandler * eventhandler_init(struct usecase * u); 110 | void eventhandler_finish(struct eventhandler * eh); 111 | 112 | void eventhandler_delevent(struct eventhandler * eh, struct event * e); 113 | 114 | /* 115 | * Get a new event 116 | */ 117 | struct event * eventhandler_getevent(struct eventhandler * eh); 118 | 119 | /* 120 | * The server said if it could/coundn't add the trigger. What should the event do? 121 | */ 122 | void eventhandler_addtrigger_return(struct eventhandler * eh, uint16_t eventid, bool success, struct serverdata *server, uint32_t time); 123 | 124 | /* 125 | * Notify the receipt of a trigger satisfacction or poll reply from a server 126 | */ 127 | void eventhandler_notify(struct eventhandler * eh, uint16_t eventid, struct serverdata * server, uint32_t time, char * buf, bool satisfaction_or_query, uint16_t code, struct flow * f); 128 | 129 | /* 130 | * Get epoch number 131 | */ 132 | uint32_t eventhandler_gettime(struct eventhandler * eh); 133 | 134 | /* 135 | * Get time from the eventhandle init time in nanosecond 136 | */ 137 | uint64_t eventhandler_gettime_(struct eventhandler *eh); 138 | 139 | void eventhandler_addserver(struct eventhandler *eh, struct serverdata *server); 140 | void eventhandler_removeserver(struct eventhandler *eh, struct serverdata * server); 141 | 142 | /* 143 | * Get number of active servers 144 | */ 145 | uint16_t eventhandler_activeservers(struct eventhandler *eh); 146 | 147 | /* 148 | * Add a delayed command 149 | */ 150 | void eventhandler_adddc(struct eventhandler * eh, struct delayedcommand * dc2); 151 | 152 | /* 153 | * Ge the servers that may receive or send traffic that matters to the event e 154 | * servers memory must be allocated before calling the function 155 | * returns the number of found servers 156 | */ 157 | uint16_t eventhandler_getserversforevent(struct eventhandler * eh, struct event * e, struct serverdata ** servers); 158 | 159 | /* 160 | * returns until the time is a multiple of passed ms 161 | */ 162 | void eventhandler_syncepoch(int ms); 163 | 164 | 165 | /* 166 | * Fills the buffer based on the event information (e.g., threshold) to be passed with trigger install command to the server 167 | */ 168 | void event_fill(struct event * e, struct trigger * t, char * buf); 169 | bool event_print(void * data, void * aux); 170 | 171 | #endif /* eventhandler.h */ 172 | -------------------------------------------------------------------------------- /controller/hashmap.h: -------------------------------------------------------------------------------- 1 | #ifndef HASHMAP_H 2 | #define HASHMAP_H 1 3 | 4 | #include 5 | #include "stdbool.h" 6 | #include "bitmap.h" 7 | #define NULL_NEXT 0 8 | #define CHAIN_END_NEXT 1 9 | 10 | /* 11 | * prev element is to facilitate the removal algorithm, we don't have previous item in the linked list and don't want to hash & search to find the entry 12 | */ 13 | typedef struct { 14 | uint32_t next; 15 | uint32_t prev; 16 | } hashmap_elem; 17 | 18 | #define list_entry(HASH_ELEM, STRUCT, MEMBER) \ 19 | ((STRUCT *) ((uint8_t *) &(HASH_ELEM)->next \ 20 | - offsetof (STRUCT, MEMBER.next))) 21 | 22 | typedef uint32_t (*hashmap_hash_func)(void * data); 23 | //data1 is your input, data2 will be whatever in map 24 | typedef bool (*hashmap_equal_func)(void * data1, void * data2, void * aux); 25 | typedef bool (*hashmap_apply_func)(void * data, void * aux); 26 | typedef int (*hashmap_comparison_func)(void * data1, void * data2); 27 | typedef void (*hashmap_init_func)(void * newdata, void * data, void * aux); 28 | typedef bool (*hashmap_replace_func)(void * newdata, void * data, void * aux); 29 | 30 | /* 31 | * A general hashmap implementation that keeps collided items in a linked list. It divides the memory into two parts ordinary entries and collisions. Upon collision a slot from collision part will be allocated, so first entry of the linked list is in the ordinary part others are in the collision part (shared among all entriess). 32 | * The structures should have at least one hashmap_elem field. This design comparing to adding that by hashmap itself, helps the user pack and align that hashmap_elem entry inside the datastructure. 33 | * Some additional capabilities are to replace obsolete entries and sort the linked list (using give functions). 34 | * The use can pass a function for initializing the new entry. So during addition, the user can just pass the key not the whole entry 35 | * This is not multi-thread safe 36 | */ 37 | struct hashmap{ 38 | uint8_t * buffer; 39 | uint32_t hashmask; //mask according to the hashmap size 40 | uint32_t entry_size; 41 | uint32_t size; 42 | uint32_t filled; //how many ordinary entries are filled 43 | uint32_t collisions; // how may collision entries are filled 44 | uint16_t elem_offset; //the offset of element in the data put in this hashmap 45 | hashmap_equal_func equal_func; 46 | hashmap_replace_func replace_func; 47 | uint8_t * last_collision_pointer; //the next empty entry in the collision part 48 | uint8_t * bufferlastentry; //just a pointer to the last entry 49 | uint8_t * collision_start; //a pointer to the start of collision part 50 | uint32_t collision_size; 51 | struct bitmap* bm; //filled entries bitmap. Can be null 52 | hashmap_comparison_func lru_func;// if it set, it tries to sort collided entries based on most recently used 53 | }; 54 | 55 | /* 56 | * An iterator over the hashmap. 57 | * It is not safe to change the hashmap during iteration and it is not checked. 58 | * You can only remove entries and pass that event to the hashmap_iterator_next function. 59 | */ 60 | struct hashmap_iterator{ 61 | struct hashmap * h2; 62 | uint8_t * data2; 63 | struct bitmap_iterator *bi; 64 | uint32_t seen_collisions; 65 | uint32_t seen_filled; 66 | uint32_t tosee_filled; 67 | }; 68 | 69 | /* 70 | * elem_offset: the offset of the hashmap_elem entry in the data structure that is going to be saved in the map. You can find it using offsetof function. 71 | * entry_size: It is recommended to use a size multiple of 4 and even better multiple of 64 (cache line size) 72 | * replace_func: a function that returns true/false to replace an entry upon collision. This can be null 73 | */ 74 | struct hashmap * hashmap_init(uint32_t size, uint32_t collision_size, uint32_t entry_size, uint16_t elem_offset, hashmap_replace_func replace_func); 75 | void hashmap_finish(struct hashmap * h2); 76 | 77 | /* 78 | * What percent of ordinary slots are full. 79 | */ 80 | uint16_t hashmap_fullpercent (struct hashmap * h2); 81 | 82 | /* 83 | * Returns tthe number of items saved in the hashmap 84 | */ 85 | uint32_t hashmap_getfull(struct hashmap * h2); 86 | 87 | /* 88 | * return the memory usage of the hashmap 89 | */ 90 | uint32_t hashmap_byte_size(struct hashmap * h2); 91 | 92 | /* 93 | * Upon walking the linkedlist of an entry while adding an entry, the hashmap can swap entries to sort entries (say keep most recently used one close to the head of the linked list for faster retrieval) 94 | */ 95 | void hashmap_setlru(struct hashmap * h2, hashmap_comparison_func func); 96 | 97 | void hashmap_print(struct hashmap * h2); 98 | 99 | /* 100 | * remove all entries 101 | */ 102 | void hashmap_clear(struct hashmap * h2); 103 | 104 | /* 105 | * apply a function on all hashmap entries 106 | */ 107 | void hashmap_apply(struct hashmap * h2, hashmap_apply_func func, void * aux); 108 | 109 | /** 110 | * returns 0 if cannot add 111 | * equal_func: assume the parameter data is the first entry to equal_func. So data can only have the key not the value 112 | * init_func: the function to initialize the entry in the hashmap. If it is null the parameter data will be memcpy to the entry 113 | * aux: a data that will be passsed to equal, init and replace functions 114 | * returns a pointer to the entry in the hashmap, or NULL if it ccannot add it. 115 | */ 116 | void * hashmap_add2 (struct hashmap* h2, void * data, uint32_t h, hashmap_equal_func equal_func, hashmap_init_func init, void * aux); 117 | 118 | /** 119 | * assume data is the first entry to equal_func, this allows just give the key as data 120 | * aux is passed to the equal function 121 | */ 122 | void * hashmap_get2 (struct hashmap * h2, void * data, uint32_t h, hashmap_equal_func equal_func, void * aux); 123 | 124 | /* 125 | * Remove an entry already saved in the hashmap 126 | * After remove, the entry will be zeroed 127 | */ 128 | void hashmap_remove(struct hashmap * h2, void * data2); 129 | 130 | /* 131 | * Prefetch the ordinary slot corresponding to the hash h 132 | */ 133 | void hashmap_prefetch(struct hashmap * h2, uint32_t h); 134 | 135 | /* 136 | * data: the pointer to the next available entry 137 | * removed: should be set to true, if the last entry that is returned is removed from the map 138 | * returns false if no entries available 139 | */ 140 | bool hashmap_iterator_next(struct hashmap_iterator * hi, void ** data, bool removed); 141 | void hashmap_iterator_init(struct hashmap * h2, struct hashmap_iterator * hi); 142 | void hashmap_iterator_finish(struct hashmap_iterator * hi); 143 | 144 | 145 | #endif /* hashmap.h */ 146 | -------------------------------------------------------------------------------- /receiver/hashmap.h: -------------------------------------------------------------------------------- 1 | #ifndef HASHMAP_H 2 | #define HASHMAP_H 1 3 | 4 | #include 5 | #include "stdbool.h" 6 | #include "bitmap.h" 7 | #define NULL_NEXT 0 8 | #define CHAIN_END_NEXT 1 9 | 10 | /* 11 | * prev element is to facilitate the removal algorithm, we don't have previous item in the linked list and don't want to hash & search to find the entry 12 | */ 13 | typedef struct { 14 | uint32_t next; 15 | uint32_t prev; 16 | } hashmap_elem; 17 | 18 | #define list_entry(HASH_ELEM, STRUCT, MEMBER) \ 19 | ((STRUCT *) ((uint8_t *) &(HASH_ELEM)->next \ 20 | - offsetof (STRUCT, MEMBER.next))) 21 | 22 | typedef uint32_t (*hashmap_hash_func)(void * data); 23 | //data1 is your input, data2 will be whatever in map 24 | typedef bool (*hashmap_equal_func)(void * data1, void * data2, void * aux); 25 | //return false if you remove the object from the hashmap 26 | typedef bool (*hashmap_apply_func)(void * data, void * aux); 27 | typedef int (*hashmap_comparison_func)(void * data1, void * data2); 28 | typedef void (*hashmap_init_func)(void * newdata, void * data, void * aux); 29 | typedef bool (*hashmap_replace_func)(void * newdata, void * data, void * aux); 30 | 31 | /* 32 | * A general hashmap implementation that keeps collided items in a linked list. It divides the memory into two parts ordinary entries and collisions. Upon collision a slot from collision part will be allocated, so first entry of the linked list is in the ordinary part others are in the collision part (shared among all entriess). 33 | * The structures should have at least one hashmap_elem field. This design comparing to adding that by hashmap itself, helps the user pack and align that hashmap_elem entry inside the datastructure. 34 | * Some additional capabilities are to replace obsolete entries and sort the linked list (using give functions). 35 | * The use can pass a function for initializing the new entry. So during addition, the user can just pass the key not the whole entry 36 | * This is not multi-thread safe 37 | */ 38 | struct hashmap{ 39 | uint8_t * buffer; 40 | uint32_t hashmask; //mask according to the hashmap size 41 | uint32_t entry_size; 42 | uint32_t size; 43 | uint32_t filled; //how many ordinary entries are filled 44 | uint32_t collisions; // how may collision entries are filled 45 | uint16_t elem_offset; //the offset of element in the data put in this hashmap 46 | hashmap_equal_func equal_func; 47 | hashmap_replace_func replace_func; 48 | uint8_t * last_collision_pointer; //the next empty entry in the collision part 49 | uint8_t * bufferlastentry; //just a pointer to the last entry 50 | uint8_t * collision_start; //a pointer to the start of collision part 51 | uint32_t collision_size; 52 | struct bitmap* bm; //filled entries bitmap. Can be null 53 | hashmap_comparison_func lru_func;// if it set, it tries to sort collided entries based on most recently used 54 | }; 55 | 56 | /* 57 | * An iterator over the hashmap. 58 | * It is not safe to change the hashmap during iteration and it is not checked. 59 | * You can only remove entries and pass that event to the hashmap_iterator_next function. 60 | */ 61 | struct hashmap_iterator{ 62 | struct hashmap * h2; 63 | uint8_t * data2; 64 | struct bitmap_iterator *bi; 65 | uint32_t seen_collisions; 66 | uint32_t seen_filled; 67 | uint32_t tosee_filled; 68 | }; 69 | 70 | /* 71 | * elem_offset: the offset of the hashmap_elem entry in the data structure that is going to be saved in the map. You can find it using offsetof function. 72 | * entry_size: It is recommended to use a size multiple of 4 and even better multiple of 64 (cache line size) 73 | * replace_func: a function that returns true/false to replace an entry upon collision. This can be null 74 | */ 75 | struct hashmap * hashmap_init(uint32_t size, uint32_t collision_size, uint32_t entry_size, uint16_t elem_offset, hashmap_replace_func replace_func); 76 | void hashmap_finish(struct hashmap * h2); 77 | 78 | /* 79 | * What percent of ordinary slots are full. 80 | */ 81 | uint16_t hashmap_fullpercent (struct hashmap * h2); 82 | 83 | /* 84 | * Returns tthe number of items saved in the hashmap 85 | */ 86 | uint32_t hashmap_getfull(struct hashmap * h2); 87 | 88 | /* 89 | * return the memory usage of the hashmap 90 | */ 91 | uint32_t hashmap_byte_size(struct hashmap * h2); 92 | 93 | /* 94 | * Upon walking the linkedlist of an entry while adding an entry, the hashmap can swap entries to sort entries (say keep most recently used one close to the head of the linked list for faster retrieval) 95 | */ 96 | void hashmap_setlru(struct hashmap * h2, hashmap_comparison_func func); 97 | 98 | void hashmap_print(struct hashmap * h2); 99 | 100 | /* 101 | * remove all entries 102 | */ 103 | void hashmap_clear(struct hashmap * h2); 104 | 105 | /* 106 | * apply a function on all hashmap entries 107 | */ 108 | void hashmap_apply(struct hashmap * h2, hashmap_apply_func func, void * aux); 109 | 110 | /** 111 | * returns 0 if cannot add 112 | * equal_func: assume the parameter data is the first entry to equal_func. So data can only have the key not the value 113 | * init_func: the function to initialize the entry in the hashmap. If it is null the parameter data will be memcpy to the entry 114 | * aux: a data that will be passsed to equal, init and replace functions 115 | * returns a pointer to the entry in the hashmap, or NULL if it ccannot add it. 116 | */ 117 | void * hashmap_add2 (struct hashmap* h2, void * data, uint32_t h, hashmap_equal_func equal_func, hashmap_init_func init, void * aux); 118 | 119 | /** 120 | * assume data is the first entry to equal_func, this allows just give the key as data 121 | * aux is passed to the equal function 122 | */ 123 | void * hashmap_get2 (struct hashmap * h2, void * data, uint32_t h, hashmap_equal_func equal_func, void * aux); 124 | 125 | /* 126 | * Remove an entry already saved in the hashmap 127 | * After remove, the entry will be zeroed 128 | */ 129 | void hashmap_remove(struct hashmap * h2, void * data2); 130 | 131 | /* 132 | * Prefetch the ordinary slot corresponding to the hash h 133 | */ 134 | void hashmap_prefetch(struct hashmap * h2, uint32_t h); 135 | 136 | /* 137 | * data: the pointer to the next available entry 138 | * removed: should be set to true, if the last entry that is returned is removed from the map 139 | * returns false if no entries available 140 | */ 141 | bool hashmap_iterator_next(struct hashmap_iterator * hi, void ** data, bool removed); 142 | void hashmap_iterator_init(struct hashmap * h2, struct hashmap_iterator * hi); 143 | void hashmap_iterator_finish(struct hashmap_iterator * hi); 144 | 145 | 146 | #endif /* hashmap.h */ 147 | -------------------------------------------------------------------------------- /receiver/summary.h: -------------------------------------------------------------------------------- 1 | #ifndef SUMMARY_H 2 | #define SUMMARY_H 1 3 | #include 4 | #include 5 | #include 6 | #include //for offsetof 7 | #include "flowentry.h" 8 | #include "bitmap.h" 9 | 10 | #define SUMMARY_NAME_LEN 16 11 | 12 | #define SUMMARY_UPDATE_FUNC_OFFSET offsetof(struct summary, update) 13 | 14 | struct flatreport; 15 | struct flatreport_pkt; 16 | struct summary; 17 | 18 | typedef void (*summary_apply_func)(struct summary *s, char * buf, struct flatreport * fr); 19 | typedef void (*summary_apply_update_func)(struct summary *s, char * buf, struct flatreport * fr, struct flatreport_pkt * pkt); 20 | typedef void (*summary_apply_func2)(struct summary *s); 21 | 22 | struct summary{ 23 | uint16_t size; //number of bytes to be reserved in the flowtable per flow 24 | uint8_t index; 25 | summarymask_t mask; 26 | summary_apply_update_func update; 27 | summary_apply_func reset; 28 | summary_apply_func finish; //must free any resources malloced 29 | summary_apply_func2 free; //just in case somebody need to instantiate the summary out of the flowtable 30 | void * moredata; //points to subclasses 31 | char name[SUMMARY_NAME_LEN]; 32 | }; 33 | 34 | struct summary_table{ 35 | struct summary * summaries[SUMMARIES_NUM]; 36 | uint8_t filled; 37 | }; 38 | 39 | void summary_init(struct summary_table * st); 40 | void summary_finish(struct summary_table * st); 41 | struct summary * summary_hassummary(struct summary_table * st, const char * name); 42 | struct summary * summary_add(struct summary_table * st, struct summary * s); 43 | 44 | /* 45 | * applies the function on all the summaries enabled for the flowentry fe 46 | */ 47 | void summary_apply(struct summary_table * st, struct flowentry * fe, summary_apply_func func, struct flatreport * fr); 48 | 49 | /* 50 | * calls the update function for all summaries on the flowentry 51 | */ 52 | void summary_apply_update(struct summary_table * st, struct flowentry * fe, struct flatreport * fr, struct flatreport_pkt * pkt); 53 | 54 | /* 55 | * calls the finish function for the summary that uses the buffer buf 56 | */ 57 | void summary_apply_finish(struct summary *s, char * buf, struct flatreport * fr); 58 | 59 | /* 60 | * calls the reset function for the summary as if it uses the buffer buf 61 | */ 62 | void summary_apply_reset(struct summary *s, char * buf, struct flatreport * fr); 63 | 64 | /*----------------------------------- pktnum summary -----------------------*/ 65 | uint32_t summary_pktnum_get(char * buf, struct flatreport * fr); 66 | struct summary * summary_pktnum_init(const char * name); 67 | 68 | /*----------------------------------- volume summary -----------------------*/ 69 | uint32_t summary_volume_get(char * buf, struct flatreport * fr); 70 | struct summary * summary_volume_init(const char * name); 71 | 72 | /*----------------------- -- # retransmitted packets summary ---------------*/ 73 | uint32_t summary_lossnum2_get(char * buf, struct flatreport * fr); 74 | struct summary * summary_lossnum2_init(const char * name); 75 | 76 | /*----------------------------------- # acks -------------------------------*/ 77 | uint32_t summary_ack_get(char * buf); 78 | uint32_t summary_ack_get2(char * buf); 79 | uint32_t summary_ack_getdup(char * buf); 80 | struct summary * summary_ack_init(const char * name); 81 | 82 | 83 | /*------------------------------- maximum syn number------------------------*/ 84 | uint32_t summary_syn_get(char * buf); 85 | uint32_t summary_syn_get2(char * buf); 86 | struct summary * summary_syn_init(const char * name); 87 | 88 | 89 | /*---------------------------- loss num using a bitmap----------------------*/ 90 | 91 | /* 92 | * A shared data structure among all lossnum summaries that keeps track of 93 | * seen sequence numbers in a bitmap 94 | */ 95 | struct lossfinder{ 96 | struct bitmap * lossbm1; 97 | struct bitmap * lossbm2; 98 | uint32_t lasthash; 99 | uint32_t pkts_num; 100 | uint8_t lastresult; 101 | uint8_t needsreset; 102 | }; 103 | 104 | struct lossfinder * summary_lossfinder_init(void); 105 | void summary_lossfinder_finish(struct lossfinder * lf); 106 | void summary_lossfinder_reset(struct lossfinder * lf); 107 | 108 | uint32_t summary_lossnum_get(char* buf, struct flatreport * fr); 109 | struct summary * summary_lossnum_init(struct lossfinder * lf, const char * name); 110 | 111 | 112 | /*------------ list of sequence number of retransmitted packets---------------*/ 113 | struct losslisthead{ 114 | struct losslist * last_ll; 115 | struct losslist * first_ll; 116 | uint32_t lastseq; 117 | uint16_t nextIndex; 118 | }; 119 | 120 | struct losslist { 121 | uint32_t lost[LOSSLIST_BLOCK]; 122 | struct losslist * next; 123 | }; 124 | 125 | typedef void (*loss_apply_func)(uint32_t seq, void * aux); 126 | 127 | void losslisthead_add(struct losslisthead * llh, uint32_t seq); 128 | void losslisthead_apply(struct losslisthead * llh, loss_apply_func, void * aux); 129 | void losslisthead_reset(struct losslisthead * llh); 130 | struct summary * summary_losslisthead_init(void); 131 | struct losslisthead * summary_losslist_get(char* buf); 132 | 133 | struct losslist * losslist_init(void); 134 | void losslist_finish(struct losslist * ll); 135 | void losslist_print(uint32_t seq, void * aux); 136 | 137 | 138 | /*-------------------------------- burst detection --------------------------*/ 139 | /* 140 | * start and finish sequence numbers of a burst 141 | */ 142 | struct burst{ 143 | uint32_t seq1; 144 | uint32_t seq2; 145 | }; 146 | 147 | /* 148 | * a block of bursts 149 | */ 150 | struct burstlist{ 151 | struct burst b[BURSTLIST_BLOCK]; 152 | struct burstlist * next; 153 | struct burstlist * prev; 154 | }; 155 | 156 | /* 157 | * burst summary 158 | */ 159 | struct burstlisthead{ 160 | uint64_t ts; 161 | uint32_t seq1; 162 | uint32_t seq2; 163 | uint16_t num; 164 | uint16_t nextIndex; 165 | struct burstlist * last_bl; 166 | struct burstlist * first_bl; 167 | }; 168 | 169 | struct burstsearchstate{ 170 | struct burstlist * current; 171 | uint16_t nextIndex; 172 | }; 173 | 174 | typedef void (*burst_apply_func)(struct burst * b, void * aux); 175 | 176 | void burstlisthead_add(struct burstlisthead * blh, uint32_t seq, uint64_t ts); 177 | void burstlisthead_apply(struct burstlisthead * blh, burst_apply_func, void * aux); 178 | bool burstlisthead_isburst(struct burstlisthead * blh, uint32_t seq, void * state1); 179 | struct burstlisthead * summary_burstlist_get(char * buf); 180 | void burstlisthead_reset(struct burstlisthead * blh); 181 | void burstlisthead_dump(struct burstlisthead * blh); 182 | struct summary * summary_burstlisthead_init(void); 183 | void summary_updatesummaries(struct summary_table * st, struct flowentry * fe); 184 | 185 | struct burstlist * burstlist_init(void); 186 | void burstlist_finish(struct burstlist * bl); 187 | void burstlist_print(struct burst * b, void * aux); 188 | 189 | #endif /* summary.h */ 190 | -------------------------------------------------------------------------------- /controller/tcpserver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tcpserver.c - A simple TCP echo server 3 | * usage: tcpserver 4 | */ 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 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "serverdata.h" 27 | #include "eventhandler.h" 28 | #include "util.h" 29 | #include "loguser.h" 30 | #include "usecase.h" 31 | 32 | 33 | struct globalconfig{ 34 | uint16_t servernum; 35 | uint16_t eventsnum; 36 | bool finish; 37 | char log_prefix[50]; 38 | }; 39 | 40 | static struct globalconfig g; 41 | 42 | static void int_handler(int sig_num){ 43 | printf("signal %d\n", sig_num); 44 | g.finish = true; 45 | } 46 | 47 | static void printhelp(void){ 48 | printf("This is the manual for the commandline parameters of the controller side in Trumpet.\n"); 49 | printf("\t -p : port number (default 5000)\n"); 50 | printf("\t -l : log prefix (default 'log')\n"); 51 | printf("\t -u : the index of the usecase. 0 is TCP burst and loss, 1 is the TCP congestion example and 2 is the network-wide example (default 2)\n"); 52 | printf("\t -s : number of servers for the network-wide example (default 4)\n"); 53 | printf("\t -e : number of events to add for network-wide usecase (default 16)\n"); 54 | printf("\t -h : prints this help\n"); 55 | } 56 | 57 | int main(int argc, char **argv) { 58 | int ret = rte_eal_init(argc, argv); 59 | if (ret < 0) 60 | rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); 61 | 62 | argc -= ret; 63 | argv += ret; 64 | //util_init(); 65 | 66 | ///////////////////// handle connections 67 | int addeventforservers = 4; 68 | 69 | int parentfd; /* parent socket */ 70 | int childfd; /* child socket */ 71 | int portno = 5000; /* port to listen on */ 72 | socklen_t clientlen; /* byte size of client's address */ 73 | struct sockaddr_in serveraddr; /* server's addr */ 74 | struct sockaddr_in clientaddr; /* server's addr */ 75 | int optval; /* flag value for setsockopt */ 76 | snprintf(g.log_prefix, 50, "log"); 77 | g.eventsnum = 16; 78 | 79 | /* 80 | * check command line arguments 81 | */ 82 | int opt; 83 | 84 | uint16_t ui = 2; 85 | 86 | while ((opt = getopt(argc, argv, "p:l:s:e:u:h")) != -1){ 87 | switch (opt) { 88 | case 'p': 89 | portno = atof(optarg); 90 | break; 91 | case 'l': 92 | snprintf(g.log_prefix, 50, "%s", optarg); 93 | break; 94 | case 's': 95 | addeventforservers = atof(optarg); 96 | break; 97 | case 'e': 98 | g.eventsnum = atof(optarg); 99 | break; 100 | case 'u': 101 | ui = atoi(optarg); 102 | if (ui != 1 && ui != 2 && ui != 3){ 103 | printf("Unknown usecase option %d\n", ui); 104 | abort(); 105 | } 106 | break; 107 | case 'h': 108 | printhelp(); 109 | abort(); 110 | break; 111 | default: 112 | printf("Unknown option %d\n", optopt); 113 | abort(); 114 | } 115 | } 116 | util_lu = loguser_init(1<<12, g.log_prefix, 14); 117 | struct usecase * u = NULL; 118 | if (ui == 1){ 119 | u = usecase_congestion_init(); 120 | }else if (ui == 2){ 121 | u = usecase_netwide_init(addeventforservers, g.eventsnum); 122 | }else if (ui == 3){ 123 | u = usecase_file_init("testevents.txt", addeventforservers); 124 | }else{ 125 | printf("Unknown usecase\n"); 126 | abort(); 127 | } 128 | struct eventhandler * eh = eventhandler_init(u); 129 | 130 | /* 131 | * socket: create the parent socket 132 | */ 133 | parentfd = socket(AF_INET, SOCK_STREAM, 0); 134 | if (parentfd < 0) 135 | fprintf(stderr, "ERROR opening socket"); 136 | 137 | /* setsockopt: Handy debugging trick that lets 138 | * us rerun the server immediately after we kill it; 139 | * otherwise we have to wait about 20 secs. 140 | * Eliminates "ERROR on binding: Address already in use" error. 141 | */ 142 | optval = 1; 143 | setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, 144 | (const void *)&optval , sizeof(int)); 145 | int on = 1; 146 | int rc = ioctl(parentfd, FIONBIO, (char *)&on); 147 | if (rc < 0) 148 | { 149 | perror("ioctl() failed"); 150 | close(parentfd); 151 | exit(-1); 152 | } 153 | 154 | /* 155 | * build the server's Internet address 156 | */ 157 | bzero((char *) &serveraddr, sizeof(serveraddr)); 158 | 159 | /* this is an Internet address */ 160 | serveraddr.sin_family = AF_INET; 161 | 162 | /* let the system figure out our IP address */ 163 | serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 164 | 165 | /* this is the port we will listen on */ 166 | serveraddr.sin_port = htons((unsigned short)portno); 167 | 168 | /* 169 | * bind: associate the parent socket with a port 170 | */ 171 | if (bind(parentfd, (struct sockaddr *) &serveraddr, 172 | sizeof(serveraddr)) < 0) 173 | fprintf(stderr, "ERROR on binding"); 174 | 175 | /* 176 | * listen: make this socket ready to accept connection requests 177 | */ 178 | if (listen(parentfd, 5) < 0) /* allow 5 requests to queue up */ 179 | fprintf(stderr, "ERROR on listen"); 180 | 181 | /* 182 | * create reading threads 183 | */ 184 | g.servernum = 0; 185 | 186 | /* 187 | * main loop: wait for a connection request, echo input line, 188 | * then close connection. 189 | */ 190 | clientlen = sizeof(clientaddr); 191 | g.finish = false; 192 | signal(SIGINT, int_handler); 193 | // polling from http://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzab6/poll.htm 194 | 195 | struct pollfd fd; 196 | fd.fd = parentfd; // your socket handler 197 | fd.events = POLLIN; 198 | while (!g.finish) { 199 | int ret = poll(&fd, 1, 1000); 200 | if (ret < 0){ 201 | fprintf(stderr, "tcpserver cannot poll\n"); 202 | break; 203 | } 204 | if (ret == 0){ 205 | continue; 206 | } 207 | if(fd.revents != POLLIN){ 208 | printf(" Error! revents = %d\n", fd.revents); 209 | break; 210 | } 211 | /* 212 | * accept: wait for a connection request 213 | */ 214 | childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen); 215 | if (childfd < 0 && g.servernum < MAX_SERVERS){ 216 | fprintf(stderr, "ERROR on accept"); 217 | }else if (g.servernum >= MAX_SERVERS){ 218 | fprintf(stderr, "Can only support %d connections", MAX_SERVERS); 219 | }else{ 220 | int one = 1; 221 | setsockopt(childfd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)); 222 | struct serverdata * server = serverdata_init(eh, childfd, clientaddr,g.servernum, 2+g.servernum*2); 223 | g.servernum++; 224 | eventhandler_addserver(eh, server); 225 | } 226 | /* if (eventhandler_activeservers(eh) == addeventforservers){ 227 | //add the event after some delay so that the servers are setup correctly 228 | eventhandler_addeventdelay(eh, g.eventsnum, 1000000); 229 | }*/ 230 | } 231 | 232 | ////////////////////////////////////////////////// close 233 | close(parentfd); 234 | 235 | eventhandler_finish(eh); 236 | // util_finish(); 237 | loguser_finish(util_lu); 238 | 239 | return 0; 240 | } 241 | -------------------------------------------------------------------------------- /receiver/matcher.c: -------------------------------------------------------------------------------- 1 | #include "matcher.h" 2 | #include "util.h" 3 | 4 | bool matcherlist_head_finish(void * data, void * aux __attribute((unused))); 5 | bool matcherlist_head_flowequal(void * data1, void * data2, void * aux __attribute__((unused))); 6 | bool matcherlist_head_equal(void * data1, void * data2, void * aux __attribute__((unused))); 7 | struct table * findtable(struct matcher * m, struct flow * mask); 8 | 9 | void table_maskinit(void * m, void * data, void * aux); 10 | void table_finish(struct table * tbl); 11 | bool table_add(struct table * tbl, struct flow * f, void * data); 12 | bool table_remove(struct table * tbl, struct flow * f, void * data, matcher_dataequal_func func, void ** removed); 13 | bool table_finish2(void * data, void * aux); 14 | bool table_maskequal(void * data1, void * data2, void * aux); 15 | 16 | struct matcherlist_entry{ 17 | struct matcherlist_entry * next; 18 | void * data; 19 | }; 20 | 21 | struct matcherlist_head{ 22 | struct flow f; 23 | hashmap_elem e; 24 | struct matcherlist_entry mle; 25 | }; 26 | 27 | 28 | bool matcherlist_head_finish(void * data, void * aux __attribute((unused))){ 29 | struct matcherlist_head * mlh = (struct matcherlist_head *) data; 30 | struct matcherlist_entry * mle, * mle2; 31 | for (mle = mlh->mle.next; mle != NULL; mle = mle2){ 32 | mle2 = mle->next; 33 | FREE(mle); 34 | } 35 | return true; 36 | } 37 | 38 | bool matcherlist_head_flowequal(void * data1, void * data2, void * aux __attribute__((unused))){ 39 | struct flow * f = (struct flow *) data1; 40 | struct matcherlist_head * mlh = (struct matcherlist_head *) data2; 41 | return flow_equal(f, &mlh->f); 42 | } 43 | 44 | bool matcherlist_head_equal(void * data1, void * data2, void * aux __attribute__((unused))){ 45 | struct matcherlist_head * mlh1 = (struct matcherlist_head *) data1; 46 | struct matcherlist_head * mlh2 = (struct matcherlist_head *) data2; 47 | return flow_equal(&mlh1->f, &mlh2->f); 48 | } 49 | 50 | static inline int matcher_tablematch(struct table * tbl, struct flow * f2, void ** dataarr, uint16_t * size){ 51 | struct flow f; 52 | uint16_t i = 0; 53 | flow_mask(&f, f2, &tbl->mask); 54 | struct matcherlist_head * mlh = hashmap_get2(tbl->map, &f, flow_hash(&f), matcherlist_head_flowequal, NULL); 55 | if (mlh != NULL){ 56 | struct matcherlist_entry * mle; 57 | for (mle = &mlh->mle; mle != NULL; mle = mle->next){ 58 | if (unlikely(i >= *size)){ 59 | break; 60 | } 61 | *(dataarr + i) = mle->data; 62 | i++; 63 | } 64 | } 65 | return i; 66 | } 67 | 68 | void matcher_matchmask(struct matcher * m, struct flow * f2, struct flow * mask, void ** dataarr, uint16_t * size){ 69 | struct table * tbl = findtable(m, mask); 70 | if (tbl == NULL){ 71 | *size = 0; 72 | return; 73 | } 74 | 75 | *size = matcher_tablematch(tbl, f2, dataarr, size); 76 | } 77 | 78 | void matcher_match(struct matcher * m, struct flow * f2, void ** dataarr, uint16_t * size){ 79 | //go through tables 80 | struct table * tbl; 81 | uint16_t s = *size; 82 | for (tbl = m->tables; tbl != NULL; tbl = tbl->next){ 83 | *size -= matcher_tablematch(tbl, f2, dataarr + (s - *size), size); 84 | } 85 | 86 | *size = s - *size; 87 | } 88 | 89 | inline struct table * findtable(struct matcher * m, struct flow * mask){ 90 | return (struct table *) hashmap_get2(m->masktable, mask, flow_hash(mask), table_maskequal, NULL); 91 | } 92 | 93 | //it may add duplicates 94 | bool matcher_add (struct matcher * m, struct flow * f, struct flow * mask, void * data){ 95 | if (data == NULL){ 96 | fprintf(stderr, "Matcher cannot add null data\n"); 97 | return false; 98 | } 99 | //find the table 100 | struct table * tbl2 = findtable(m, mask); 101 | if (tbl2 == NULL){ //add table 102 | tbl2 = hashmap_add2(m->masktable, mask, flow_hash(mask), table_maskequal, table_maskinit, NULL); 103 | // tbl2 = table_init(mask); 104 | if (m->tables == NULL){ 105 | m->tables = tbl2; 106 | }else{ 107 | struct table * tbl; 108 | for (tbl = m->tables; tbl->next != NULL; tbl = tbl->next); 109 | tbl->next = tbl2; 110 | } 111 | } 112 | return table_add(tbl2, f, data); 113 | } 114 | 115 | //deletes only one if it finds equal 116 | bool matcher_remove(struct matcher * m, struct flow * f, struct flow * mask, void * data, matcher_dataequal_func func, void ** removed){ 117 | struct table * tbl = findtable(m, mask); 118 | if (tbl != NULL){ 119 | if (table_remove(tbl, f, data, func, removed)){ 120 | return true; 121 | }else{ 122 | fprintf(stderr, "Matcher: Entry not found in the table to be removed"); 123 | } 124 | }else{ 125 | fprintf(stderr, "Matcher: Table not found to be removed"); 126 | } 127 | return false; 128 | } 129 | 130 | struct matcher * matcher_init(void){ 131 | struct matcher * m = (struct matcher *)MALLOC (sizeof(struct matcher)); 132 | uint16_t entry_size = entry_size_64(sizeof(struct table)); 133 | m->masktable = hashmap_init(1<<10, 1<<10, entry_size, offsetof(struct table, e), NULL); 134 | m->tables = NULL; 135 | return m; 136 | } 137 | 138 | void matcher_finish(struct matcher * m){ 139 | hashmap_apply(m->masktable, table_finish2, NULL); 140 | hashmap_finish(m->masktable); 141 | /* struct table * tbl; 142 | struct table * tbl2; 143 | int i = 0; 144 | for (tbl = m->tables; tbl != NULL; tbl = tbl2){ 145 | tbl2 = tbl->next; 146 | table_finish(tbl); 147 | i++; 148 | }*/ 149 | FREE(m); 150 | } 151 | 152 | 153 | ///////////////////////////////// TABLE ///////////////////////// 154 | 155 | void table_maskinit(void * m, void * data, void * aux __attribute__((unused))){ 156 | struct flow * mask = (struct flow *) m; 157 | struct table * tbl = (struct table *) data; 158 | flow_fill(&tbl->mask, mask); 159 | 160 | uint16_t entry_size = entry_size_64(sizeof(struct matcherlist_head)); 161 | tbl->map = hashmap_init(1<<14, 1<<13, entry_size, offsetof(struct matcherlist_head, e), NULL); 162 | tbl->next = NULL; 163 | } 164 | 165 | bool table_finish2(void * data, void * aux __attribute__((unused))){ 166 | table_finish((struct table*)data); 167 | return true; 168 | } 169 | 170 | inline void table_finish(struct table * tbl){ 171 | hashmap_apply(tbl->map, matcherlist_head_finish, NULL); 172 | hashmap_finish(tbl->map); 173 | // FREE(tbl); 174 | } 175 | 176 | bool table_maskequal(void * data1, void * data2, void * aux __attribute__((unused))){ 177 | return flow_equal((struct flow *) data1, &((struct table *) data2)->mask); 178 | } 179 | 180 | bool table_add(struct table * tbl, struct flow * f, void * data){ 181 | struct flow f2; 182 | flow_mask(&f2, f, &tbl->mask); 183 | struct matcherlist_head * mlh = hashmap_get2(tbl->map, &f2, flow_hash(&f2), matcherlist_head_flowequal, NULL); 184 | if (mlh == NULL){ 185 | struct matcherlist_head mlh2; 186 | mlh = &mlh2; 187 | flow_fill(&mlh->f, &f2); 188 | mlh->mle.data = data; 189 | mlh->mle.next = NULL; 190 | hashmap_add2(tbl->map, mlh, flow_hash(&f2), matcherlist_head_equal, NULL, NULL); 191 | return false; 192 | }else{ 193 | struct matcherlist_entry * mle2 = (struct matcherlist_entry *) MALLOC(sizeof(struct matcherlist_entry)); 194 | mle2->next = NULL; 195 | mle2->data = data; 196 | 197 | struct matcherlist_entry * mle; 198 | for (mle = &mlh->mle; mle->next != NULL; mle = mle->next); 199 | 200 | mle->next = mle2; 201 | return true; 202 | } 203 | } 204 | 205 | bool table_remove(struct table * tbl, struct flow * f, void * data, matcher_dataequal_func func, void ** removed){ 206 | struct flow f2; 207 | flow_mask(&f2, f, &tbl->mask); 208 | struct matcherlist_head * mlh = hashmap_get2(tbl->map, &f2, flow_hash(&f2), matcherlist_head_flowequal, NULL); 209 | if (mlh != NULL){ 210 | if (func(mlh->mle.data, data)){ 211 | *removed = mlh->mle.data; 212 | if (mlh->mle.next == NULL){ 213 | hashmap_remove(tbl->map, mlh); 214 | }else{ 215 | struct matcherlist_entry * mle2 = mlh->mle.next; //copy data of next and remove it 216 | mlh->mle.data = mle2->data; 217 | mlh->mle.next = mle2->next; 218 | FREE(mle2); 219 | } 220 | return true; 221 | }else{ 222 | struct matcherlist_entry * mle; 223 | struct matcherlist_entry * last_mle = &mlh->mle; 224 | for (mle = last_mle->next; mle != NULL; last_mle = mle, mle = mle->next){ 225 | if (func(mle->data, data)){ 226 | last_mle->next = mle->next; 227 | *removed = mle->data; 228 | FREE(mle); 229 | return true; 230 | } 231 | } 232 | } 233 | 234 | fprintf(stderr, "No matching data is found in the table entry to be removed"); 235 | }else{ 236 | fprintf(stderr, "No data is found in the table to be removed"); 237 | } 238 | return false; 239 | } 240 | -------------------------------------------------------------------------------- /receiver/triggertable2.h: -------------------------------------------------------------------------------- 1 | #ifndef TRIGGERTABLE2_H 2 | #define TRIGGERTABLE2_H 1 3 | #include "flow.h" 4 | #include "flowentry.h" 5 | #include "summary.h" 6 | #include "util.h" 7 | #include "matcher.h" 8 | 9 | #define TYPE_NAME_SIZE 20 10 | #define VIOLATED_ENTRIES_SIZE 1024 11 | #define TRIGGERTABLE_POSITION_TABLE_SIZE 32768 12 | 13 | struct triggertable; 14 | struct trigger; 15 | struct trigger_pointer; 16 | 17 | 18 | typedef void (*trigger_update_func)(struct trigger * t, void * d, struct triggertable * tt); 19 | typedef bool (*trigger_report_func)(struct trigger * t, uint32_t stepsback, char * buf); 20 | typedef void (*trigger_apply_func)(struct trigger * t, void * aux); 21 | typedef bool (*trigger_condition_func)(struct trigger * t); 22 | 23 | 24 | struct triggerflow{ 25 | struct flow f; 26 | // struct flowentry * fe; 27 | // uint32_t hash; 28 | }; 29 | 30 | /* 31 | * A linklist of triggerflowlists. 32 | * These can be chained together to keep track of them in a linkedlist by themselves 33 | */ 34 | struct triggerflowlistpool{ 35 | struct triggerflowlist * tfl; 36 | struct triggerflowlistpool * next; 37 | }; 38 | 39 | struct triggerflowlist{ 40 | uint64_t fullmap;//1 bits show an occupied entry in tf array 41 | struct triggerflow tf[TRIGGERFLOW_BATCH]; 42 | struct triggerflowlist * next; 43 | }; 44 | 45 | struct sweep_state{ 46 | uint32_t index; 47 | uint32_t seen; // How many triggers have been seen till now 48 | struct triggerflowlist * tfl; 49 | struct triggerflowlist * tfl_last; 50 | bool triggerinterrupted;// If we are in the middle of processing flows for a trigger 51 | }; 52 | 53 | struct triggertable{ 54 | struct matcher * m; 55 | struct flatreport * fr; 56 | struct trigger ** violated_entries_buffer; //keep track of triggers to report (for strawman that sweeps over flow table instad of triggers) 57 | struct bitmap * trigger_pos_bm; 58 | struct triggerflowlist * freelist; //keeps track of free triggerflowlistss in a linkedlist 59 | #if TRIGGERTABLE_INLINE_TRIGGER 60 | struct trigger * position_table; 61 | #else 62 | struct trigger ** position_table; 63 | #endif 64 | struct sweep_state state; 65 | struct triggertype * types; 66 | struct triggerflowlistpool * pools; 67 | struct triggertype * fgtype; 68 | uint16_t violated_entry_index; // for reporting when strawman goes over flow table entries 69 | uint16_t filled; //number of added triggers 70 | uint16_t lastid; 71 | void * triggers_temp[FLOWENTRY_TRIGGER_SIZE]; //used for strawman that sweeps over flow table entries 72 | }; 73 | 74 | struct triggertype{ 75 | struct summary ** s; // a trigger type may need multiple summaries 76 | trigger_update_func update_func; 77 | trigger_apply_func reset_func; 78 | trigger_condition_func condition_func; 79 | uint32_t ticksperupdate; 80 | uint32_t ticksperupdate2; 81 | uint16_t ticksperupdate_num; 82 | uint16_t flow_micronum; 83 | summarymask_t summarymask; //Which summaries are necessary for this trigger? 84 | uint8_t id; 85 | struct triggertype * next; 86 | trigger_report_func report_func; 87 | trigger_apply_func free_func; 88 | trigger_apply_func print_func; 89 | }; 90 | 91 | /* 92 | * The general structure for triggers. Use the buffer buf to store trigger specific information like threshold. 93 | */ 94 | struct trigger{ 95 | struct triggertype * type; 96 | uint32_t lastreset;//the epoch number when the trigger is reset 97 | uint16_t reset_interval; 98 | uint16_t eventid; 99 | struct flow filter; 100 | struct flow mask; 101 | uint32_t matched; 102 | uint16_t id; 103 | #if !TRIGGERTABLE_INLINE_TRIGGER 104 | uint16_t pos;//index in the table of back-to-back triggers 105 | #endif 106 | uint8_t historyindex;//handles the history of aggregated values in the circular buffer of the trigger 107 | #if TRIGGERTABLE_SWEEP 108 | uint8_t tfhead_filled; 109 | struct triggerflowlist * tfl; 110 | char buf[64] __attribute__((aligned(4))); 111 | #else 112 | bool reported; 113 | char buf[70] __attribute__((aligned(4))); 114 | #endif 115 | }; 116 | 117 | struct triggertable * triggertable_init(struct flatreport * fr); 118 | void triggertable_finish(struct triggertable * tt); 119 | void triggertable_print(struct triggertable * tt); 120 | 121 | void triggertable_addtype(struct triggertable * tt, struct triggertype * type1); 122 | uint16_t triggertable_gettypenum(struct triggertable * tt); 123 | struct triggertype * triggertable_gettype(struct triggertable * tt, uint8_t type_id); 124 | 125 | bool triggertable_addtrigger(struct triggertable * tt, struct trigger * t); 126 | bool triggertable_removetrigger(struct triggertable * tt, struct trigger * t); 127 | 128 | /* 129 | * returns a new trigger in the trigger table 130 | */ 131 | struct trigger * triggertable_gettrigger(struct triggertable * tt); 132 | 133 | /* 134 | * Apply a function on every trigger 135 | */ 136 | void triggertable_applyontriggers(struct triggertable * tt, trigger_apply_func func, void * aux); 137 | 138 | /* 139 | * For the strawman that sweeps over the flow table. Matches the flow and updates the flowentry 140 | */ 141 | void triggertable_match(struct triggertable * tt, struct flowentry * fe, struct summary_table * st); 142 | 143 | /* 144 | * The trigger matches the flow, so just let it know so that later it can aggregate its data. 145 | */ 146 | void triggertable_singletriggermatch(struct triggertable * tt, struct trigger * t, struct flowentry * fe, struct summary_table * st); 147 | 148 | /* 149 | * get a list of triggers that match a flow. Num should have the max number of triggers that can be put in the temptable. When the function is returned it num will be updated with the actual number of found triggers. 150 | */ 151 | void triggertable_justmatch(struct triggertable * tt, struct flow * f, struct flow * mask, struct trigger ** temptable, uint16_t * num); 152 | 153 | /* 154 | * Matching function when we want to sweep over triggers. It updates the flowentry accordingly 155 | */ 156 | void triggertable_sweepmatch(struct triggertable * tt, struct flowentry * fe, struct summary_table * st, uint32_t hash); 157 | 158 | /* 159 | * for strawman of sweeping over flows, this will aggregate statistics and updates the triggers corresponding to the flowentry 160 | */ 161 | void triggertable_update(struct triggertable * tt, struct flowentry * fe, struct summary_table * st); 162 | 163 | /* 164 | * for packet history strawman, it will update the flowentry based on the packet directly 165 | */ 166 | void triggertable_update2(struct triggertable * tt, struct flowentry * fe, struct flatreport_pkt * pkt); 167 | 168 | /* 169 | * Sweep over the trigger table. If multiplestep is on, it respects the sweeptime and returns true if the sweep is finished. minsweepticks tells with what granularity check the time to not pass sweeptime. 170 | */ 171 | bool triggertable_sweep(struct triggertable * tt, uint32_t sweeptime, const uint32_t minsweepticks); 172 | 173 | /* 174 | * sweeping for packet history strawman. It assumes the statistics of triggers are already aggregated 175 | */ 176 | void triggertable_naivesweep(struct triggertable * tt); 177 | 178 | /* 179 | * Start sweeping over triggers 180 | */ 181 | void triggertable_startsweep(struct triggertable * tt); 182 | 183 | /* 184 | * returns true if the sweep over triggers finished 185 | */ 186 | bool triggertable_issweepfinished(struct triggertable * tt); 187 | 188 | /* 189 | * for sweeping over flows, this will collect all reports from triggers and print a report 190 | */ 191 | void triggertable_report(struct triggertable * tt); 192 | 193 | /* 194 | * Get the report for a trigger. It can return false if the data is not availbale for the requested time. 195 | */ 196 | bool triggertable_getreport(struct triggertable * tt, struct trigger * t, char * buf, uint32_t time); 197 | 198 | 199 | void triggertable_parseflowgranularity(uint32_t flowgranularity, uint8_t* srcip_len, uint8_t* dstip_len, uint8_t* srcport_len, uint8_t* dstport_len, uint8_t* protocol_len); 200 | 201 | struct triggertype * triggertype_init(uint16_t id, trigger_update_func update_func, trigger_report_func report_func, trigger_apply_func free_func, trigger_apply_func reset_func, trigger_apply_func print_func, struct summary ** s, int summarynum, trigger_condition_func condition_func, uint32_t tickspersweep); 202 | void triggertype_finish(struct triggertype * type); 203 | 204 | void trigger_print2(struct trigger * t, void * aux); 205 | void trigger_print(struct trigger * t, void * aux); 206 | void trigger_cleantfl(struct trigger * t, struct triggertable * tt); 207 | 208 | /* 209 | * if the trigger matches the flow. Could be used for linear matching 210 | */ 211 | bool trigger_match(struct trigger * t, struct flow * f, struct flow * tempflow); 212 | 213 | struct trigger * counter_trigger_init(struct trigger * t, uint16_t eventid, struct flow * filter, struct flow * mask, struct triggertype * type, uint32_t threshold, uint16_t timeinterval); 214 | bool counter_trigger_report(struct trigger * t, uint32_t stepsback, char * buf); 215 | 216 | void counter_trigger_free(struct trigger * t, void * aux); 217 | void counter_trigger_reset(struct trigger * t, void * aux); 218 | void counter_trigger_print(struct trigger * t, void * aux); 219 | bool counter_trigger_condition(struct trigger * t); 220 | void counter_trigger_historyprint(struct trigger * t); 221 | 222 | void volume_trigger_update(struct trigger * t, void * d, struct triggertable * tt); 223 | void pktnum_trigger_update(struct trigger * t, void * d, struct triggertable * tt); 224 | void lossnum_trigger_update(struct trigger * t, void * d, struct triggertable * tt); 225 | void congestion_trigger_update(struct trigger * t, void * data __attribute__((unused)), struct triggertable * tt); 226 | //void congestion_trigger_reset(struct trigger * t, void * aux __attribute__((unused))); 227 | void burst_trigger_update(struct trigger * t, void * d, struct triggertable * tt); 228 | void burstloss_trigger_update(struct trigger * t, void * d, struct triggertable * tt); 229 | 230 | struct trigger * fgcounter_trigger_init(struct trigger * t, uint16_t eventid, struct flow * filter, struct flow * mask, struct triggertype * type, uint32_t flowgranularity, struct triggertype * triggertype, uint32_t threshold, uint16_t timeinterval); 231 | void fgcounter_trigger_reset(struct trigger * t, void * aux); 232 | void fgcounter_trigger_print(struct trigger * t, void * aux); 233 | bool fgcounter_trigger_condition(struct trigger * t); 234 | bool fgcounter_trigger_report(struct trigger * t, uint32_t stepsback, char * buf); 235 | void fgcounter_trigger_update(struct trigger * t, void * d, struct triggertable * tt); 236 | 237 | #endif /* triggertable2.h */ 238 | --------------------------------------------------------------------------------