├── .gitignore ├── README.md ├── backend ├── example.out ├── inputs │ └── readme.md ├── makefile ├── old │ ├── multi_kernel_bench │ │ ├── clfr_converter_main.cc │ │ ├── clfr_driver_main.cc │ │ ├── kernels │ │ │ ├── MurmerHash3.h │ │ │ ├── allstats_feature_calculator.h │ │ │ ├── benchmark_printer.h │ │ │ ├── clfr_counter.h │ │ │ ├── clfr_counter_chain.h │ │ │ ├── clfr_counter_replicated.h │ │ │ ├── clfr_reader copy.h │ │ │ ├── clfr_reader.h │ │ │ ├── cloner.h │ │ │ ├── counter.h │ │ │ ├── flat_hash_map.hpp │ │ │ ├── host_timing_profiler.h │ │ │ ├── ip_source_timestamps.h │ │ │ ├── join_printer.h │ │ │ ├── microburst_detector.h │ │ │ ├── microflow_reader.h │ │ │ ├── netflow_feature_calculator.h │ │ │ ├── pfe_feature_calculator.h │ │ │ ├── printer.h │ │ │ ├── redis_flow_subscriber.h │ │ │ ├── rich_feature_calculator.h │ │ │ ├── sink.h │ │ │ ├── starFlow.h │ │ │ └── tap.h │ │ └── readme.md │ └── single_kernel_bench │ │ ├── bin │ │ ├── allMetricsBenchmark.inp.py │ │ ├── benchmarkMetrics.sh │ │ ├── df.dat │ │ ├── starflow_app_benchmark │ │ └── turboflow_starflow_highlevel.numbers │ │ ├── inputparser.h │ │ ├── kernels │ │ ├── benchmark_printer.h │ │ ├── flat_hash_map.hpp │ │ ├── merged_all_metrics.h │ │ ├── microflow_reader.h │ │ └── starFlow.h │ │ ├── readme.md │ │ └── starflow_app_benchmark.cc ├── pin.sh ├── readme.md └── src │ ├── benchmark_main.cpp │ └── kernels │ ├── benchmark_printer.h │ ├── clfr_reader.h │ ├── clfr_writer.h │ ├── defs.h │ ├── feature_calculator.h │ ├── flat_hash_map.hpp │ ├── flow_rate.h │ ├── microburst_detector.h │ ├── microflow_reader.h │ ├── old │ ├── MurmerHash3.h │ ├── allstats_feature_calculator.h │ ├── benchmark_printer.h │ ├── clfr_counter.h │ ├── clfr_counter_chain.h │ ├── clfr_counter_replicated.h │ ├── clfr_reader copy.h │ ├── cloner.h │ ├── counter.h │ ├── flat_hash_map.hpp │ ├── host_timing_profiler.h │ ├── ip_source_timestamps.h │ ├── join_printer.h │ ├── microburst_detector.h │ ├── microflow_reader.h │ ├── netflow_feature_calculator.h │ ├── pfe_feature_calculator.h │ ├── printer.h │ ├── redis_flow_subscriber.h │ ├── rich_feature_calculator.h │ ├── sink.h │ ├── starFlow.h │ └── tap.h │ ├── packet_rate.h │ ├── sink.h │ └── starFlow.h └── cache ├── cModel ├── MurmerHash3.h ├── README.md ├── example.pcap ├── example.sh ├── makefile ├── starFlow.h ├── starflowModel └── starflowModel.cpp ├── p4Generic ├── README.md └── p4src │ ├── forwardL2.p4 │ ├── genPsuedocode.py │ ├── mainStarFlow.p4 │ ├── miscUtils.p4 │ ├── parser.p4 │ ├── starFlow.p4 │ └── statefulFunctions.p4 └── tofino ├── control ├── controlManager.py └── starFlowController.py └── p4src ├── forwardL2.p4 ├── mainStarFlow.p4 ├── miscUtils.p4 ├── parser.p4 └── starFlow.p4 /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## StarFlow 2 | 3 | **Update 8/26/20** RaftLib kernels that implement the StarFlow backend have been added to `/backend`, along with a program to benchmark it from in-memory datasets. 4 | 5 | **Update 8/21/20** The reference P4-tofino dataplane implementation has been added to /starflowCache/tofino. It originally ran on SDE 8.X. 6 | 7 | 8 | 9 | ### Contents 10 | cache/ -- dataplane component (multiple implementations). 11 | backend/ -- software backend and benchmarks. 12 | -------------------------------------------------------------------------------- /backend/inputs/readme.md: -------------------------------------------------------------------------------- 1 | ### Input datasets 2 | 3 | You can download input datasets (about 2.5GB) to use with the benchmarking program here: 4 | 5 | https://drive.google.com/drive/folders/1cZmwCv0IhNUmUSo18VtCDUSsPGD3JLAi?usp=sharing 6 | 7 | Put the files in ./inputs (filenames are hard-coded in the benchmarking program). 8 | 9 | - ``mCLFRs.32.bin`` -- a short micro-CLFR trace from a CAIDA dataset. 10 | 11 | - ``microburst.clfrs.bin`` -- a synthetic trace with microbursts, for benchmarking the microburst detector. 12 | 13 | -------------------------------------------------------------------------------- /backend/makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | LIBS= `pkg-config --libs raftlib` 4 | # LIBS= -L/usr/local/lib -lraft -lpthread -lshm -lrt -lnuma -laffinity -lpthread -ldemangle -lcmdargs 5 | 6 | # --unused libs-- 7 | # -lcmph -lpcap 8 | 9 | CFLAGS = `pkg-config --cflags raftlib` -O2 -fopt-info-vec-optimized -funroll-loops 10 | # CFLAGS = `pkg-config --cflags raftlib` 11 | # CFLAGS = -L/usr/local/lib -lraft -lpthread -lshm -lrt -lnuma -laffinity -lpthread -ldemangle -lcmdargs -Ofast -fopt-info-vec-optimized -funroll-loops 12 | 13 | # --unused flags (some from other projects) -- 14 | # CFLAGS = -std=c++14 -Ofast -fopt-info-vec-optimized 15 | # -std=c++14 -O3 -funroll-loops -mprefer-vector-width=512 -march=skylake-avx512 -fopt-info-vec-optimized #-mavx512f -mavx512dq -mavx512bw -mavx512vbmi -mavx512vbmi2 -mavx512vl 16 | 17 | CC = g++ 18 | 19 | objects = benchmark_main 20 | all: $(objects) 21 | 22 | $(objects): %: src/%.cpp 23 | $(CC) -o $@ $< $(LIBS) $(CFLAGS) 24 | 25 | clean: 26 | rm $(objects) -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/clfr_converter_main.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "kernels/microflow_reader.h" 6 | // #include "kernels/clfr_reader.h" 7 | #include "kernels/clfr_counter.h" 8 | 9 | #include "kernels/microburst_detector.h" 10 | 11 | #include "kernels/cloner.h" 12 | 13 | #include "kernels/clfr_counter_replicated.h" 14 | 15 | #include "kernels/benchmark_printer.h" 16 | 17 | #include "kernels/tap.h" 18 | #include "kernels/benchmark_printer.h" 19 | 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | 27 | void runReplicas(int N){ 28 | raft::map m; 29 | 30 | 31 | 32 | starflow::kernels::MicroflowReader * readers[N]; 33 | // starflow::kernels::ClfrCounterReplicated * counters[N]; 34 | starflow::kernels::ClfrCounter * counters[N]; 35 | starflow::kernels::BenchmarkPrinter logger(N); 36 | 37 | 38 | starflow::kernels::ClfrTap * taps[N]; 39 | // starflow::kernels::ClfrTap mfTap(N); 40 | for (int i=0; i(1); 42 | 43 | } 44 | 45 | for (int i=0; i> mfTap[std::to_string(i)]; 48 | 49 | readers[i] = new starflow::kernels::MicroflowReader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin"); 50 | // readers[i] = new starflow::kernels::MicroflowReader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin"); 51 | 52 | 53 | m += (*(readers[i]))["out"] >> (*(taps[(i/1)]))[std::to_string(i%1)]; 54 | // counters[i] = new starflow::kernels::ClfrCounterReplicated(i); 55 | // counters[i] = new starflow::kernels::ClfrCounter; 56 | 57 | // m += (*(readers[i]))["out"] >> (*(taps[i]))[std::to_string(i/2)]; 58 | // m += (*(readers[i]))["out"] >> *(counters[i]); 59 | m += (*(readers[i]))["stats"] >> logger[std::to_string(i)]; 60 | } 61 | 62 | m.exe(); 63 | 64 | } 65 | 66 | // counters[i] = new starflow::kernels::ClfrCounterReplicated(i); 67 | // m += *(readers[i]) >> *(counters[i]); 68 | 69 | void benchmarkReplicas(){ 70 | for (int i = 1; i<=32; i = i*2){ 71 | std::cout << "# testing " << i << " replicas" << endl; 72 | std::cout << "# ------------ " << endl; 73 | runReplicas(i); 74 | std::cout << "# ------------ " << endl; 75 | } 76 | 77 | } 78 | 79 | void runClones(int N){ 80 | raft::map m; 81 | // starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin.clfrs"); 82 | starflow::kernels::MicroflowReader reader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin"); 83 | 84 | // Clone CLFRs to multiple counters. 85 | starflow::kernels::ClfrCloner cloner(N); 86 | m += reader >> cloner; 87 | starflow::kernels::ClfrCounter counters[N]; 88 | for (int i = 0; i> counters[i]; 90 | } 91 | std::cout << "executing kernels." << endl; 92 | m.exe(); 93 | } 94 | 95 | 96 | int main(int argc, char** argv) 97 | { 98 | benchmarkReplicas(); 99 | return 0; 100 | // // runClones(3); 101 | // return 1; 102 | // runReplicas(1); 103 | // benchmarkReplicas(); 104 | // return 1; 105 | std::cout << "initializing kernels." << endl; 106 | // The kernel to read CLFRs. Emits CLFRs. 107 | // starflow::kernels::MicroflowReader reader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin"); 108 | // starflow::kernels::MicroflowReader reader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs_small2.bin"); 109 | starflow::kernels::MicroflowReader reader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin"); 110 | 111 | // A counter to process output from the reader. Does not emit anything. 112 | // The counter is typed by the kind of object it reads. 113 | starflow::kernels::ClfrCounter counter; 114 | // starflow::kernels::MicroburstDetector detector; 115 | std::cout << "executing kernels." << endl; 116 | // Connect the kernels and execute. 117 | raft::map m; 118 | starflow::kernels::BenchmarkPrinter logger(1); 119 | 120 | // m += reader >> counter; 121 | m += reader["out"] >> counter; 122 | m += reader["stats"] >> logger; 123 | m.exe(); 124 | // m += subscriber >> ip_source_timestamps >> sink; 125 | // m.exe(); 126 | 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/clfr_driver_main.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "kernels/microflow_reader.h" 6 | #include "kernels/clfr_reader.h" 7 | #include "kernels/clfr_counter.h" 8 | 9 | // Apps. 10 | // Profiler. 11 | #include "kernels/host_timing_profiler.h" 12 | 13 | // Feature calculators. 14 | #include "kernels/rich_feature_calculator.h" 15 | #include "kernels/netflow_feature_calculator.h" 16 | #include "kernels/pfe_feature_calculator.h" 17 | #include "kernels/allstats_feature_calculator.h" 18 | 19 | // Micro-burst detector. 20 | #include "kernels/microburst_detector.h" 21 | 22 | 23 | // Utilities. 24 | #include "kernels/cloner.h" 25 | 26 | #include "kernels/clfr_counter_chain.h" 27 | 28 | #include "kernels/clfr_counter_replicated.h" 29 | 30 | #include "kernels/benchmark_printer.h" 31 | 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | 39 | 40 | void runSimpleCounter(); 41 | void runHostProfiler(); 42 | void runClassifiers(); 43 | void runMicroburstDetector(); 44 | 45 | void runClones(int N); 46 | void runChains(int N); 47 | void runReplicas(int N); 48 | 49 | void benchmarkReplicas(); 50 | 51 | int main(int argc, char** argv) 52 | { 53 | benchmarkReplicas(); 54 | return 0; 55 | runSimpleCounter(); 56 | return 0; 57 | runClones(1); 58 | return 0; 59 | benchmarkReplicas(); 60 | 61 | // for (int i = 1; i<=64; i = i*2){ 62 | // std::cout << "testing " << i << " chain" << endl; 63 | // std::cout << " ------------ " << endl; 64 | // runChains(i); 65 | // std::cout << " ------------ " << endl; 66 | // } 67 | 68 | // for (int i = 1; i!=32; i = i*2){ 69 | // std::cout << "testing " << i << " clones" << endl; 70 | // std::cout << " ------------ " << endl; 71 | // runClones(i); 72 | // std::cout << " ------------ " << endl; 73 | // } 74 | return 0; 75 | } 76 | 77 | 78 | void runSimpleCounter(){ 79 | raft::map m; 80 | std::cout << "initializing kernels." << endl; 81 | // The kernel to read CLFRs. Emits CLFRs generated by converter. 82 | starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin.clfrs"); 83 | // starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin.clfrs"); 84 | starflow::kernels::ClfrCounter counter; 85 | m += reader >> counter; 86 | m.exe(); 87 | return; 88 | } 89 | 90 | 91 | void runHostProfiler(){ 92 | raft::map m; 93 | std::cout << "initializing kernels." << endl; 94 | starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin.clfrs"); 95 | starflow::kernels::HostProfiler profiler("/home/jsonch/gits/starflow_analytics/outputs/timingProfile.bin", 5 * 60 * 1000); 96 | m += reader >> profiler; 97 | m.exe(); 98 | return; 99 | } 100 | void runClassifiers(){ 101 | raft::map m; 102 | std::cout << "initializing kernels." << endl; 103 | starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin.clfrs"); 104 | // Compute clfr features. 105 | starflow::kernels::FeatureCalculator calculator; 106 | 107 | // Compute netflow features. 108 | // starflow::kernels::NetFlowFeatureCalculator calculator; 109 | 110 | // Compute PFE aggregatable features. 111 | // starflow::kernels::PFEFeatureCalculator calculator; 112 | 113 | // Compute complex aggregated stat features. 114 | // starflow::kernels::AllStatsFeatureCalculator calculator; 115 | // m += reader >> calculator; 116 | m += reader >> calculator; 117 | m.exe(); 118 | 119 | } 120 | void runMicroburstDetector(){ 121 | raft::map m; 122 | std::cout << "initializing kernels." << endl; 123 | starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/microburst.clfrs.bin"); 124 | 125 | starflow::kernels::MicroburstDetector detector; 126 | m += reader >> detector; 127 | m.exe(); 128 | } 129 | 130 | void runClones(int N){ 131 | raft::map m; 132 | starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin.clfrs"); 133 | 134 | // Clone CLFRs to multiple counters. 135 | starflow::kernels::ClfrCloner cloner(N); 136 | m += reader >> cloner; 137 | starflow::kernels::ClfrCounter counters[N]; 138 | for (int i = 0; i> counters[i]; 140 | } 141 | std::cout << "executing kernels." << endl; 142 | m.exe(); 143 | } 144 | 145 | 146 | void runChains(int N){ 147 | starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin.clfrs"); 148 | // starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin.clfrs"); 149 | std::cout << "N: " << N << std::endl; 150 | if (N > 1){ 151 | raft::map m; 152 | starflow::kernels::ClfrCounterChain counters[N-1]; 153 | m += reader >> counters[0]; 154 | for (int i = 0; i<(N-2); i++){ 155 | m += counters[i] >> counters[i+1]; 156 | } 157 | starflow::kernels::ClfrCounter counter; 158 | m += counters[N-2] >> counter; 159 | std::cout << "executing kernels." << endl; 160 | m.exe(); 161 | } 162 | else{ 163 | raft::map m; 164 | starflow::kernels::ClfrCounter counter; 165 | m += reader >> counter; 166 | std::cout << "executing kernels." << endl; 167 | m.exe(); 168 | } 169 | } 170 | 171 | void runReplicas(int N){ 172 | raft::map m; 173 | 174 | starflow::kernels::ClfrReader * readers[N]; 175 | // starflow::kernels::ClfrCounterReplicated * counters[N]; 176 | // starflow::kernels::NetFlowFeatureCalculator * sinks[N]; 177 | starflow::kernels::MicroburstDetector * sinks[N]; 178 | 179 | 180 | starflow::kernels::BenchmarkPrinter logger(N); 181 | 182 | for (int i=0; i(i); 186 | 187 | sinks[i] = new starflow::kernels::MicroburstDetector; 188 | m += *(readers[i]) >> *(sinks[i]); 189 | m += *(sinks[i]) >> logger[std::to_string(i)]; 190 | } 191 | 192 | m.exe(); 193 | 194 | } 195 | 196 | 197 | void benchmarkReplicas(){ 198 | for (int i = 1; i<=16; i = i*2){ 199 | std::cout << "testing " << i << " replicas" << endl; 200 | std::cout << " ------------ " << endl; 201 | runReplicas(i); 202 | std::cout << " ------------ " << endl; 203 | } 204 | 205 | } 206 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/benchmark_printer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_BENCHMARK_PRINTER 3 | #define STARFLOW_KERNELS_BENCHMARK_PRINTER 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | #include 15 | 16 | namespace starflow { 17 | namespace kernels { 18 | template 19 | class BenchmarkPrinter : public raft::kernel 20 | { 21 | public: 22 | // Tracks and summarizes throughput stats from multiple ports. 23 | #define BENCHMARK_CT 1000000 24 | 25 | int inC; 26 | 27 | std::unordered_map portStats; 28 | int ctr = 0; 29 | explicit BenchmarkPrinter(int inputPortCt) 30 | : raft::kernel() 31 | { 32 | inC = inputPortCt; 33 | // Configure the stream processing outputs. 34 | for (int i=0; i(std::to_string(i)); 38 | } 39 | } 40 | 41 | raft::kstatus run() override 42 | { 43 | 44 | cout << std::fixed << "stats[" << ctr << "]=["; 45 | double combined = 0; 46 | for (int i = 0; i 6 | #include 7 | using namespace std; 8 | using namespace std::chrono; 9 | 10 | 11 | 12 | namespace starflow { 13 | namespace kernels { 14 | template 15 | class ClfrCounter : public raft::kernel 16 | { 17 | // Counts CLFRs, gives periodic statistic updates. 18 | #define BENCHMARK_CT 1000000 19 | 20 | 21 | public: 22 | high_resolution_clock::time_point last, cur; 23 | 24 | uint64_t counter=0; 25 | uint64_t flowCounter = 0; 26 | uint64_t pktCounter = 0; 27 | explicit ClfrCounter() 28 | : raft::kernel() 29 | { 30 | last = high_resolution_clock::now(); 31 | input.template add_port("in"); 32 | } 33 | 34 | raft::kstatus run() override 35 | { 36 | 37 | // some black magic to get a refrecne to the CLFR batch object. 38 | auto &clfrVector(input["in"].template peek()); 39 | counter+= clfrVector.size(); 40 | flowCounter+= clfrVector.size(); 41 | for (auto rec : clfrVector){ 42 | pktCounter += rec.second.packetVector.size(); 43 | } 44 | // std::cout << clfr.timeStamps[0] << endl; 45 | 46 | // input["in"].unpeek(); // unpeek if it remains in the stream. 47 | input["in"].recycle(); // recycle to move to next item. 48 | 49 | // std::cout << "counter: " << counter << std::endl; 50 | if (counter > BENCHMARK_CT){ 51 | // std::cout << "read " << counter << " CLFRs " << endl; 52 | // report throughput. 53 | // cur = high_resolution_clock::now(); 54 | // auto duration = duration_cast( cur - last ).count(); 55 | // std::cout << std::fixed << "time to get " << BENCHMARK_CT << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 56 | // std::cout << "packet count: " << pktCounter << " CLFR count: " << flowCounter << endl; 57 | // counter = 0; 58 | // last = high_resolution_clock::now(); 59 | } 60 | 61 | return (raft::proceed); 62 | } 63 | }; 64 | } 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/clfr_counter_chain.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_COUNTER_CHAIN 3 | #define STARFLOW_KERNELS_CLFR_COUNTER_CHAIN 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | using namespace std::chrono; 9 | 10 | 11 | 12 | namespace starflow { 13 | namespace kernels { 14 | template 15 | class ClfrCounterChain : public raft::kernel 16 | { 17 | // Counts CLFRs, gives periodic statistic updates. 18 | #define BENCHMARK_CT 1000000 19 | 20 | 21 | public: 22 | high_resolution_clock::time_point last, cur; 23 | uint64_t counter=0; 24 | explicit ClfrCounterChain() 25 | : raft::kernel() 26 | { 27 | last = high_resolution_clock::now(); 28 | input.template add_port("in"); 29 | output.template add_port("out"); 30 | } 31 | 32 | raft::kstatus run() override 33 | { 34 | 35 | // some black magic to get a refrecne to the CLFR batch object. 36 | auto &clfrVector(input["in"].template peek()); 37 | counter+= clfrVector.size(); 38 | // std::cout << clfr.timeStamps[0] << endl; 39 | 40 | // Send to next counter. 41 | auto out( output["out"].template allocate_s() ); 42 | (*out) = clfrVector; 43 | 44 | // input["in"].unpeek(); // unpeek if it remains in the stream. 45 | input["in"].recycle(); // recycle to move to next item. 46 | 47 | 48 | // std::cout << "counter: " << counter << std::endl; 49 | if (counter > BENCHMARK_CT){ 50 | // std::cout << "read " << counter << " CLFRs " << endl; 51 | // report throughput. 52 | cur = high_resolution_clock::now(); 53 | auto duration = duration_cast( cur - last ).count(); 54 | // if (doPrint){ 55 | // std::cout << std::fixed << "time to get " << BENCHMARK_CT << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 56 | // } 57 | counter = 0; 58 | last = high_resolution_clock::now(); 59 | } 60 | 61 | return (raft::proceed); 62 | } 63 | }; 64 | } 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/clfr_counter_replicated.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_COUNTER_REPLICATED 3 | #define STARFLOW_KERNELS_CLFR_COUNTER_REPLICATED 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | using namespace std::chrono; 9 | 10 | 11 | 12 | namespace starflow { 13 | namespace kernels { 14 | template 15 | class ClfrCounterReplicated : public raft::kernel 16 | { 17 | // Counts CLFRs, gives periodic statistic updates. 18 | #define BENCHMARK_CT 1000000 19 | 20 | 21 | public: 22 | int replicaId; 23 | high_resolution_clock::time_point last, cur; 24 | 25 | uint64_t counter=0; 26 | uint64_t total = 0; 27 | explicit ClfrCounterReplicated(int rid) 28 | : raft::kernel() 29 | { 30 | replicaId = rid; 31 | last = high_resolution_clock::now(); 32 | input.template add_port("in"); 33 | output.template add_port("stats"); 34 | } 35 | 36 | raft::kstatus run() override 37 | { 38 | if ((total == 0) && (counter == 0)) 39 | last = high_resolution_clock::now(); 40 | 41 | // some black magic to get a refrecne to the CLFR batch object. 42 | auto &clfrVector(input["in"].template peek()); 43 | counter+= clfrVector.size(); 44 | // std::cout << clfr.timeStamps[0] << endl; 45 | 46 | // input["in"].unpeek(); // unpeek if it remains in the stream. 47 | input["in"].recycle(); // recycle to move to next item. 48 | 49 | // std::cout << "counter: " << counter << std::endl; 50 | if (counter > BENCHMARK_CT){ 51 | total += counter; 52 | // std::cout << "read " << counter << " CLFRs " << endl; 53 | // report throughput. 54 | cur = high_resolution_clock::now(); 55 | auto duration = duration_cast( cur - last ).count(); 56 | // std::cout << "replica id: " << replicaId << std::fixed << " time to get " << total << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(total)/float(duration)) << std::endl; 57 | counter =0; 58 | // Push latest throughput value to stat tracker. 59 | output["stats"].push(1000.0*(float(total)/float(duration))); 60 | } 61 | 62 | return (raft::proceed); 63 | } 64 | }; 65 | } 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/clfr_reader copy.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_READER 3 | #define STARFLOW_KERNELS_CLFR_READER 4 | 5 | #include "starFlow.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | 15 | #include "flat_hash_map.hpp" 16 | 17 | #define BATCH_SIZE_READER 100 18 | 19 | namespace starflow { 20 | namespace kernels { 21 | class ClfrReader : public raft::kernel 22 | { 23 | public: 24 | 25 | char * inBuf; // Buffer for CLFRs to replay. 26 | char * bufPos; 27 | char * bufEnd; 28 | 29 | // output type: what the kernel emits. 30 | // A batch of CLFRs. 31 | using output_t = std::vector>; 32 | 33 | // ptr to a reference. 34 | std::vector> * batchVec = NULL; 35 | 36 | // for profiling. 37 | high_resolution_clock::time_point last, cur; 38 | 39 | // Load the eval data set into RAM. This would be done by the NIC. 40 | void loadClfrs(const char *inFile){ 41 | FILE *f = fopen(inFile, "rb"); 42 | fseek(f, 0, SEEK_END); 43 | long f_sz = ftell(f); 44 | fseek(f, 0, SEEK_SET); 45 | std::cout << "loading " << f_sz << " bytes of CLFRs." << std::endl; 46 | inBuf = (char *) malloc(f_sz); 47 | std::cout << "finished mallocing" << std::endl; 48 | fread((char *)inBuf, f_sz, 1, f); 49 | fclose(f); 50 | std::cout << "finished reading" << std::endl; 51 | bufPos = inBuf; 52 | bufEnd = inBuf + f_sz; 53 | } 54 | 55 | ClfrReader(const std::string& fn) : raft::kernel() 56 | { 57 | last = high_resolution_clock::now(); 58 | 59 | // Load microflows in. 60 | loadClfrs(fn.c_str()); 61 | 62 | // Configure the stream processing outputs. 63 | output.template add_port("out"); 64 | } 65 | 66 | void sendBatch(){ 67 | // Send the output vector. 68 | output["out"].send(); 69 | // Get new batch vec. 70 | auto &out( output["out"].template allocate() ); 71 | batchVec = &out; 72 | batchVec->reserve(BATCH_SIZE_READER); 73 | } 74 | 75 | raft::kstatus run() override 76 | { 77 | if (batchVec == NULL){ 78 | // Get new batch vec. 79 | auto &out( output["out"].template allocate() ); 80 | batchVec = &out; 81 | batchVec->reserve(BATCH_SIZE_READER); 82 | } 83 | 84 | uint64_t ctr = 0; 85 | // Parse CLFRs, fill, send. 86 | while (bufPosemplace_back(keyStr, val); 103 | // Send. 104 | if (batchVec->size() > BATCH_SIZE_READER){ 105 | sendBatch(); 106 | } 107 | } 108 | // std::cout << "done replaying CLFRs." << std::endl; 109 | output["out"].send(); 110 | return (raft::stop); 111 | // exit(0); 112 | 113 | // Return / push. 114 | return (raft::proceed); 115 | } 116 | }; 117 | } 118 | } 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/clfr_reader.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_READER 3 | #define STARFLOW_KERNELS_CLFR_READER 4 | 5 | #include "starFlow.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | 15 | #include "flat_hash_map.hpp" 16 | 17 | #define BATCH_SIZE_READER 300 18 | 19 | namespace starflow { 20 | namespace kernels { 21 | class ClfrReader : public raft::kernel 22 | { 23 | public: 24 | 25 | char * inBuf; // Buffer for CLFRs to replay. 26 | char * bufPos; 27 | char * bufEnd; 28 | 29 | // output type: what the kernel emits. 30 | // A batch of CLFRs. 31 | using output_t = std::vector>; 32 | 33 | // ptr to a reference. 34 | std::vector> * batchVec = NULL; 35 | 36 | // for profiling. 37 | high_resolution_clock::time_point last, cur; 38 | 39 | // Load the eval data set into RAM. This would be done by the NIC. 40 | void loadClfrs(const char *inFile){ 41 | FILE *f = fopen(inFile, "rb"); 42 | fseek(f, 0, SEEK_END); 43 | long f_sz = ftell(f); 44 | fseek(f, 0, SEEK_SET); 45 | std::cout << "loading " << f_sz << " bytes of CLFRs." << std::endl; 46 | inBuf = (char *) malloc(f_sz); 47 | std::cout << "finished mallocing" << std::endl; 48 | fread((char *)inBuf, f_sz, 1, f); 49 | fclose(f); 50 | std::cout << "finished reading" << std::endl; 51 | bufPos = inBuf; 52 | bufEnd = inBuf + f_sz; 53 | } 54 | 55 | ClfrReader(const std::string& fn) : raft::kernel() 56 | { 57 | last = high_resolution_clock::now(); 58 | 59 | // Load microflows in. 60 | loadClfrs(fn.c_str()); 61 | 62 | // Configure the stream processing outputs. 63 | output.template add_port("out"); 64 | } 65 | 66 | void sendBatch(){ 67 | // Send the output vector. 68 | output["out"].send(); 69 | // Get new batch vec. 70 | auto &out( output["out"].template allocate() ); 71 | batchVec = &out; 72 | batchVec->reserve(BATCH_SIZE_READER); 73 | } 74 | 75 | raft::kstatus run() override 76 | { 77 | if (batchVec == NULL){ 78 | // Get new batch vec. 79 | auto &out( output["out"].template allocate() ); 80 | batchVec = &out; 81 | batchVec->reserve(BATCH_SIZE_READER); 82 | } 83 | 84 | uint64_t ctr = 0; 85 | // Parse CLFRs, fill, send. 86 | while (bufPosemplace_back(keyStr, val); 103 | // Send. 104 | if (batchVec->size() > BATCH_SIZE_READER){ 105 | sendBatch(); 106 | } 107 | } 108 | // std::cout << "done replaying CLFRs." << std::endl; 109 | output["out"].send(); 110 | return (raft::stop); 111 | // exit(0); 112 | 113 | // Return / push. 114 | return (raft::proceed); 115 | } 116 | }; 117 | } 118 | } 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/cloner.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_CLONER 3 | #define STARFLOW_KERNELS_CLFR_CLONER 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | 15 | 16 | 17 | namespace starflow { 18 | namespace kernels { 19 | template 20 | class ClfrCloner : public raft::kernel 21 | { 22 | public: 23 | // Counts CLFRs, gives periodic statistic updates. 24 | #define BENCHMARK_CT 1000000 25 | high_resolution_clock::time_point last, cur; 26 | 27 | int outC; 28 | 29 | uint64_t counter=0; 30 | explicit ClfrCloner(int outputPortCt) 31 | : raft::kernel() 32 | { 33 | outC = outputPortCt; 34 | last = high_resolution_clock::now(); 35 | input.template addPort("in"); 36 | // Configure the stream processing outputs. 37 | for (int i=0; i(std::to_string(i)); 40 | } 41 | } 42 | 43 | raft::kstatus run() override 44 | { 45 | 46 | // some black magic to get a refrecne to the CLFR batch object. 47 | auto &clfrVector(input["in"].template peek()); 48 | counter+= clfrVector.size(); 49 | // std::cout << clfr.timeStamps[0] << endl; 50 | 51 | for (int i = 0; i() ); 53 | auto out( output[std::to_string(i)].template allocate_s() ); 54 | (*out) = clfrVector; 55 | // output[std::to_string(i)].send(); 56 | } 57 | 58 | // input["in"].unpeek(); // unpeek if it remains in the stream. 59 | input["in"].recycle(); // recycle to move to next item. 60 | 61 | // std::cout << "counter: " << counter << std::endl; 62 | if (counter > BENCHMARK_CT){ 63 | // std::cout << "read " << counter << " CLFRs " << endl; 64 | // report throughput. 65 | cur = high_resolution_clock::now(); 66 | auto duration = duration_cast( cur - last ).count(); 67 | std::cout << std::fixed << "# outputs: " << outC << " time to clone: " << BENCHMARK_CT << " clfrs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 68 | counter = 0; 69 | last = high_resolution_clock::now(); 70 | } 71 | 72 | return (raft::proceed); 73 | } 74 | }; 75 | } 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/counter.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_COUNTER 3 | #define STARFLOW_KERNELS_COUNTER 4 | 5 | namespace starflow { 6 | namespace kernels { 7 | template 8 | class Counter : public raft::kernel 9 | { 10 | public: 11 | Counter() : raft::kernel() 12 | { 13 | input.template add_port("in"); 14 | output.add_port("out"); 15 | } 16 | 17 | raft::kstatus run() override 18 | { 19 | T t; 20 | input["in"].pop(t); 21 | 22 | auto out(output["out"].template allocate_s()); 23 | *out = ++_counter; 24 | 25 | return(raft::proceed); 26 | } 27 | 28 | private: 29 | unsigned long long _counter = 0; 30 | }; 31 | } 32 | } 33 | 34 | 35 | #endif -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/host_timing_profiler.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_HOST_PROFILER 3 | #define STARFLOW_KERNELS_HOST_PROFILER 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | using namespace std::chrono; 12 | 13 | #include "flat_hash_map.hpp" 14 | 15 | // Builds a timing profile of each monitored source address. 16 | // (example 1) 17 | 18 | #define DUMP 1 19 | #define STATS 1 20 | #define BENCHMARK 1 21 | #define BENCHMARK_CT 1000000 22 | 23 | 24 | 25 | namespace starflow { 26 | namespace kernels { 27 | template 28 | class HostProfiler : public raft::kernel 29 | { 30 | public: 31 | const char * outFileName; 32 | uint32_t profileDuration = 0; 33 | 34 | high_resolution_clock::time_point last, cur, start, end; 35 | ska::flat_hash_map> hostTimes; 36 | std::vector blankValue; 37 | uint32_t startTs = 0; 38 | uint32_t endTs = 0; 39 | 40 | 41 | uint64_t counter=0; 42 | 43 | // input: profile dump file name, duration of profile (ms). 44 | explicit HostProfiler(const char *of, uint32_t profDur) 45 | : raft::kernel() 46 | { 47 | outFileName = of; 48 | profileDuration = profDur; 49 | last = high_resolution_clock::now(); 50 | start = high_resolution_clock::now(); 51 | input.template add_port("in"); 52 | } 53 | 54 | // Dump profile. Format: host ip, # arrivals, timestamps (all uint_64) 55 | void dumpProfile(){ 56 | std::cout << "dumping profile to: " << outFileName << std::endl; 57 | ofstream o; 58 | o.open(outFileName, ios::binary); 59 | uint64_t tsesWritten = 0; 60 | for (auto kv : hostTimes){ 61 | uint32_t hostIp = kv.first; 62 | uint32_t tsCt = uint32_t(kv.second.size()); 63 | o.write((char *) &hostIp, sizeof(hostIp)); 64 | o.write((char *) &tsCt, sizeof(tsCt)); 65 | for (auto ts : kv.second){ 66 | o.write((char *) &ts, sizeof(ts)); 67 | tsesWritten++; 68 | } 69 | } 70 | o.close(); 71 | std::cout << "\twrote " << tsesWritten << " timestamps" << std::endl; 72 | } 73 | 74 | raft::kstatus run() override 75 | { 76 | // get a referecne to the CLFR batch object. 77 | auto &clfrVector(input["in"].template peek()); 78 | // handle a batch. 79 | for (auto kv : clfrVector){ 80 | // key is src addr. 81 | uint32_t key = *((uint32_t *) &(kv.first.c_str()[4])); 82 | 83 | auto got = hostTimes.find(key); 84 | if (got == hostTimes.end()){ 85 | hostTimes[key] = blankValue; 86 | got = hostTimes.find(key); 87 | } 88 | // update profile. 89 | for (auto pfs : kv.second.packetVector){ 90 | got->second.push_back(pfs.ts); 91 | #ifdef STATS 92 | endTs = max(pfs.ts, endTs); 93 | #endif 94 | } 95 | } 96 | 97 | // handleBatch(clfrVector); 98 | 99 | input["in"].recycle(); // recycle to move to next item. 100 | 101 | // for benchmarking. 102 | #ifdef BENCHMARK 103 | counter+= clfrVector.size(); 104 | 105 | if (counter > BENCHMARK_CT){ 106 | // std::cout << "read " << counter << " CLFRs " << endl; 107 | // report throughput. 108 | cur = high_resolution_clock::now(); 109 | auto duration = duration_cast( cur - last ).count(); 110 | std::cout << std::fixed << "time to gen host profiles with " << BENCHMARK_CT << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 111 | counter = 0; 112 | last = high_resolution_clock::now(); 113 | 114 | #ifdef STATS 115 | std::cout << "number of hosts: " << hostTimes.size() << " time interval represented: " << (endTs - startTs)/1000.0 << " (ms)" << std::endl; 116 | #endif 117 | 118 | } 119 | #endif 120 | 121 | #ifdef DUMP 122 | // Dump profile and exit (entire app for now). 123 | if ((endTs - startTs) > (profileDuration*1000)){ 124 | end = high_resolution_clock::now(); 125 | auto duration = duration_cast( end - start ).count(); 126 | std::cout << "total time to get profile: " << duration << " ms" << std::endl; 127 | dumpProfile(); 128 | // return (raft::stop); 129 | exit(0); 130 | 131 | } 132 | #endif 133 | 134 | return (raft::proceed); 135 | } 136 | 137 | // void handleBatch(std::vector batchVector){ 138 | 139 | // } 140 | 141 | 142 | }; 143 | } 144 | } 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/ip_source_timestamps.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_IP_SOURCE_TIMESTAMPS 3 | #define STARFLOW_KERNELS_IP_SOURCE_TIMESTAMPS 4 | 5 | #include 6 | #include 7 | #include 8 | #include "../flow.h" 9 | #include "../flow_table.h" 10 | 11 | namespace starflow { 12 | namespace kernels { 13 | class IPSourceTimestamps : public raft::kernel 14 | { 15 | public: 16 | 17 | using input_t = std::pair; 18 | using output_t = std::pair>; 19 | 20 | IPSourceTimestamps() : raft::kernel() 21 | { 22 | input.add_port("in"); 23 | output.add_port("out"); 24 | } 25 | 26 | raft::kstatus run() override 27 | { 28 | input_t flow; 29 | input["in"].pop(flow); 30 | 31 | std::list timestamps; 32 | 33 | for (auto& packet : flow.second.packets()) 34 | timestamps.push_back(packet.ts); 35 | 36 | auto out(output["out"].allocate_s()); 37 | auto pair = std::make_pair(flow.first.ip_src, timestamps); 38 | *out = pair; 39 | 40 | std::cout << to_string(pair) << std::endl; 41 | 42 | return(raft::proceed); 43 | } 44 | 45 | static std::string to_string(const output_t& p) 46 | { 47 | std::stringstream ss; 48 | ss << FlowTable::uint32_ip_addr_to_str(p.first) << ":"; 49 | 50 | for (auto& ts : p.second) 51 | ss << " " << ts.count(); 52 | 53 | return ss.str(); 54 | } 55 | }; 56 | } 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/join_printer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_PRINTER 3 | #define STARFLOW_KERNELS_PRINTER 4 | 5 | #include 6 | 7 | namespace starflow { 8 | namespace kernels { 9 | template 10 | class Printer : public raft::kernel 11 | { 12 | public: 13 | explicit Printer(std::ostream& os = std::cout, bool endl = true, bool forward = false) 14 | : raft::kernel(), 15 | _os(os), 16 | _endl(endl), 17 | _forward(forward) 18 | { 19 | input.template add_port("in"); 20 | if (_forward) 21 | output.template add_port("out"); 22 | } 23 | 24 | raft::kstatus run() override 25 | { 26 | T t{}; 27 | input["in"].pop(t); 28 | _os << t << (_endl ? '\n' : '\0'); 29 | 30 | if (_forward) { 31 | auto out(output["out"].template allocate_s()); 32 | *out = t; 33 | } 34 | 35 | return (raft::proceed); 36 | } 37 | 38 | private: 39 | std::ostream& _os; 40 | bool _endl; 41 | bool _forward; 42 | }; 43 | } 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/microburst_detector.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_MICROBURST_DETECTOR 3 | #define STARFLOW_KERNELS_MICROBURST_DETECTOR 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | using namespace std::chrono; 14 | 15 | 16 | // Identifies the hosts responsible for microbursts. 17 | 18 | #define BENCHMARK_CT_MICROBURST 10000 19 | 20 | #ifndef UINT32_MAX 21 | #define UINT32_MAX (0xffffffff) 22 | #endif 23 | 24 | namespace starflow { 25 | namespace kernels { 26 | 27 | // Data structure to cache flows until they can no longer have packets in the queue. 28 | typedef std::pair CLFR_PAIR_TYPE; 29 | struct CLFR_Pair_comp { 30 | bool operator() (const CLFR_PAIR_TYPE lhs, const CLFR_PAIR_TYPE rhs) const 31 | {return lhs.second.packetVector.back().ts < rhs.second.packetVector.back().ts;} 32 | }; 33 | 34 | typedef std::pair PKT_PAIR_TYPE; 35 | // Data structure to reconstruct the queue at the point in time when a drop happened. 36 | struct Pkt_Pair_comp { 37 | bool operator() (const PKT_PAIR_TYPE lhs, const PKT_PAIR_TYPE rhs) const 38 | {return lhs.second.ts < rhs.second.ts;} 39 | }; 40 | 41 | template 42 | class MicroburstDetector : public raft::kernel 43 | { 44 | public: 45 | std::multiset orderedCache; 46 | CLFR_PAIR_TYPE blankClfrPair; 47 | std::multiset reconstructedQueue; 48 | PKT_PAIR_TYPE blankPktPair; 49 | 50 | // Which packets of each flow are currently in the reconstructed queue. 51 | std::unordered_map startPktIdx; 52 | 53 | uint16_t queueThreshold = 20; 54 | uint16_t lastQueueSize = 0; 55 | 56 | uint64_t counter=0; 57 | 58 | high_resolution_clock::time_point last, cur; 59 | 60 | explicit MicroburstDetector() 61 | : raft::kernel() 62 | { 63 | last = high_resolution_clock::now(); 64 | input.template add_port("in"); 65 | } 66 | 67 | // enqueue packets that arrived before endtime in all currently active flows. 68 | void updateQueue(uint32_t endTime){ 69 | // int oldQueueSize = reconstructedQueue.size(); 70 | for (auto kv : orderedCache){ 71 | startPktIdx.emplace(kv.first, 0); 72 | // update which packets from this flow are in the queue. 73 | for (int idx = startPktIdx[kv.first]; idx endTime){ 76 | startPktIdx[kv.first] = idx; // where to start in next update on this flow. 77 | break; 78 | } 79 | 80 | // place packet into queue reconstructor. 81 | reconstructedQueue.emplace(*(uint32_t *)(kv.first.c_str()), p); 82 | } 83 | } 84 | // cout << "\tinserted " << reconstructedQueue.size()-oldQueueSize << " packets into queue" << endl; 85 | } 86 | 87 | // arrive by start time, sort by end time. 88 | raft::kstatus run() override 89 | { 90 | // get a ref to the clfr batch. 91 | auto &clfrVector(input["in"].template peek()); 92 | counter+= clfrVector.size(); 93 | 94 | for (auto kv : clfrVector){ 95 | // Insert into cache. 96 | orderedCache.insert(kv); 97 | 98 | // calculate max queue size. 99 | uint16_t localMaxSize = 0; 100 | uint32_t localMaxTime = 0; 101 | uint32_t sizeTally =0; 102 | uint32_t numAboveThreshold = 0; 103 | for (auto p : kv.second.packetVector){ 104 | if (p.queueSize > localMaxSize){ 105 | localMaxSize = p.queueSize; 106 | localMaxTime = p.ts; 107 | } 108 | sizeTally+=p.queueSize; 109 | if (p.queueSize ==24){ 110 | numAboveThreshold++; 111 | } 112 | } 113 | double avgSize = double(sizeTally) / double(kv.second.packetVector.size()); 114 | double pctAboveThreshold = double(numAboveThreshold) / double(kv.second.packetVector.size()); 115 | // do queue processing for important flows. 116 | uint32_t src = *(uint32_t *)(kv.first.c_str()); 117 | if (src > 20){ 118 | cout << "timeseries[" << kv.second.packetVector[0].ts << "]=" << pctAboveThreshold<= queueThreshold){ 123 | // cout << "\tqueue threshold (" << queueThreshold << ") reached!" << endl; 124 | updateQueue(localMaxTime); 125 | 126 | // walk back from end of queue to find out what sources are the cause. 127 | std::vector packetSrcsInQueue; 128 | for (auto rit = reconstructedQueue.rbegin(); rit!= reconstructedQueue.rend(); ++rit){ 129 | packetSrcsInQueue.push_back((*rit).first); 130 | if (packetSrcsInQueue.size() >= localMaxSize){ 131 | break; 132 | } 133 | } 134 | std::unordered_set uniqueOffenders; 135 | for (auto h : packetSrcsInQueue){ 136 | uniqueOffenders.insert(h); 137 | } 138 | // cout << " , " << uniqueOffenders.size(); 139 | // cout << "\tHosts in queue:"; 140 | cout << "occupants["< nv; 156 | nv.push_back(kv.second.packetVector[0]); 157 | blankClfrPair.second.packetVector = nv; 158 | auto maxOldFlowIt = orderedCache.lower_bound(blankClfrPair); 159 | orderedCache.erase(orderedCache.begin(), maxOldFlowIt); 160 | 161 | // remove packets from reconstructed queue before current flow start time. 162 | blankPktPair.second.ts = kv.second.packetVector[0].ts; 163 | // (neither could be responsible for high queue sizes that future flows observe). 164 | auto maxOldPktIt = reconstructedQueue.lower_bound(blankPktPair); 165 | reconstructedQueue.erase(reconstructedQueue.begin(), maxOldPktIt); 166 | 167 | // cout << "flow cache size: " << orderedCache.size() << " reconstructedQueue size: " << reconstructedQueue.size() << endl; 168 | } 169 | 170 | input["in"].recycle(); // recycle to move to next item. 171 | 172 | // std::cout << "counter: " << counter << std::endl; 173 | if (counter > BENCHMARK_CT_MICROBURST){ 174 | // std::cout << "read " << counter << " CLFRs " << endl; 175 | // report throughput. 176 | cur = high_resolution_clock::now(); 177 | auto duration = duration_cast( cur - last ).count(); 178 | // std::cout << std::fixed << "time to process " << BENCHMARK_CT_MICROBURST << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 179 | counter = 0; 180 | last = high_resolution_clock::now(); 181 | } 182 | 183 | return (raft::proceed); 184 | } 185 | }; 186 | } 187 | } 188 | 189 | #endif 190 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/microflow_reader.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_MICROFLOW_READER 3 | #define STARFLOW_KERNELS_MICROFLOW_READER 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "starFlow.h" 15 | #include 16 | #include 17 | #include 18 | #include // std::max 19 | 20 | #include 21 | using namespace std; 22 | using namespace std::chrono; 23 | 24 | 25 | #include "flat_hash_map.hpp" 26 | 27 | 28 | #define BATCH_SIZE 200 29 | #define MF_BATCH_SIZE 500 30 | 31 | 32 | // #define DUMPCLFRS 1 33 | 34 | #define BENCHMARK 1 35 | #define BENCHMARK_CT 1000000 36 | 37 | namespace starflow { 38 | namespace kernels { 39 | class MicroflowReader : public raft::kernel 40 | { 41 | 42 | 43 | public: 44 | // output type: what the kernel emits. 45 | // A batch of CLFRs. 46 | using output_t = std::vector>; 47 | // ptr to output batch vector. 48 | std::vector> * batchVec = NULL; 49 | 50 | char * inBuf, * bufPos, * bufEnd; // Buffer where microflows from PFEs end up. 51 | 52 | // A map of CLFRs. 53 | ska::flat_hash_map CLFR_flatmap; 54 | CLFR_Value blankValue; 55 | 56 | // Timeout stuff, in usec. 57 | uint32_t timeoutCheckPeriod = 5000*1000; // 5 seconds. 58 | uint32_t timeoutThreshold = 10000*1000; // 10 seconds. 59 | uint32_t curTs = 0; 60 | uint32_t lastCheckTs = 0; 61 | 62 | 63 | // for profiling. 64 | high_resolution_clock::time_point last, cur; 65 | uint64_t mfCt = 0; 66 | uint64_t totalMfCt = 0; 67 | uint64_t finCt = 0; 68 | uint64_t timeoutCt = 0; 69 | 70 | uint64_t tmpCtr = 0; 71 | uint64_t lastMfCt = 0; 72 | 73 | uint64_t finalMfCt = 0; 74 | uint64_t finalClfrCt = 0; 75 | 76 | uint64_t total = 0; 77 | // for dumping CLFRs, if set. 78 | ofstream o; 79 | 80 | // long f_sz; 81 | // void * mmappedData; 82 | 83 | // void loadMicroflows(const char *inFile){ 84 | // FILE *f = fopen(inFile, "rb"); 85 | // fseek(f, 0, SEEK_END); 86 | // f_sz = ftell(f); 87 | // fseek(f, 0, SEEK_SET); 88 | 89 | // #define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) 90 | 91 | // int flags = MAP_PRIVATE | MAP_POPULATE; 92 | // mmappedData = mmap(NULL, f_sz, PROT_READ, FLAGS, 0, 0); 93 | // if (mmappedData == MAP_FAILED) { 94 | // perror("mmap"); 95 | // exit(1); 96 | // } 97 | // // assert(mmappedData != MAP_FAILED); 98 | // // int rc = madvise(mmappedData, f_sz, MADV_SEQUENTIAL); 99 | // // if (rc != 0) 100 | // // perror("madvise"); 101 | // // assert(rc == 0); 102 | // inBuf = (char *) mmappedData; 103 | // fread((char *)inBuf, f_sz, 1, f); 104 | // fclose(f); 105 | 106 | // bufPos = inBuf; 107 | // bufEnd = inBuf + f_sz; 108 | // std::cout << "ret from main" << endl; 109 | // } 110 | 111 | // Load the eval data set into RAM. This would be done by the NIC. 112 | void loadMicroflows(const char *inFile){ 113 | 114 | FILE *f = fopen(inFile, "rb"); 115 | fseek(f, 0, SEEK_END); 116 | long f_sz = ftell(f); 117 | fseek(f, 0, SEEK_SET); 118 | // std::cout << "loading " << f_sz << " bytes of microflows." << std::endl; 119 | inBuf = (char *) malloc(f_sz); 120 | // std::cout << "finished mallocing" << std::endl; 121 | fread((char *)inBuf, f_sz, 1, f); 122 | fclose(f); 123 | // std::cout << "finished reading" << std::endl; 124 | bufPos = inBuf; 125 | bufEnd = inBuf + f_sz; 126 | } 127 | 128 | MicroflowReader(const std::string& fn) : raft::kernel() 129 | { 130 | 131 | // Load microflows in. 132 | loadMicroflows(fn.c_str()); 133 | // Read metadata (# of microflows. ) 134 | ifstream insz; 135 | insz.open(fn + std::string(".len"), ios::binary); 136 | insz.read((char*)&totalMfCt, sizeof(totalMfCt)); 137 | insz.close(); 138 | // std::cout << "looping " << totalMfCt << " mCLFRs" << endl; 139 | 140 | // Configure the stream processing outputs. 141 | output.template addPort("out"); 142 | 143 | output.template addPort("stats"); 144 | 145 | CLFR_flatmap.reserve(234141); 146 | 147 | blankValue.flowFeatures = {0}; 148 | blankValue.packetVector.reserve(4); 149 | #ifdef DUMPCLFRS 150 | std::cout << "dumping CLFRs to: " << fn + std::string(".clfrs") << std::endl; 151 | o.open(fn + std::string(".clfrs"), ios::binary); 152 | #endif 153 | 154 | last = high_resolution_clock::now(); 155 | 156 | } 157 | 158 | void sendBatch(){ 159 | finalClfrCt+=batchVec->size(); 160 | #ifdef DUMPCLFRS 161 | for (auto kv : (*batchVec)){ 162 | o.write(kv.first.c_str(), 13); 163 | // if (kv.second.flowFeatures.pktCt > 1000){ 164 | // std::cout << "writing pkt ct: " << kv.second.flowFeatures.pktCt << std::endl; 165 | // } 166 | if (kv.second.flowFeatures.pktCt != kv.second.packetVector.size()){ 167 | std::cout << "size error: " << kv.second.flowFeatures.pktCt << " vec len: " << kv.second.packetVector.size() << std::endl; 168 | exit(1); 169 | } 170 | o.write((char *)&(kv.second.flowFeatures), sizeof(kv.second.flowFeatures)); 171 | for (auto pf : kv.second.packetVector){ 172 | o.write((char *)&pf, sizeof(pf)); 173 | } 174 | 175 | } 176 | #endif 177 | // Send the output vector. 178 | output["out"].send(); 179 | // Get new batch vec. 180 | auto &out( output["out"].template allocate() ); 181 | batchVec = &out; 182 | batchVec->reserve(BATCH_SIZE); 183 | } 184 | 185 | // Check flows for timeouts. 186 | // Last update time > 187 | void timeoutFlows(){ 188 | uint64_t newTimeouts = 0; 189 | for (auto kv : CLFR_flatmap){ 190 | if (curTs - kv.second.packetVector.back().ts > timeoutThreshold){ 191 | // std::cout << " timeout: " << kv.second.packetVector.back().ts << " cur: " << curTs << std::endl; 192 | batchVec->emplace_back(kv.first, kv.second); 193 | CLFR_flatmap.erase(kv.first); 194 | timeoutCt++; 195 | newTimeouts++; 196 | if (batchVec->size() > BATCH_SIZE){ 197 | sendBatch(); 198 | } 199 | 200 | } 201 | } 202 | // std :: cout << "new timeouts: " << newTimeouts << std::endl; 203 | lastCheckTs = curTs; 204 | } 205 | 206 | // Aggregate MF_BATCH_SIZE microflow, add finished flows to output. 207 | void readMicroflows(){ 208 | 209 | char * key_chr; 210 | FlowFeatures * flow_features; 211 | PacketFeatures *pkt_features; 212 | // Parse MF_BATCH_SIZE microflows. 213 | for (int i=0; i<(MF_BATCH_SIZE-batchVec->size())+1; i++){ 214 | finalMfCt ++; 215 | // parse key. 216 | key_chr = bufPos; 217 | bufPos += KEYLEN; 218 | // parse flow features. 219 | flow_features = (FlowFeatures *) bufPos; 220 | bufPos += sizeof(FlowFeatures); 221 | 222 | // parse packet features. 223 | pkt_features = (PacketFeatures *) bufPos; 224 | bufPos+= sizeof(PacketFeatures) * flow_features->pktCt; 225 | 226 | // insert. 227 | std::string keyStr = std::string(key_chr, 13); 228 | 229 | auto got = CLFR_flatmap.find(keyStr); 230 | if (got == CLFR_flatmap.end()){ 231 | CLFR_flatmap[keyStr] = blankValue; 232 | got = CLFR_flatmap.find(keyStr); 233 | } 234 | 235 | // update flow features. 236 | got->second.flowFeatures.pktCt+= flow_features->pktCt; 237 | // append packet features to vectors. 238 | for (int i=0; ipktCt; i++){ 239 | got->second.packetVector.push_back(*pkt_features); 240 | pkt_features++; 241 | } 242 | // estimate cur ts, for timeouts. 243 | curTs = std::max(curTs, got->second.packetVector.back().ts); 244 | 245 | // std::cout << " ----" << std::endl; 246 | // Evict if fin. 247 | if (((flow_features->th_flags & TH_FIN) == TH_FIN) || ((flow_features->th_flags & TH_RST) == TH_RST)) { 248 | batchVec->emplace_back(keyStr, got->second); 249 | finCt++; 250 | CLFR_flatmap.erase(keyStr); 251 | } 252 | if (batchVec->size() > BATCH_SIZE){ 253 | sendBatch(); 254 | } 255 | 256 | } 257 | 258 | if (batchVec->size() > BATCH_SIZE){ 259 | sendBatch(); 260 | } 261 | mfCt+= MF_BATCH_SIZE; 262 | } 263 | 264 | // Read microflows from a per-port file, emit batches of CLFRs. 265 | raft::kstatus run() override 266 | { 267 | 268 | if (batchVec == NULL){ 269 | // Get new batch vec. 270 | auto &out( output["out"].template allocate() ); 271 | batchVec = &out; 272 | batchVec->reserve(BATCH_SIZE); 273 | } 274 | // Read microflows and push finished flows to batch vector. 275 | readMicroflows(); 276 | lastMfCt += MF_BATCH_SIZE; 277 | 278 | // Check timeouts, if necessary, push to batch vector. 279 | if (curTs - lastCheckTs > timeoutCheckPeriod){ 280 | timeoutFlows(); 281 | } 282 | 283 | benchmark(); 284 | if ((mfCt+MF_BATCH_SIZE) > totalMfCt){ 285 | // std::cout<<"resetting input buffer." < BENCHMARK_CT ){ 302 | total += lastMfCt; 303 | cur = high_resolution_clock::now(); 304 | auto duration = duration_cast( cur - last ).count(); 305 | // std::cout << std::fixed << "time to process BENCHMARK_CT MFs: " << duration <<" processing rate: " << 1000.0*(float(lastMfCt)/float(duration)) << std::endl; 306 | // std::cout << "fin ct: " << finCt << " timeout ct: " << timeoutCt << std::endl; 307 | // std::cout << "table size: " << CLFR_flatmap.size() << std::endl; 308 | // Push latest throughput value to stat tracker. 309 | output["stats"].push(1000.0*(float(total)/float(duration))); 310 | 311 | lastMfCt = 0; 312 | 313 | // last = high_resolution_clock::now(); 314 | } 315 | 316 | #endif 317 | } 318 | 319 | 320 | }; 321 | } 322 | } 323 | 324 | #endif 325 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/printer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_PRINTER 3 | #define STARFLOW_KERNELS_PRINTER 4 | 5 | #include 6 | 7 | namespace starflow { 8 | namespace kernels { 9 | template 10 | class Printer : public raft::kernel 11 | { 12 | public: 13 | explicit Printer(std::ostream& os = std::cout, bool endl = true, bool forward = false) 14 | : raft::kernel(), 15 | _os(os), 16 | _endl(endl), 17 | _forward(forward) 18 | { 19 | input.template add_port("in"); 20 | if (_forward) 21 | output.template add_port("out"); 22 | } 23 | 24 | raft::kstatus run() override 25 | { 26 | T t{}; 27 | input["in"].pop(t); 28 | _os << t << (_endl ? '\n' : '\0'); 29 | 30 | if (_forward) { 31 | auto out(output["out"].template allocate_s()); 32 | *out = t; 33 | } 34 | 35 | return (raft::proceed); 36 | } 37 | 38 | private: 39 | std::ostream& _os; 40 | bool _endl; 41 | bool _forward; 42 | }; 43 | } 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/redis_flow_subscriber.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_REDIS_FLOW_SUBSCRIBER 3 | #define STARFLOW_KERNELS_REDIS_FLOW_SUBSCRIBER 4 | 5 | #include "../redis_flow_subscriber.h" 6 | #include 7 | 8 | namespace starflow { 9 | namespace kernels { 10 | class RedisFlowSubscriber : public raft::kernel 11 | { 12 | public: 13 | 14 | using output_t = std::pair; 15 | 16 | RedisFlowSubscriber(const std::string& host, unsigned port, const std::string& topic) 17 | : _redis_subscriber(host, port, topic, 18 | [this](starflow::FlowTable::key_t k, starflow::Flow f) { 19 | _new_flow(k, f); 20 | }) 21 | { 22 | output.add_port("out"); 23 | } 24 | 25 | void _new_flow(starflow::FlowTable::key_t k, starflow::Flow f) 26 | { 27 | auto out(output["out"].allocate_s()); 28 | *out = std::make_pair(k, f); 29 | } 30 | 31 | raft::kstatus run() override 32 | { 33 | _redis_subscriber(); 34 | return(raft::proceed); 35 | } 36 | 37 | private: 38 | starflow::RedisFlowSubscriber _redis_subscriber; 39 | }; 40 | } 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/sink.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_SINK 3 | #define STARFLOW_KERNELS_SINK 4 | 5 | 6 | namespace starflow { 7 | namespace kernels { 8 | template 9 | class Sink : public raft::kernel 10 | { 11 | public: 12 | explicit Sink() 13 | : raft::kernel() 14 | { 15 | input.template add_port("in"); 16 | } 17 | 18 | raft::kstatus run() override 19 | { 20 | // T t{}; 21 | // input["in"].pop(t); 22 | 23 | return (raft::proceed); 24 | } 25 | }; 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/starFlow.h: -------------------------------------------------------------------------------- 1 | #ifndef STARFLOW_CSTRUCTS 2 | #define STARFLOW_CSTRUCTS 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include 15 | #include "MurmerHash3.h" 16 | using namespace std; 17 | uint64_t gpid = 0; 18 | 19 | // Structs and support functions for *Flow. 20 | 21 | 22 | #define KEYLEN 13 // Length of key used in any flow tables. 23 | 24 | 25 | #define PKT_FTR_SZ 8 26 | // Features of individual packet, for export from switch. 27 | struct PacketFeatures{ 28 | uint16_t queueSize; 29 | uint16_t byteCt; 30 | uint32_t ts; 31 | }; 32 | 33 | 34 | struct PacketRecord{ 35 | char key[KEYLEN]; 36 | u_char th_flags; 37 | PacketFeatures features; 38 | }; 39 | 40 | // Maximum number of packet features that a micro-CLFR can hold. 41 | // (Will be truncated if < MCLFR_MAXLEN before switch export) 42 | #define MCLFR_MAXLEN 32 43 | struct MCLFR { 44 | // metadata. 45 | uint64_t hashVal; 46 | bool inUse; 47 | uint32_t lastAccessTs; 48 | uint64_t flowId; 49 | // key and aggregate features. 50 | char key[KEYLEN]; 51 | std::string keyStr; 52 | u_char th_flags; 53 | uint16_t pktCt; 54 | // per packet features. 55 | PacketFeatures packetVector[MCLFR_MAXLEN]; 56 | // Index of long vector, if owned. 57 | uint32_t longVectorIdx; 58 | }; 59 | 60 | 61 | // Key represented as ints for testing different hash tables. 62 | // probably should be changed back to string. 63 | struct PackedKey { 64 | uint64_t addrs; 65 | uint64_t portsproto; 66 | }; 67 | 68 | struct FlowFeatures { 69 | uint32_t pktCt; 70 | u_char th_flags; 71 | }; 72 | 73 | #define MF_HDR_SZ 24 74 | // Format of switch export. 75 | struct Export_MCLFR { 76 | char key[KEYLEN]; 77 | // PackedKey packedKey; 78 | FlowFeatures flowFeatures; 79 | PacketFeatures packetVector[MCLFR_MAXLEN]; 80 | }; 81 | 82 | struct Export_MCLFR_hdr { 83 | char key[KEYLEN]; 84 | // PackedKey packedKey; 85 | FlowFeatures flowFeatures; 86 | }; 87 | 88 | 89 | 90 | // Internal CLFR format for applications. 91 | // ( previously named struct FlowRecord ) 92 | struct CLFR { 93 | char key[KEYLEN]; 94 | FlowFeatures flowFeatures; 95 | // byte counts and timeStamps of each packet in the flow. 96 | std::vector queueSizes; 97 | std::vector byteCounts; 98 | std::vector timeStamps; 99 | }; 100 | 101 | 102 | struct CLFR_Value { 103 | FlowFeatures flowFeatures; 104 | // byte counts and timeStamps of each packet in the flow. 105 | std::vector packetVector; 106 | // std::vector queueSizes; 107 | // std::vector byteCounts; 108 | // std::vector timeStamps; 109 | }; 110 | 111 | // struct CLFR_Value_Blob { 112 | // FlowFeatures flowFeatures; 113 | 114 | // }; 115 | 116 | // void write_CLFR_Blob(char * outBuf, std::pair& clfrTup){ 117 | // memcpy(outBuf, clfrTup.first.c_str(), KEYLEN); 118 | // outBuf+=KEYLEN; 119 | // memcpy(outBuf, (char *) &clfrTup.second.flowFeatures, sizeof(CLFR_Value)); 120 | // outBuf+=sizeof(CLFR_Value); 121 | // for (PacketFeatures p : clfrTup.second.packetVector){ 122 | // memcpy(outBuf, (char *) &p, sizeof(PacketFeatures)); 123 | // outBuf += sizeof(PacketFeatures); 124 | // } 125 | // return; 126 | // } 127 | // void read_CLFR_Blob() 128 | 129 | void printSizes(){ 130 | std::cout << "struct sizes" << std::endl; 131 | std::cout << "PacketFeatures:\t" << sizeof(PacketFeatures) << std::endl; 132 | std::cout << "PackedKey:\t" << sizeof(PackedKey) << std::endl; 133 | std::cout << "Export_MCLFR_hdr:\t" << sizeof(Export_MCLFR_hdr) << std::endl; 134 | std::cout << "Export_MCLFR:\t" << sizeof(Export_MCLFR) << std::endl; 135 | std::cout << "Export_MCLFR packetVector:\t" << MCLFR_MAXLEN*sizeof(PacketFeatures) << std::endl; 136 | } 137 | 138 | 139 | 140 | // Helpers. 141 | void setKey(char *keyBuf, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader); 142 | uint64_t getMicrosecondTs(uint64_t seconds, uint64_t microSeconds); 143 | MCLFR * newMicroflow(uint64_t curTs, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader); 144 | unsigned simpleHash(unsigned int p, const char* s, int len, int maxHashVal); 145 | std::string string_to_hex(const std::string& input); 146 | 147 | 148 | // Convert a packet into a microflow with 1 item. 149 | void initMicroflow(MCLFR * mfr, uint64_t curTs, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader){ 150 | // Set raw key. 151 | setKey(mfr->key, ipHeader, udpOrtcpHeader); 152 | // Set aggregate features. 153 | mfr->pktCt = 1; 154 | // Set features of first packet vector slot. 155 | mfr->packetVector[0].byteCt = ipHeader->ip_len; 156 | mfr->packetVector[0].ts = curTs; 157 | } 158 | 159 | 160 | // Get 64 bit timestamp. 161 | uint64_t getMicrosecondTs(uint64_t seconds, uint64_t microSeconds){ 162 | uint64_t ts = seconds * 1000000 + microSeconds; 163 | return ts; 164 | } 165 | 166 | void setKey(char *keyBuf, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader){ 167 | memcpy(&(keyBuf[0]), &ipHeader->ip_src, 4); 168 | memcpy(&(keyBuf[4]), &ipHeader->ip_dst, 4); 169 | memcpy(&(keyBuf[8]), &udpOrtcpHeader->source, 2); 170 | memcpy(&(keyBuf[10]), &udpOrtcpHeader->dest, 2); 171 | memcpy(&(keyBuf[12]), &ipHeader->ip_p, 1); 172 | } 173 | 174 | 175 | // A simple hashing function. 176 | unsigned simpleHash(unsigned int p, const char* s, int len, int maxHashVal) 177 | { 178 | uint64_t out[2]; 179 | MurmurHash3_x64_128(s, len, p, out); 180 | return out[1] % maxHashVal; 181 | } 182 | 183 | std::string string_to_hex(const std::string& input) 184 | { 185 | static const char* const lut = "0123456789ABCDEF"; 186 | size_t len = input.length(); 187 | 188 | std::string output; 189 | output.reserve(2 * len); 190 | for (size_t i = 0; i < len; ++i) 191 | { 192 | const unsigned char c = input[i]; 193 | output.push_back(lut[c >> 4]); 194 | output.push_back(lut[c & 15]); 195 | } 196 | return output; 197 | } 198 | 199 | #endif -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/kernels/tap.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_TAP 3 | #define STARFLOW_KERNELS_CLFR_TAP 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | 15 | 16 | 17 | namespace starflow { 18 | namespace kernels { 19 | template 20 | class ClfrTap : public raft::kernel 21 | { 22 | public: 23 | // Counts CLFRs, gives periodic statistic updates. 24 | #define BENCHMARK_CT 1000000 25 | high_resolution_clock::time_point last, cur; 26 | 27 | int outC; 28 | 29 | uint64_t counter=0; 30 | explicit ClfrTap(int inputPortCt) 31 | : raft::kernel() 32 | { 33 | outC = inputPortCt; 34 | last = high_resolution_clock::now(); 35 | // input.template addPort("out"); 36 | // Configure the stream processing outputs. 37 | for (int i=0; i(std::to_string(i)); 40 | } 41 | } 42 | 43 | raft::kstatus run() override 44 | { 45 | 46 | // some black magic to get a refrecne to the CLFR batch object. 47 | // std::cout << clfr.timeStamps[0] << endl; 48 | 49 | for (int i = 0; i()); 51 | counter+= clfrVector.size(); 52 | // auto &out( output[std::to_string(i)].template allocate() ); 53 | // auto out( output[out].template allocate_s() ); 54 | // (*out) = clfrVector; 55 | // output[std::to_string(i)].send(); 56 | input[std::to_string(i)].recycle(); // recycle to move to next item. 57 | } 58 | 59 | // std::cout << "counter: " << counter << std::endl; 60 | if (counter > BENCHMARK_CT){ 61 | // std::cout << "read " << counter << " CLFRs " << endl; 62 | // report throughput. 63 | cur = high_resolution_clock::now(); 64 | auto duration = duration_cast( cur - last ).count(); 65 | // std::cout << std::fixed << "# inputs: " << outC << " time to join: " << BENCHMARK_CT << " clfrs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 66 | counter = 0; 67 | last = high_resolution_clock::now(); 68 | } 69 | 70 | return (raft::proceed); 71 | } 72 | }; 73 | } 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /backend/old/multi_kernel_bench/readme.md: -------------------------------------------------------------------------------- 1 | ###Multi-kernel benchmarks 2 | 3 | **Todo: upload build instructions and example input files.** 4 | 5 | This directory contains a set of older (late 2017) in-memory benchmarks of a raftlib-based starflow backend. 6 | 7 | ####important files: 8 | 9 | - ``clfr_converter_main.cc`` -- this benchmarks a raftlib pipeline that reads telemetry records in a switch-exported format (using kernels/microflow_reader.h) and converts them into CLFR records (each CLFR has a flow key and a vector of packet features). 10 | 11 | - ``clfr_driver_main.cc`` -- this benchmarks raftlib pipelines that run one or more kernels that analyze clfrs. 12 | 13 | - ``kernels/microflow_reader.h`` -- transforms micro-CLFRs (i.e., the format of telemetry data exported by a switch) into full CLFRs. For benchmarking, this kernel pre-loads mCLFRs from a file to a buffer. In production, it would read from a socket or a ringbuffer populated by a NIC. 14 | 15 | - ``kernels/host_timing_profiler.h``, ``kernels/microburst_detector.h``, ``kernels/*FeatureCalculator.h`` -- various CLFR-based analysis kernels. 16 | 17 | - ``kernels/printer.h`` -- a sink for when multiple instances of an analysis kernel run in parallel. It prints performance statistics. 18 | 19 | 20 | ####notes: 21 | 22 | CLFR stands for "compact lossless flow records". They are a compact and efficient format for storing and analyzing packet-level telemetry data. A CLFR contains a flow key, some flow-level metadata, and a small tuple of features from every packet in the flow. In the starflow paper (ATC 18'), we renamed CLFRs to GPVs ("grouped packet vectors"). 23 | 24 | -------------------------------------------------------------------------------- /backend/old/single_kernel_bench/bin/benchmarkMetrics.sh: -------------------------------------------------------------------------------- 1 | # benchmark metric sets with different numbers of cores. 2 | # 11/19 3 | echo "msetReplicaCtReplicaRate = {}" 4 | for mSet in {1..5} 5 | do 6 | echo "msetReplicaCtReplicaRate[$mSet] = {}" 7 | for nReplicas in 1 2 4 8 16 8 | # for nReplicas in 1 2 4 6 8 10 12 14 16 9 | do 10 | # echo "#running" 11 | numactl --cpunodebind=0 --membind=0 ./starflow_app_benchmark -r $nReplicas -m $mSet 12 | done 13 | done 14 | -------------------------------------------------------------------------------- /backend/old/single_kernel_bench/bin/df.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonch/StarFlow/08c6d65b4e4b31065a471a8bcbe29b56455b4508/backend/old/single_kernel_bench/bin/df.dat -------------------------------------------------------------------------------- /backend/old/single_kernel_bench/bin/starflow_app_benchmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonch/StarFlow/08c6d65b4e4b31065a471a8bcbe29b56455b4508/backend/old/single_kernel_bench/bin/starflow_app_benchmark -------------------------------------------------------------------------------- /backend/old/single_kernel_bench/bin/turboflow_starflow_highlevel.numbers: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonch/StarFlow/08c6d65b4e4b31065a471a8bcbe29b56455b4508/backend/old/single_kernel_bench/bin/turboflow_starflow_highlevel.numbers -------------------------------------------------------------------------------- /backend/old/single_kernel_bench/inputparser.h: -------------------------------------------------------------------------------- 1 | // From: https://stackoverflow.com/questions/865668/how-to-parse-command-line-arguments-in-c 2 | 3 | #include 4 | 5 | char* getCmdOption(char ** begin, char ** end, const std::string & option) 6 | { 7 | char ** itr = std::find(begin, end, option); 8 | if (itr != end && ++itr != end) 9 | { 10 | return *itr; 11 | } 12 | return 0; 13 | } 14 | 15 | bool cmdOptionExists(char** begin, char** end, const std::string& option) 16 | { 17 | return std::find(begin, end, option) != end; -------------------------------------------------------------------------------- /backend/old/single_kernel_bench/kernels/benchmark_printer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_BENCHMARK_PRINTER 3 | #define STARFLOW_KERNELS_BENCHMARK_PRINTER 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | #include 15 | 16 | namespace starflow { 17 | namespace kernels { 18 | template 19 | class BenchmarkPrinter : public raft::kernel 20 | { 21 | public: 22 | // Tracks and summarizes throughput stats from multiple ports. 23 | #define BENCHMARK_CT 1000000 24 | 25 | int inC; 26 | 27 | std::unordered_map portStats; 28 | int ctr = 0; 29 | explicit BenchmarkPrinter(int inputPortCt) 30 | : raft::kernel() 31 | { 32 | inC = inputPortCt; 33 | // Configure the stream processing outputs. 34 | for (int i=0; i(std::to_string(i)); 38 | } 39 | } 40 | 41 | raft::kstatus run() override 42 | { 43 | 44 | cout << std::fixed << "stats[" << ctr << "]=["; 45 | double combined = 0; 46 | for (int i = 0; i 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include 15 | #include "MurmerHash3.h" 16 | using namespace std; 17 | uint64_t gpid = 0; 18 | 19 | // Structs and support functions for *Flow. 20 | 21 | 22 | #define KEYLEN 13 // Length of key used in any flow tables. 23 | 24 | 25 | struct GPVHeader { 26 | char key[KEYLEN]; 27 | uint8_t dpid; 28 | uint16_t pktCt; 29 | uint64_t startTs; 30 | }; 31 | 32 | struct FeatureTuple { 33 | uint32_t tsDelta : 20; 34 | uint16_t byteCt : 11; 35 | bool highQueue: 1; 36 | }; 37 | 38 | 39 | 40 | #define PKT_FTR_SZ 16 41 | // Features of individual packet, for export from switch. 42 | struct PacketFeatures{ 43 | uint16_t queueSize; 44 | uint16_t byteCt; 45 | uint64_t ts; 46 | }; 47 | 48 | 49 | struct PacketRecord{ 50 | char key[KEYLEN]; 51 | u_char th_flags; 52 | PacketFeatures features; 53 | }; 54 | 55 | // Maximum number of packet features that a micro-CLFR can hold. 56 | // (Will be truncated if < MCLFR_MAXLEN before switch export) 57 | #define MCLFR_MAXLEN 32 58 | struct MCLFR { 59 | // metadata. 60 | uint64_t hashVal; 61 | bool inUse; 62 | uint64_t lastAccessTs; 63 | uint64_t firstAccessTs; 64 | uint64_t flowId; 65 | // key and aggregate features. 66 | char key[KEYLEN]; 67 | std::string keyStr; 68 | u_char th_flags; 69 | uint16_t pktCt; 70 | bool allocAttempt; 71 | // per packet features. 72 | PacketFeatures packetVector[MCLFR_MAXLEN]; 73 | // Index of long vector, if owned. 74 | uint32_t longVectorIdx; 75 | }; 76 | 77 | 78 | // Key represented as ints for testing different hash tables. 79 | // probably should be changed back to string. 80 | struct PackedKey { 81 | uint64_t addrs; 82 | uint64_t portsproto; 83 | }; 84 | 85 | struct FlowFeatures { 86 | uint32_t pktCt; 87 | u_char th_flags; 88 | }; 89 | 90 | #define MF_HDR_SZ 24 91 | // Format of switch export. 92 | struct Export_MCLFR { 93 | PackedKey packedKey; 94 | FlowFeatures flowFeatures; 95 | PacketFeatures packetVector[MCLFR_MAXLEN]; 96 | }; 97 | 98 | struct Export_MCLFR_hdr { 99 | PackedKey packedKey; 100 | FlowFeatures flowFeatures; 101 | }; 102 | 103 | 104 | 105 | // Internal CLFR format for applications. 106 | // ( previously named struct FlowRecord ) 107 | struct CLFR { 108 | PackedKey packedKey; 109 | FlowFeatures flowFeatures; 110 | // byte counts and timeStamps of each packet in the flow. 111 | std::vector queueSizes; 112 | std::vector byteCounts; 113 | std::vector timeStamps; 114 | }; 115 | 116 | 117 | struct CLFR_Value { 118 | FlowFeatures flowFeatures; 119 | // byte counts and timeStamps of each packet in the flow. 120 | std::vector packetVector; 121 | // std::vector queueSizes; 122 | // std::vector byteCounts; 123 | // std::vector timeStamps; 124 | }; 125 | 126 | 127 | 128 | 129 | 130 | // Helpers. 131 | void setKey(char *keyBuf, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader); 132 | uint64_t getMicrosecondTs(uint32_t seconds, uint32_t microSeconds); 133 | MCLFR * newMicroflow(uint64_t curTs, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader); 134 | unsigned simpleHash(unsigned int p, const char* s, int len, int maxHashVal); 135 | std::string string_to_hex(const std::string& input); 136 | 137 | 138 | // Convert a packet into a microflow with 1 item. 139 | void initMicroflow(MCLFR * mfr, uint64_t curTs, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader){ 140 | // Set raw key. 141 | setKey(mfr->key, ipHeader, udpOrtcpHeader); 142 | // Set aggregate features. 143 | mfr->pktCt = 1; 144 | // Set features of first packet vector slot. 145 | mfr->packetVector[0].byteCt = ipHeader->ip_len; 146 | mfr->packetVector[0].ts = curTs; 147 | } 148 | 149 | 150 | // Get 64 bit timestamp. 151 | uint64_t getMicrosecondTs(uint32_t seconds, uint32_t microSeconds){ 152 | uint64_t seconds64 = seconds; 153 | uint64_t microSeconds64 = microSeconds; 154 | uint64_t ts = seconds64 * 1000000 + microSeconds64; 155 | return ts; 156 | } 157 | 158 | void setKey(char *keyBuf, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader){ 159 | memcpy(&(keyBuf[0]), &ipHeader->ip_src, 4); 160 | memcpy(&(keyBuf[4]), &ipHeader->ip_dst, 4); 161 | memcpy(&(keyBuf[8]), &udpOrtcpHeader->source, 2); 162 | memcpy(&(keyBuf[10]), &udpOrtcpHeader->dest, 2); 163 | memcpy(&(keyBuf[12]), &ipHeader->ip_p, 1); 164 | } 165 | 166 | 167 | // A simple hashing function. 168 | unsigned simpleHash(unsigned int p, const char* s, int len, int maxHashVal) 169 | { 170 | uint64_t out[2]; 171 | MurmurHash3_x64_128(s, len, p, out); 172 | return out[1] % maxHashVal; 173 | } 174 | 175 | std::string string_to_hex(const std::string& input) 176 | { 177 | static const char* const lut = "0123456789ABCDEF"; 178 | size_t len = input.length(); 179 | 180 | std::string output; 181 | output.reserve(2 * len); 182 | for (size_t i = 0; i < len; ++i) 183 | { 184 | const unsigned char c = input[i]; 185 | output.push_back(lut[c >> 4]); 186 | output.push_back(lut[c & 15]); 187 | } 188 | return output; 189 | } 190 | 191 | #endif -------------------------------------------------------------------------------- /backend/old/single_kernel_bench/readme.md: -------------------------------------------------------------------------------- 1 | ### starflow single kernel backend 2 | *date: 11/2019* 3 | 4 | This starflow backend runs a single raftlib kernel that: 5 | 6 | 1. Loads microflows from a file. 7 | 2. Applies all selected telemetry analysis functions. 8 | 3. Reports performance statistics to a downstream kernel. 9 | 10 | 11 | The goal was to measure raw performance without any overheads from stream processing frameworks or NICs. 12 | 13 | Notes: 14 | 15 | The binary in this directory, starflow_app_benchmark, was originally run in 11/2019 on a debian (x86-64) server. 16 | 17 | Currently (8/2020), that server is offline and inaccessible. So, these source files come from two different versions of the code and may not compile correctly. 18 | 19 | starflow_app_benchmark.cc and kernels/merged_all_metrics.h (the most important files with all the actual analysis code) are from local copies of the 11/2019 benchmark source. 20 | 21 | The remaining files come from an older repository. 22 | -------------------------------------------------------------------------------- /backend/old/single_kernel_bench/starflow_app_benchmark.cc: -------------------------------------------------------------------------------- 1 | // simplified starflow application benchmark. 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include "kernels/microflow_reader.h" 8 | // #include "kernels/clfr_reader.h" 9 | // #include "kernels/clfr_counter.h" 10 | 11 | // // All-metric calculator. 12 | // #include "kernels/all_metrics.h" 13 | 14 | // Metric calculator with integrated GPV reader. 15 | #include "kernels/merged_all_metrics.h" 16 | // Something to pipe to... 17 | #include "kernels/benchmark_printer.h" 18 | 19 | // Arg parsing. 20 | #include "inputparser.h" 21 | 22 | // // Apps. 23 | // // Profiler. 24 | // #include "kernels/host_timing_profiler.h" 25 | // // Micro-burst detector. 26 | // #include "kernels/microburst_detector.h" 27 | // // Metric measurement and app label 28 | // #include "kernels/performance_metrics_and_app_label.h" 29 | 30 | // // Feature calculators. 31 | // #include "kernels/rich_feature_calculator.h" 32 | // #include "kernels/netflow_feature_calculator.h" 33 | // #include "kernels/pfe_feature_calculator.h" 34 | // #include "kernels/allstats_feature_calculator.h" 35 | 36 | 37 | 38 | 39 | 40 | // // Utilities. 41 | // #include "kernels/cloner.h" 42 | 43 | // #include "kernels/clfr_counter_chain.h" 44 | 45 | // #include "kernels/clfr_counter_replicated.h" 46 | 47 | // #include "kernels/benchmark_printer.h" 48 | 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | 56 | 57 | 58 | // void runSimpleCounter(); 59 | // void runHostProfiler(); 60 | // void runClassifiers(); 61 | // void runMicroburstDetector(); 62 | 63 | // void runClones(int N); 64 | // void runChains(int N); 65 | // void runReplicas(int N); 66 | 67 | // void benchmarkReplicas(); 68 | 69 | // New files 11/19 70 | void benchmarkReplicasFromDigests(); 71 | void runMetricGeneratorFromDigests(int N, int metricSet); 72 | 73 | 74 | /*================================= 75 | = Arguments = 76 | =================================*/ 77 | 78 | int nReplicas = 1; // Number of replica pipelines. Each uses 2 cores. 79 | int mSet = 1; // Metric set. 80 | /** 81 | * 82 | * metric sets: 83 | * 1: 4 streaming metrics. 84 | * 2: 20 streaming metrics. 85 | * 3: +application class. 86 | * 4: +host profiles. 87 | * 5: +full queue occupants. 88 | */ 89 | 90 | void parseArgs(int argc, char *argv[]){ 91 | char * ptr_nReplicas = getCmdOption(argv, argv+argc, "-r"); 92 | if (ptr_nReplicas != 0) { 93 | nReplicas = atoi(ptr_nReplicas); 94 | } 95 | char * ptr_mSet = getCmdOption(argv, argv+argc, "-m"); 96 | if (ptr_mSet != 0) { 97 | mSet = atoi(ptr_mSet); 98 | } 99 | std::cout << "#---arguments---" < logger(N); 149 | starflow::kernels::MetricBackend * sinks[N]; 150 | for (int i=0; i(metricSet, i, "/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin"); 152 | m += *(sinks[i]) >> logger[std::to_string(i)]; 153 | } 154 | m.exe(); 155 | 156 | 157 | // raft::map m; 158 | 159 | // starflow::kernels::MicroflowReader * readers[N]; 160 | // starflow::kernels::MetricBackend * sinks[N]; 161 | // for (int i=0; i(metricSet); 164 | // m += *(readers[i]) >> *(sinks[i]); 165 | // } 166 | // m.exe(); 167 | } 168 | 169 | /*===== End of new code 11/19 ======*/ 170 | 171 | 172 | // /*=============================================== 173 | // = Functionality test code = 174 | // ===============================================*/ 175 | 176 | // void runSimpleCounter(){ 177 | // raft::map m; 178 | // std::cout << "initializing kernels." << endl; 179 | // // The kernel to read CLFRs. Emits CLFRs generated by converter. 180 | // starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin.clfrs"); 181 | // // starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/mCLFRs.32.bin.clfrs"); 182 | // starflow::kernels::ClfrCounter counter; 183 | // m += reader >> counter; 184 | // m.exe(); 185 | // return; 186 | // } 187 | 188 | 189 | // void runHostProfiler(){ 190 | // raft::map m; 191 | // std::cout << "initializing kernels." << endl; 192 | // starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin.clfrs"); 193 | // starflow::kernels::HostProfiler profiler("/home/jsonch/gits/starflow_analytics/outputs/timingProfile.bin", 5 * 60 * 1000); 194 | // m += reader >> profiler; 195 | // m.exe(); 196 | // return; 197 | // } 198 | // void runClassifiers(){ 199 | // raft::map m; 200 | // std::cout << "initializing kernels." << endl; 201 | // starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/caida2015_02_dirA.mCLFRs.bin.clfrs"); 202 | // // // Compute clfr features. 203 | // // starflow::kernels::FeatureCalculator calculator; 204 | 205 | // // Compute netflow features. 206 | // // starflow::kernels::NetFlowFeatureCalculator calculator; 207 | 208 | // // Compute PFE aggregatable features. 209 | // // starflow::kernels::PFEFeatureCalculator calculator; 210 | 211 | // // Compute complex aggregated stat features. 212 | // // starflow::kernels::AllStatsFeatureCalculator calculator; 213 | // // m += reader >> calculator; 214 | // // m += reader >> calculator; 215 | // m.exe(); 216 | 217 | // } 218 | // void runMicroburstDetector(){ 219 | // raft::map m; 220 | // std::cout << "initializing kernels." << endl; 221 | // starflow::kernels::ClfrReader reader("/home/jsonch/gits/starflow_analytics/inputs/microburst.clfrs.bin"); 222 | 223 | // starflow::kernels::MicroburstDetector detector; 224 | // m += reader >> detector; 225 | // m.exe(); 226 | // } 227 | 228 | 229 | // /*===== End of Functionality test code ======*/ -------------------------------------------------------------------------------- /backend/pin.sh: -------------------------------------------------------------------------------- 1 | numactl --cpunodebind=1 --membind=1 $1 2 | -------------------------------------------------------------------------------- /backend/readme.md: -------------------------------------------------------------------------------- 1 | ## StarFlow raftlib-based backend 2 | 3 | This directory contains raftlib kernels that implement key parts of the starflow backend, and a simple exapmle program that benchmarks single instances of kernel pipelines. 4 | 5 | ### Dependencies 6 | 7 | * libraft [[1]](https://github.com/RaftLib/RaftLib) 8 | 9 | ### Input datasets 10 | 11 | You can download input datasets (about 2.5GB) to use with the benchmarking program here: 12 | 13 | https://drive.google.com/drive/folders/1cZmwCv0IhNUmUSo18VtCDUSsPGD3JLAi?usp=sharing 14 | 15 | Put the files in ./inputs (filenames are hard-coded in the benchmarking program). 16 | 17 | - ``mCLFRs.32.bin`` -- a short micro-CLFR trace from a CAIDA dataset. 18 | 19 | - ``microburst.clfrs.bin`` -- a synthetic trace with microbursts, for benchmarking the microburst detector. 20 | 21 | ### Usage 22 | 23 | make 24 | ./benchmark_main 25 | 26 | *See example.out for output from an example run.* 27 | 28 | ### Important files 29 | 30 | - ``benchmark_main.cpp`` -- this benchmarks single instances of the following raftlib pipelines, on in-memory datasets: 31 | - micro-CLFR to CLFR conversion. 32 | - CLFR reading from memory. 33 | - CLFR processing (flow metric calculation and microburst detection) 34 | 35 | - ``kernels/microflow_reader.h`` -- transforms micro-CLFRs (i.e., the format of telemetry data exported by a switch) into full CLFRs. For benchmarking, this kernel pre-loads mCLFRs from a file to a buffer. In production, it would read from a socket or a ringbuffer populated by a NIC. 36 | 37 | - ``kernels/feature_calculator.h``, ``kernels/microburst_detector.h`` -- example CLFR-based apps 38 | 39 | 40 | ### Notes 41 | 42 | CLFR stands for "compact lossless flow records". They are a compact and efficient format for storing and analyzing packet-level telemetry data. A CLFR contains a flow key, some flow-level metadata, and a small tuple of features from every packet in the flow. In the starflow paper (ATC 18'), we renamed CLFRs to GPVs ("grouped packet vectors"). 43 | -------------------------------------------------------------------------------- /backend/src/benchmark_main.cpp: -------------------------------------------------------------------------------- 1 | // benchmark throughput (in packets per second) of a kernel 2 | // that groups mCLFRs into CLFRs. 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "kernels/microflow_reader.h" 11 | 12 | #include "kernels/clfr_writer.h" 13 | #include "kernels/clfr_reader.h" 14 | 15 | #include "kernels/packet_rate.h" 16 | #include "kernels/flow_rate.h" 17 | #include "kernels/benchmark_printer.h" 18 | 19 | #include "kernels/feature_calculator.h" 20 | 21 | #include "kernels/microburst_detector.h" 22 | 23 | #include "kernels/sink.h" 24 | 25 | void benchmarkMclfrReader(const char * inFn); 26 | void generateClfrs(const char * inFn, const char * clfrFn); 27 | void benchmarkClfrReader(const char * clfrFn); 28 | 29 | void benchmarkFlowMeasApp(const char * clfrFn); 30 | 31 | void benchmarkMicroburstApp(const char *clfrFn); 32 | 33 | int main(int argc, char** argv) { 34 | const char * inFn = "inputs/mCLFRs.32.bin"; 35 | const char * clfrFn = "mCLFRs.32.clfr"; 36 | generateClfrs(inFn, clfrFn); 37 | 38 | benchmarkMclfrReader(inFn); 39 | 40 | benchmarkClfrReader(clfrFn); 41 | 42 | // note that this benchmark reports in FLOWS per second, not packets! 43 | benchmarkFlowMeasApp(clfrFn); 44 | 45 | // Test the microburst detector on a synthetic trace that actually has microbursts. 46 | const char * mbClfrFn = "inputs/microburst.clfrs.bin"; 47 | benchmarkMicroburstApp(mbClfrFn); 48 | return 0; 49 | } 50 | 51 | 52 | // benchmark a single mclfr reader. 53 | void benchmarkMclfrReader(const char * inFn) { 54 | cout << "# ---------------" << endl; 55 | std::cout << "# benchmarking a single micro-clfr reader" << endl; 56 | std::cout << "# initializing kernels." << endl; 57 | // read mclfrs and convert to clfrs 58 | starflow::kernels::MicroflowReader reader(inFn); 59 | // measure stream rate in packets per second 60 | starflow::kernels::MeasurePacketRate counter; 61 | // print results 62 | starflow::kernels::BenchmarkPrinter pktRateLogger(1, "pkts_per_second"); 63 | 64 | std::cout << "# executing kernels." << endl; 65 | 66 | raft::map m; 67 | m += reader["out"] >> counter >> pktRateLogger; 68 | m.exe(); 69 | cout << "# ---------------" << endl; 70 | } 71 | 72 | // convert mCLFRs to CLFRs. 73 | void generateClfrs(const char * inFn, const char * clfrFn) { 74 | cout << "# ---------------" << endl; 75 | cout << "# converting micro-clfrs to clfrs" << endl; 76 | // read mclfrs and convert to clfrs. 77 | starflow::kernels::MicroflowReader reader(inFn); 78 | // write clfrs. 79 | starflow::kernels::ClfrWriter writer(clfrFn); 80 | 81 | raft::map m; 82 | m += reader >> writer; 83 | m.exe(); 84 | cout << "# ---------------" << endl; 85 | } 86 | 87 | void benchmarkClfrReader(const char * clfrFn) { 88 | cout << "# ---------------" << endl; 89 | std::cout << "# benchmarking a single clfr reader" << endl; 90 | // Read clfrs 91 | starflow::kernels::ClfrReader reader(clfrFn); 92 | // measure stream rate in packets per second 93 | starflow::kernels::MeasurePacketRate counter; 94 | // print results 95 | starflow::kernels::BenchmarkPrinter pktRateLogger(1, "packets_per_second"); 96 | 97 | std::cout << "# executing kernels." << endl; 98 | 99 | raft::map m; 100 | m += reader["out"] >> counter >> pktRateLogger; 101 | m.exe(); 102 | cout << "# ---------------" << endl; 103 | } 104 | 105 | // Benchmark an application that calculates 20 flow metrics from each clfr. 106 | // (These metrics can be features for a classifier.) 107 | void benchmarkFlowMeasApp(const char * clfrFn) { 108 | cout << "# ---------------" << endl; 109 | std::cout << "# benchmarking flow meas clfr app" << endl; 110 | // Read clfrs 111 | starflow::kernels::ClfrReader reader(clfrFn); 112 | 113 | // // Measure per-flow stats from clfrs. 114 | starflow::kernels::FeatureCalculator 115 | calc; 116 | 117 | // print output stream throughput (in flows / sec) 118 | starflow::kernels::MeasureFlowRate 119 | >>> ctr; 120 | 121 | starflow::kernels::BenchmarkPrinter lgr(1, "flows_per_second"); 122 | 123 | std::cout << "# executing kernels." << endl; 124 | 125 | raft::map m; 126 | m += reader["out"] >> calc >> ctr >> lgr; 127 | m.exe(); 128 | cout << "# ---------------" << endl; 129 | } 130 | 131 | // Benchmark an application to identify the hosts 132 | // responsible for microbursts 133 | void benchmarkMicroburstApp(const char * clfrFn) { 134 | cout << "# ---------------" << endl; 135 | std::cout << "# benchmarking microburst clfr app" << endl; 136 | // Read clfrs 137 | starflow::kernels::ClfrReader reader(clfrFn); 138 | 139 | starflow::kernels::MicroburstDetector detector; 140 | 141 | starflow::kernels::Sink> sink; 142 | starflow::kernels::BenchmarkPrinter pktRateLogger(1, "pkts_per_second"); 143 | 144 | 145 | raft::map m; 146 | m += reader["out"] >> detector; 147 | m += detector["out"] >> sink; 148 | m += detector["stats"] >> pktRateLogger; 149 | m.exe(); 150 | cout << "# ---------------" << endl; 151 | } 152 | 153 | -------------------------------------------------------------------------------- /backend/src/kernels/benchmark_printer.h: -------------------------------------------------------------------------------- 1 | // Tracks and summarizes throughput stats from multiple ports. 2 | // Prints output in a python friendly format (e.g., to copy and paste into a notebook) 3 | #ifndef STARFLOW_KERNELS_BENCHMARK_PRINTER 4 | #define STARFLOW_KERNELS_BENCHMARK_PRINTER 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | using namespace std; 13 | using namespace std::chrono; 14 | 15 | #include 16 | 17 | namespace starflow { 18 | namespace kernels { 19 | template 20 | class BenchmarkPrinter : public raft::kernel 21 | { 22 | public: 23 | int inC; 24 | 25 | std::unordered_map portStats; 26 | int ctr = 0; 27 | char * statName; 28 | explicit BenchmarkPrinter(int inputPortCt, char * stat) 29 | : raft::kernel() 30 | { 31 | statName = stat; 32 | inC = inputPortCt; 33 | // Configure the stream processing outputs. 34 | for (int i=0; i(std::to_string(i)); 38 | } 39 | cout << "per_input_" << statName << " = []" << endl; 40 | cout << "aggregate_" << statName << " = []" << endl; 41 | } 42 | 43 | raft::kstatus run() override 44 | { 45 | cout << std::fixed << "per_input_" << statName << "[" << ctr << "]=["; 46 | double combined = 0; 47 | for (int i = 0; i 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | using namespace std::chrono; 12 | 13 | #include "starFlow.h" 14 | #include "flat_hash_map.hpp" 15 | 16 | #define BATCH_SIZE_READER 300 17 | 18 | namespace starflow { 19 | namespace kernels { 20 | class ClfrReader : public raft::kernel 21 | { 22 | public: 23 | 24 | char * inBuf; // Buffer for CLFRs to replay. 25 | char * bufPos; 26 | char * bufEnd; 27 | 28 | uint64_t clfrCt = 0; 29 | uint64_t pktCt = 0; 30 | uint64_t byteCt = 0; 31 | 32 | // output type: what the kernel emits. 33 | // A batch of CLFRs. 34 | using output_t = std::vector>; 35 | 36 | // ptr to a reference. 37 | std::vector> * batchVec = NULL; 38 | 39 | // for profiling. 40 | high_resolution_clock::time_point last, cur; 41 | 42 | // Load the eval data set into RAM. This would be done by the NIC. 43 | void loadClfrs(const char *inFile){ 44 | FILE *f = fopen(inFile, "rb"); 45 | fseek(f, 0, SEEK_END); 46 | long f_sz = ftell(f); 47 | byteCt = (uint64_t) f_sz; 48 | fseek(f, 0, SEEK_SET); 49 | std::cout << "# loading " << f_sz << " bytes of CLFRs." << std::endl; 50 | inBuf = (char *) malloc(f_sz); 51 | std::cout << "# finished mallocing" << std::endl; 52 | fread((char *)inBuf, f_sz, 1, f); 53 | fclose(f); 54 | std::cout << "# finished reading" << std::endl; 55 | bufPos = inBuf; 56 | bufEnd = inBuf + f_sz; 57 | } 58 | 59 | ClfrReader(const std::string& fn) : raft::kernel() 60 | { 61 | last = high_resolution_clock::now(); 62 | 63 | // Load microflows in. 64 | loadClfrs(fn.c_str()); 65 | 66 | // Configure the stream processing outputs. 67 | output.template add_port("out"); 68 | } 69 | virtual ~ClfrReader(){ 70 | std::cout << "# read " << clfrCt << " clfrs ( " << byteCt << "bytes ) representing " << pktCt << " packets " << endl; 71 | float bytesPerPkt = byteCt / float(pktCt); 72 | float pktsPerClfr = float(pktCt) / clfrCt; 73 | std::cout << "# bytes per packet: " << bytesPerPkt << endl; 74 | std::cout << "# packets per record: " << pktsPerClfr << endl; 75 | } 76 | 77 | void sendBatch(){ 78 | // Send the output vector. 79 | output["out"].send(); 80 | // Get new batch vec. 81 | auto &out( output["out"].template allocate() ); 82 | batchVec = &out; 83 | batchVec->reserve(BATCH_SIZE_READER); 84 | } 85 | 86 | raft::kstatus run() override 87 | { 88 | if (batchVec == NULL){ 89 | // Get new batch vec. 90 | auto &out( output["out"].template allocate() ); 91 | batchVec = &out; 92 | batchVec->reserve(BATCH_SIZE_READER); 93 | } 94 | 95 | // Parse CLFRs, fill, send. 96 | while (bufPosemplace_back(keyStr, val); 116 | // Send. 117 | if (batchVec->size() > BATCH_SIZE_READER){ 118 | sendBatch(); 119 | } 120 | 121 | } 122 | output["out"].send(); 123 | return (raft::stop); 124 | // exit(0); 125 | 126 | // Return / push. 127 | return (raft::proceed); 128 | } 129 | }; 130 | } 131 | } 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /backend/src/kernels/clfr_writer.h: -------------------------------------------------------------------------------- 1 | // writes clfrs to a binary file. 2 | #ifndef STARFLOW_KERNELS_CLFR_WRITER 3 | #define STARFLOW_KERNELS_CLFR_WRITER 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include // std::max 17 | #include 18 | 19 | using namespace std; 20 | using namespace std::chrono; 21 | 22 | 23 | #include "starFlow.h" 24 | #include "flat_hash_map.hpp" 25 | 26 | namespace starflow { 27 | namespace kernels { 28 | template 29 | class ClfrWriter : public raft::kernel 30 | { 31 | ofstream o; 32 | uint64_t clfrCt = 0; 33 | uint64_t pktCt = 0; 34 | uint64_t byteCt = 0; 35 | 36 | public: 37 | ClfrWriter(const std::string& fn) : raft::kernel() { 38 | std::cout << "# writing CLFRs to: " << fn << std::endl; 39 | o.open(fn, ios::binary); 40 | input.template add_port("in"); 41 | } 42 | virtual ~ClfrWriter(){ 43 | std::cout << "# wrote " << clfrCt << " clfrs (" << byteCt << "bytes ) representing " << pktCt << " packets " << endl; 44 | float bytesPerPkt = byteCt / float(pktCt); 45 | float pktsPerClfr = float(pktCt) / clfrCt; 46 | std::cout << "# bytes per packet: " << bytesPerPkt << endl; 47 | std::cout << "# packets per record: " << pktsPerClfr << endl; 48 | o.close(); 49 | } 50 | raft::kstatus run() override { 51 | auto &clfrBatch(input["in"].template peek()); 52 | for (auto kv : clfrBatch) { 53 | clfrCt += 1; 54 | pktCt += kv.second.flowFeatures.pktCt; 55 | o.write(kv.first.c_str(), KEYLEN); 56 | byteCt += KEYLEN; 57 | // sanity check. 58 | if (kv.second.flowFeatures.pktCt != kv.second.packetVector.size()){ 59 | std::cout << "size error: " << kv.second.flowFeatures.pktCt << " vec len: " << kv.second.packetVector.size() << std::endl; 60 | exit(1); 61 | } 62 | o.write((char *)&(kv.second.flowFeatures), sizeof(kv.second.flowFeatures)); 63 | byteCt += sizeof(kv.second.flowFeatures); 64 | for (auto pf : kv.second.packetVector){ 65 | o.write((char *)&pf, sizeof(pf)); 66 | byteCt += sizeof(pf); 67 | } 68 | } 69 | input["in"].recycle(); 70 | } 71 | }; 72 | } 73 | } 74 | #endif -------------------------------------------------------------------------------- /backend/src/kernels/defs.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonch/StarFlow/08c6d65b4e4b31065a471a8bcbe29b56455b4508/backend/src/kernels/defs.h -------------------------------------------------------------------------------- /backend/src/kernels/feature_calculator.h: -------------------------------------------------------------------------------- 1 | // Calculate flow statistics from clfrs. 2 | // This is an example of a lightweight kernel 3 | // (it doesn't spend much time on each item) 4 | #ifndef STARFLOW_KERNELS_FEATURE_CALCULATOR 5 | #define STARFLOW_KERNELS_FEATURE_CALCULATOR 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | using namespace std; 17 | using namespace std::chrono; 18 | 19 | // include FLOW_FEATURE_CT aggregate features and 20 | // packet-level features from MEAS_PKT_CT in each flow 21 | #define FLOW_FEATURE_CT 12 22 | #define MEAS_PKT_CT 8 23 | 24 | namespace starflow { 25 | namespace kernels { 26 | template 27 | class FeatureCalculator : public raft::kernel 28 | { 29 | public: 30 | 31 | // Output: batches of (key, featureVec) pairs 32 | using output_t = std::vector>>; 33 | 34 | explicit FeatureCalculator() 35 | : raft::kernel() 36 | { 37 | input.template add_port("in"); 38 | output.template add_port("out"); 39 | } 40 | 41 | void computeStats(std::vector &featureVec, std::vector &v){ 42 | // mean 43 | double sum = std::accumulate(std::begin(v), std::end(v), 0.0); 44 | double m = sum / v.size(); 45 | featureVec.push_back(m); 46 | 47 | // std dev 48 | double accum = 0.0; 49 | std::for_each (std::begin(v), std::end(v), [&](const double d) { 50 | accum += (d - m) * (d - m); 51 | }); 52 | double stdev = sqrt(accum / (v.size()-1)); 53 | featureVec.push_back(stdev); 54 | 55 | // min 56 | double min_val = *std::min_element(std::begin(v), std::end(v)); 57 | featureVec.push_back(min_val); 58 | 59 | // max 60 | double max_val = *std::max_element(std::begin(v), std::end(v)); 61 | featureVec.push_back(max_val); 62 | } 63 | 64 | // Compute flow feature vector 65 | void getFeatures(std::vector &featureVec, CLFR_Value &clfrRec){ 66 | // Get the 3 vectors: packet inter-arrivals, inter-packet lengths, packet lengths 67 | featureVec.reserve(FLOW_FEATURE_CT + MEAS_PKT_CT); 68 | int vecLen = clfrRec.packetVector.size(); 69 | std::vector interArrivals; 70 | interArrivals.reserve(vecLen); 71 | 72 | std::vector packetLens; 73 | packetLens.reserve(vecLen); 74 | 75 | std::vector interPacketLens; 76 | interPacketLens.reserve(vecLen); 77 | int idx = 0; 78 | int64_t lastTs, lastLen; 79 | for (auto pktRec : clfrRec.packetVector){ 80 | if (idx != 0){ 81 | interArrivals.push_back(pktRec.ts-lastTs); 82 | interPacketLens.push_back(pktRec.byteCt - lastLen); 83 | } 84 | packetLens.push_back(pktRec.byteCt); 85 | lastTs = pktRec.ts; 86 | lastLen = pktRec.byteCt; 87 | idx++; 88 | } 89 | // Compute 4 features from each vec: minimum, maximum, mean, std dev 90 | computeStats(featureVec, interArrivals); 91 | computeStats(featureVec, packetLens); 92 | computeStats(featureVec, interPacketLens); 93 | 94 | for (int i = 0; i() ); 102 | auto batchVec = &out; 103 | batchVec->reserve(BATCH_SIZE_READER); 104 | auto &clfrVector(input["in"].template peek()); 105 | for (auto kv : clfrVector) { 106 | std::vector featureVec; 107 | batchVec->emplace_back(kv.first, featureVec); 108 | getFeatures(batchVec->back().second, kv.second); 109 | } 110 | input["in"].recycle(); 111 | output["out"].send(); 112 | return (raft::proceed); 113 | } 114 | }; 115 | } 116 | } 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /backend/src/kernels/flow_rate.h: -------------------------------------------------------------------------------- 1 | // measure rate of a CLFR stream in flows per second 2 | 3 | #ifndef STARFLOW_KERNELS_FLOW_RATE 4 | #define STARFLOW_KERNELS_FLOW_RATE 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | using namespace std::chrono; 10 | 11 | namespace starflow { 12 | namespace kernels { 13 | template 14 | class MeasureFlowRate : public raft::kernel 15 | { 16 | const int BENCHMARK_CT = 1000000; 17 | 18 | public: 19 | high_resolution_clock::time_point last, cur; 20 | 21 | uint64_t flowCounter = 0; 22 | explicit MeasureFlowRate() 23 | : raft::kernel() 24 | { 25 | last = high_resolution_clock::now(); 26 | input.template add_port("in"); 27 | output.template addPort("stats"); 28 | } 29 | 30 | raft::kstatus run() override 31 | { 32 | auto &flowRecBatch(input["in"].template peek()); 33 | flowCounter+= flowRecBatch.size(); 34 | input["in"].recycle(); 35 | 36 | if (flowCounter > BENCHMARK_CT){ 37 | cur = high_resolution_clock::now(); 38 | auto duration = duration_cast( cur - last ).count(); 39 | output["stats"].push(1000.0*(float(flowCounter)/float(duration))); 40 | flowCounter = 0; 41 | last = high_resolution_clock::now(); 42 | } 43 | return (raft::proceed); 44 | } 45 | }; 46 | } 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /backend/src/kernels/microburst_detector.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_MICROBURST_DETECTOR 3 | #define STARFLOW_KERNELS_MICROBURST_DETECTOR 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | using namespace std::chrono; 14 | 15 | 16 | // Identifies the hosts responsible for microbursts. 17 | 18 | #define BENCHMARK_CT_MICROBURST 100000 19 | 20 | #ifndef UINT32_MAX 21 | #define UINT32_MAX (0xffffffff) 22 | #endif 23 | 24 | namespace starflow { 25 | namespace kernels { 26 | 27 | // Data structure to cache flows until they can no longer have packets in the queue. 28 | typedef std::pair CLFR_PAIR_TYPE; 29 | struct CLFR_Pair_comp { 30 | bool operator() (const CLFR_PAIR_TYPE lhs, const CLFR_PAIR_TYPE rhs) const 31 | {return lhs.second.packetVector.back().ts < rhs.second.packetVector.back().ts;} 32 | }; 33 | 34 | typedef std::pair PKT_PAIR_TYPE; 35 | // Data structure to reconstruct the queue at the point in time when a drop happened. 36 | struct Pkt_Pair_comp { 37 | bool operator() (const PKT_PAIR_TYPE lhs, const PKT_PAIR_TYPE rhs) const 38 | {return lhs.second.ts < rhs.second.ts;} 39 | }; 40 | 41 | template 42 | class MicroburstDetector : public raft::kernel 43 | { 44 | public: 45 | std::multiset orderedCache; 46 | CLFR_PAIR_TYPE blankClfrPair; 47 | std::multiset reconstructedQueue; 48 | PKT_PAIR_TYPE blankPktPair; 49 | 50 | // Which packets of each flow are currently in the reconstructed queue. 51 | std::unordered_map startPktIdx; 52 | 53 | uint16_t queueThreshold = 20; 54 | uint16_t lastQueueSize = 0; 55 | 56 | uint64_t pktCounter = 0; 57 | uint64_t counter=0; 58 | 59 | high_resolution_clock::time_point last, cur; 60 | 61 | explicit MicroburstDetector() 62 | : raft::kernel() 63 | { 64 | last = high_resolution_clock::now(); 65 | input.template add_port("in"); 66 | output.template addPort>("out"); 67 | output.template addPort("stats"); 68 | } 69 | 70 | // enqueue packets that arrived before endtime in all currently active flows. 71 | void updateQueue(uint32_t endTime){ 72 | // int oldQueueSize = reconstructedQueue.size(); 73 | for (auto kv : orderedCache){ 74 | startPktIdx.emplace(kv.first, 0); 75 | // update which packets from this flow are in the queue. 76 | for (int idx = startPktIdx[kv.first]; idx endTime){ 79 | startPktIdx[kv.first] = idx; // where to start in next update on this flow. 80 | break; 81 | } 82 | 83 | // place packet into queue reconstructor. 84 | reconstructedQueue.emplace(*(uint32_t *)(kv.first.c_str()), p); 85 | } 86 | } 87 | // cout << "\tinserted " << reconstructedQueue.size()-oldQueueSize << " packets into queue" << endl; 88 | } 89 | 90 | // arrive by start time, sort by end time. 91 | raft::kstatus run() override 92 | { 93 | // get a ref to the clfr batch. 94 | auto &clfrVector(input["in"].template peek()); 95 | 96 | counter+= clfrVector.size(); 97 | 98 | for (auto kv : clfrVector){ 99 | pktCounter += kv.second.packetVector.size(); 100 | // Insert into cache. 101 | orderedCache.insert(kv); 102 | 103 | // calculate max queue size. 104 | uint16_t localMaxSize = 0; 105 | uint32_t localMaxTime = 0; 106 | uint32_t sizeTally =0; 107 | uint32_t numAboveThreshold = 0; 108 | for (auto p : kv.second.packetVector){ 109 | if (p.queueSize > localMaxSize){ 110 | localMaxSize = p.queueSize; 111 | localMaxTime = p.ts; 112 | } 113 | sizeTally+=p.queueSize; 114 | if (p.queueSize ==24){ 115 | numAboveThreshold++; 116 | } 117 | } 118 | double avgSize = double(sizeTally) / double(kv.second.packetVector.size()); 119 | double pctAboveThreshold = double(numAboveThreshold) / double(kv.second.packetVector.size()); 120 | // do queue processing for important flows. 121 | uint32_t src = *(uint32_t *)(kv.first.c_str()); 122 | if (1){ 123 | // cout << "timeseries[" << kv.second.packetVector[0].ts << "]=" << pctAboveThreshold<= queueThreshold){ 128 | // cout << "\tqueue threshold (" << queueThreshold << ") reached!" << endl; 129 | updateQueue(localMaxTime); 130 | 131 | // walk back from end of queue to find out what sources are the cause. 132 | std::vector packetSrcsInQueue; 133 | for (auto rit = reconstructedQueue.rbegin(); rit!= reconstructedQueue.rend(); ++rit){ 134 | packetSrcsInQueue.push_back((*rit).first); 135 | if (packetSrcsInQueue.size() >= localMaxSize){ 136 | break; 137 | } 138 | } 139 | // std::unordered_set uniqueOffenders; 140 | // for (auto h : packetSrcsInQueue){ 141 | // uniqueOffenders.insert(h); 142 | // } 143 | // cout << " , " << uniqueOffenders.size(); 144 | // cout << "\tHosts in queue:"; 145 | // cout << "occupants["<>() ); 152 | std::unordered_set uniqueOffenders = out; 153 | for (auto h : packetSrcsInQueue){ 154 | uniqueOffenders.insert(h); 155 | } 156 | // cout << "occupants["< nv; 173 | nv.push_back(kv.second.packetVector[0]); 174 | blankClfrPair.second.packetVector = nv; 175 | auto maxOldFlowIt = orderedCache.lower_bound(blankClfrPair); 176 | orderedCache.erase(orderedCache.begin(), maxOldFlowIt); 177 | 178 | // remove packets from reconstructed queue before current flow start time. 179 | blankPktPair.second.ts = kv.second.packetVector[0].ts; 180 | // (neither could be responsible for high queue sizes that future flows observe). 181 | auto maxOldPktIt = reconstructedQueue.lower_bound(blankPktPair); 182 | reconstructedQueue.erase(reconstructedQueue.begin(), maxOldPktIt); 183 | 184 | // cout << "flow cache size: " << orderedCache.size() << " reconstructedQueue size: " << reconstructedQueue.size() << endl; 185 | } 186 | 187 | input["in"].recycle(); 188 | 189 | // std::cout << "counter: " << counter << std::endl; 190 | if (pktCounter > BENCHMARK_CT_MICROBURST) { 191 | // calculate and report throughput in packets per second. 192 | cur = high_resolution_clock::now(); 193 | auto duration = duration_cast( cur - last ).count(); 194 | output["stats"].push(1000.0*(float(pktCounter)/float(duration))); 195 | 196 | // std::cout << std::fixed << "time to process " << BENCHMARK_CT_MICROBURST << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 197 | pktCounter = 0; 198 | last = high_resolution_clock::now(); 199 | } 200 | 201 | return (raft::proceed); 202 | } 203 | }; 204 | } 205 | } 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /backend/src/kernels/microflow_reader.h: -------------------------------------------------------------------------------- 1 | // Reads microflows from a binary file, converts them to clfrs, and streams them out. 2 | #ifndef STARFLOW_KERNELS_MICROFLOW_READER 3 | #define STARFLOW_KERNELS_MICROFLOW_READER 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include // std::max 18 | #include 19 | 20 | using namespace std; 21 | using namespace std::chrono; 22 | 23 | 24 | #include "starFlow.h" 25 | #include "flat_hash_map.hpp" 26 | 27 | #define CLFR_BATCH_SIZE 300 28 | #define MF_BATCH_SIZE 500 29 | 30 | namespace starflow { 31 | namespace kernels { 32 | class MicroflowReader : public raft::kernel 33 | { 34 | 35 | public: 36 | // output type: this kernel emits batches of CLFRs. 37 | using output_t = std::vector>; 38 | // ptr to current batch vector 39 | std::vector> * batchVec = NULL; 40 | 41 | char * inBuf, * bufPos, * bufEnd; // Buffer where microflows from PFEs end up. 42 | 43 | // CLFR hash table. 44 | ska::flat_hash_map CLFR_flatmap; 45 | CLFR_Value blankValue; 46 | 47 | // Timeout stuff, in usec. 48 | uint32_t timeoutCheckPeriod = 5000*1000; // 5 seconds. 49 | uint32_t timeoutThreshold = 10000*1000; // 10 seconds. 50 | uint32_t curTs = 0; 51 | uint32_t lastCheckTs = 0; 52 | 53 | uint64_t mfCt = 0; 54 | uint64_t totalMfCt = 0; 55 | uint64_t finCt = 0; 56 | uint64_t timeoutCt = 0; 57 | 58 | // Load the eval data set into RAM. This would be done by the NIC. 59 | void loadMicroflows(const char *inFile){ 60 | FILE *f = fopen(inFile, "rb"); 61 | fseek(f, 0, SEEK_END); 62 | long f_sz = ftell(f); 63 | fseek(f, 0, SEEK_SET); 64 | std::cout << "# loading " << f_sz << " bytes of microflows." << std::endl; 65 | inBuf = (char *) malloc(f_sz); 66 | std::cout << "# finished mallocing" << std::endl; 67 | fread((char *)inBuf, f_sz, 1, f); 68 | fclose(f); 69 | std::cout << "# finished reading" << std::endl; 70 | bufPos = inBuf; 71 | bufEnd = inBuf + f_sz; 72 | } 73 | 74 | MicroflowReader(const std::string& fn) : raft::kernel() 75 | { 76 | 77 | // Load microflows in. 78 | loadMicroflows(fn.c_str()); 79 | // Read number of microflows in benchmark file. 80 | ifstream insz; 81 | insz.open(fn + std::string(".len"), ios::binary); 82 | insz.read((char*)&totalMfCt, sizeof(totalMfCt)); 83 | insz.close(); 84 | 85 | // Configure the stream processing outputs. 86 | output.template addPort("out"); 87 | 88 | // initial hash table size 89 | CLFR_flatmap.reserve(262144); 90 | 91 | blankValue.flowFeatures = {0}; 92 | blankValue.packetVector.reserve(4); 93 | } 94 | 95 | void sendBatch(){ 96 | // Send the output vector. 97 | output["out"].send(); 98 | // Get new batch vec. 99 | auto &out( output["out"].template allocate() ); 100 | batchVec = &out; 101 | batchVec->reserve(CLFR_BATCH_SIZE); 102 | } 103 | 104 | // Check flows for timeouts. 105 | void timeoutFlows(){ 106 | uint64_t newTimeouts = 0; 107 | for (auto kv : CLFR_flatmap){ 108 | if (curTs - kv.second.packetVector.back().ts > timeoutThreshold){ 109 | // std::cout << " timeout: " << kv.second.packetVector.back().ts << " cur: " << curTs << std::endl; 110 | batchVec->emplace_back(kv.first, kv.second); 111 | CLFR_flatmap.erase(kv.first); 112 | timeoutCt++; 113 | newTimeouts++; 114 | if (batchVec->size() > CLFR_BATCH_SIZE){ 115 | sendBatch(); 116 | } 117 | 118 | } 119 | } 120 | // std :: cout << "new timeouts: " << newTimeouts << std::endl; 121 | lastCheckTs = curTs; 122 | } 123 | 124 | void flushFlows(){ 125 | uint64_t newTimeouts = 0; 126 | for (auto kv : CLFR_flatmap){ 127 | if (curTs - kv.second.packetVector.back().ts > 0){ 128 | // std::cout << " timeout: " << kv.second.packetVector.back().ts << " cur: " << curTs << std::endl; 129 | batchVec->emplace_back(kv.first, kv.second); 130 | CLFR_flatmap.erase(kv.first); 131 | timeoutCt++; 132 | newTimeouts++; 133 | if (batchVec->size() > CLFR_BATCH_SIZE){ 134 | sendBatch(); 135 | } 136 | 137 | } 138 | } 139 | } 140 | 141 | // Aggregate MF_BATCH_SIZE microflow, add finished flows to output. 142 | void readMicroflows(){ 143 | 144 | char * key_chr; 145 | FlowFeatures * flow_features; 146 | PacketFeatures *pkt_features; 147 | // Parse MF_BATCH_SIZE microflows. 148 | for (int i=0; i<(MF_BATCH_SIZE-batchVec->size())+1; i++){ 149 | // parse key. 150 | key_chr = bufPos; 151 | bufPos += KEYLEN; 152 | // parse flow features. 153 | flow_features = (FlowFeatures *) bufPos; 154 | bufPos += sizeof(FlowFeatures); 155 | 156 | // parse packet features. 157 | pkt_features = (PacketFeatures *) bufPos; 158 | bufPos+= sizeof(PacketFeatures) * flow_features->pktCt; 159 | 160 | // insert. 161 | std::string keyStr = std::string(key_chr, 13); 162 | 163 | auto got = CLFR_flatmap.find(keyStr); 164 | if (got == CLFR_flatmap.end()){ 165 | CLFR_flatmap[keyStr] = blankValue; 166 | got = CLFR_flatmap.find(keyStr); 167 | } 168 | 169 | // update flow features. 170 | got->second.flowFeatures.pktCt+= flow_features->pktCt; 171 | // append packet features to vectors. 172 | for (int i=0; ipktCt; i++){ 173 | got->second.packetVector.push_back(*pkt_features); 174 | pkt_features++; 175 | } 176 | // estimate cur ts, for timeouts. 177 | curTs = std::max(curTs, got->second.packetVector.back().ts); 178 | 179 | // std::cout << " ----" << std::endl; 180 | // Evict if fin. 181 | if (((flow_features->th_flags & TH_FIN) == TH_FIN) || ((flow_features->th_flags & TH_RST) == TH_RST)) { 182 | batchVec->emplace_back(keyStr, got->second); 183 | finCt++; 184 | CLFR_flatmap.erase(keyStr); 185 | } 186 | if (batchVec->size() > CLFR_BATCH_SIZE){ 187 | sendBatch(); 188 | } 189 | } 190 | if (batchVec->size() > CLFR_BATCH_SIZE){ 191 | sendBatch(); 192 | } 193 | mfCt+= MF_BATCH_SIZE; 194 | } 195 | 196 | // Read microflows from a per-port file, emit batches of CLFRs. 197 | raft::kstatus run() override 198 | { 199 | if (batchVec == NULL){ 200 | // Get new batch vec. 201 | auto &out( output["out"].template allocate() ); 202 | batchVec = &out; 203 | batchVec->reserve(CLFR_BATCH_SIZE); 204 | } 205 | // Read microflows and push a batch of completed flows. 206 | readMicroflows(); 207 | 208 | // Check timeouts if necessary and push batches of timed-out flows. 209 | if (curTs - lastCheckTs > timeoutCheckPeriod){ 210 | timeoutFlows(); 211 | } 212 | 213 | // EOF 214 | if ((mfCt+MF_BATCH_SIZE) > totalMfCt){ 215 | cout << "read " << mfCt << " microflows " << endl; 216 | flushFlows(); 217 | 218 | return (raft::stop); 219 | } 220 | return (raft::proceed); 221 | } 222 | 223 | }; 224 | } 225 | } 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /backend/src/kernels/old/benchmark_printer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_BENCHMARK_PRINTER 3 | #define STARFLOW_KERNELS_BENCHMARK_PRINTER 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | #include 15 | 16 | namespace starflow { 17 | namespace kernels { 18 | template 19 | class BenchmarkPrinter : public raft::kernel 20 | { 21 | public: 22 | // Tracks and summarizes throughput stats from multiple ports. 23 | #define BENCHMARK_CT 1000000 24 | 25 | int inC; 26 | 27 | std::unordered_map portStats; 28 | int ctr = 0; 29 | explicit BenchmarkPrinter(int inputPortCt) 30 | : raft::kernel() 31 | { 32 | inC = inputPortCt; 33 | // Configure the stream processing outputs. 34 | for (int i=0; i(std::to_string(i)); 38 | } 39 | cout << "stats = {}" << endl; 40 | cout << "combined = []" << endl; 41 | } 42 | 43 | raft::kstatus run() override 44 | { 45 | 46 | cout << std::fixed << "stats[" << ctr << "]=["; 47 | double combined = 0; 48 | for (int i = 0; i 6 | #include 7 | using namespace std; 8 | using namespace std::chrono; 9 | 10 | 11 | 12 | namespace starflow { 13 | namespace kernels { 14 | template 15 | class ClfrCounter : public raft::kernel 16 | { 17 | // Counts CLFRs, gives periodic statistic updates. 18 | #define BENCHMARK_CT 1000000 19 | 20 | 21 | public: 22 | high_resolution_clock::time_point last, cur; 23 | 24 | uint64_t counter=0; 25 | uint64_t flowCounter = 0; 26 | uint64_t pktCounter = 0; 27 | explicit ClfrCounter() 28 | : raft::kernel() 29 | { 30 | last = high_resolution_clock::now(); 31 | input.template add_port("in"); 32 | } 33 | 34 | raft::kstatus run() override 35 | { 36 | 37 | // some black magic to get a refrecne to the CLFR batch object. 38 | auto &clfrVector(input["in"].template peek()); 39 | counter+= clfrVector.size(); 40 | flowCounter+= clfrVector.size(); 41 | for (auto rec : clfrVector){ 42 | pktCounter += rec.second.packetVector.size(); 43 | } 44 | // std::cout << clfr.timeStamps[0] << endl; 45 | 46 | // input["in"].unpeek(); // unpeek if it remains in the stream. 47 | input["in"].recycle(); // recycle to move to next item. 48 | 49 | // std::cout << "counter: " << counter << std::endl; 50 | if (counter > BENCHMARK_CT){ 51 | // std::cout << "read " << counter << " CLFRs " << endl; 52 | // report throughput. 53 | // cur = high_resolution_clock::now(); 54 | // auto duration = duration_cast( cur - last ).count(); 55 | // std::cout << std::fixed << "time to get " << BENCHMARK_CT << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 56 | // std::cout << "packet count: " << pktCounter << " CLFR count: " << flowCounter << endl; 57 | // counter = 0; 58 | // last = high_resolution_clock::now(); 59 | } 60 | 61 | return (raft::proceed); 62 | } 63 | }; 64 | } 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /backend/src/kernels/old/clfr_counter_chain.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_COUNTER_CHAIN 3 | #define STARFLOW_KERNELS_CLFR_COUNTER_CHAIN 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | using namespace std::chrono; 9 | 10 | 11 | 12 | namespace starflow { 13 | namespace kernels { 14 | template 15 | class ClfrCounterChain : public raft::kernel 16 | { 17 | // Counts CLFRs, gives periodic statistic updates. 18 | #define BENCHMARK_CT 1000000 19 | 20 | 21 | public: 22 | high_resolution_clock::time_point last, cur; 23 | uint64_t counter=0; 24 | explicit ClfrCounterChain() 25 | : raft::kernel() 26 | { 27 | last = high_resolution_clock::now(); 28 | input.template add_port("in"); 29 | output.template add_port("out"); 30 | } 31 | 32 | raft::kstatus run() override 33 | { 34 | 35 | // some black magic to get a refrecne to the CLFR batch object. 36 | auto &clfrVector(input["in"].template peek()); 37 | counter+= clfrVector.size(); 38 | // std::cout << clfr.timeStamps[0] << endl; 39 | 40 | // Send to next counter. 41 | auto out( output["out"].template allocate_s() ); 42 | (*out) = clfrVector; 43 | 44 | // input["in"].unpeek(); // unpeek if it remains in the stream. 45 | input["in"].recycle(); // recycle to move to next item. 46 | 47 | 48 | // std::cout << "counter: " << counter << std::endl; 49 | if (counter > BENCHMARK_CT){ 50 | // std::cout << "read " << counter << " CLFRs " << endl; 51 | // report throughput. 52 | cur = high_resolution_clock::now(); 53 | auto duration = duration_cast( cur - last ).count(); 54 | // if (doPrint){ 55 | // std::cout << std::fixed << "time to get " << BENCHMARK_CT << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 56 | // } 57 | counter = 0; 58 | last = high_resolution_clock::now(); 59 | } 60 | 61 | return (raft::proceed); 62 | } 63 | }; 64 | } 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /backend/src/kernels/old/clfr_counter_replicated.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_COUNTER_REPLICATED 3 | #define STARFLOW_KERNELS_CLFR_COUNTER_REPLICATED 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | using namespace std::chrono; 9 | 10 | 11 | 12 | namespace starflow { 13 | namespace kernels { 14 | template 15 | class ClfrCounterReplicated : public raft::kernel 16 | { 17 | // Counts CLFRs, gives periodic statistic updates. 18 | #define BENCHMARK_CT 1000000 19 | 20 | 21 | public: 22 | int replicaId; 23 | high_resolution_clock::time_point last, cur; 24 | 25 | uint64_t counter=0; 26 | uint64_t total = 0; 27 | explicit ClfrCounterReplicated(int rid) 28 | : raft::kernel() 29 | { 30 | replicaId = rid; 31 | last = high_resolution_clock::now(); 32 | input.template add_port("in"); 33 | output.template add_port("stats"); 34 | } 35 | 36 | raft::kstatus run() override 37 | { 38 | if ((total == 0) && (counter == 0)) 39 | last = high_resolution_clock::now(); 40 | 41 | // some black magic to get a refrecne to the CLFR batch object. 42 | auto &clfrVector(input["in"].template peek()); 43 | counter+= clfrVector.size(); 44 | // std::cout << clfr.timeStamps[0] << endl; 45 | 46 | // input["in"].unpeek(); // unpeek if it remains in the stream. 47 | input["in"].recycle(); // recycle to move to next item. 48 | 49 | // std::cout << "counter: " << counter << std::endl; 50 | if (counter > BENCHMARK_CT){ 51 | total += counter; 52 | // std::cout << "read " << counter << " CLFRs " << endl; 53 | // report throughput. 54 | cur = high_resolution_clock::now(); 55 | auto duration = duration_cast( cur - last ).count(); 56 | // std::cout << "replica id: " << replicaId << std::fixed << " time to get " << total << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(total)/float(duration)) << std::endl; 57 | counter =0; 58 | // Push latest throughput value to stat tracker. 59 | output["stats"].push(1000.0*(float(total)/float(duration))); 60 | } 61 | 62 | return (raft::proceed); 63 | } 64 | }; 65 | } 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /backend/src/kernels/old/clfr_reader copy.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_READER 3 | #define STARFLOW_KERNELS_CLFR_READER 4 | 5 | #include "starFlow.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | 15 | #include "flat_hash_map.hpp" 16 | 17 | #define BATCH_SIZE_READER 100 18 | 19 | namespace starflow { 20 | namespace kernels { 21 | class ClfrReader : public raft::kernel 22 | { 23 | public: 24 | 25 | char * inBuf; // Buffer for CLFRs to replay. 26 | char * bufPos; 27 | char * bufEnd; 28 | 29 | // output type: what the kernel emits. 30 | // A batch of CLFRs. 31 | using output_t = std::vector>; 32 | 33 | // ptr to a reference. 34 | std::vector> * batchVec = NULL; 35 | 36 | // for profiling. 37 | high_resolution_clock::time_point last, cur; 38 | 39 | // Load the eval data set into RAM. This would be done by the NIC. 40 | void loadClfrs(const char *inFile){ 41 | FILE *f = fopen(inFile, "rb"); 42 | fseek(f, 0, SEEK_END); 43 | long f_sz = ftell(f); 44 | fseek(f, 0, SEEK_SET); 45 | std::cout << "loading " << f_sz << " bytes of CLFRs." << std::endl; 46 | inBuf = (char *) malloc(f_sz); 47 | std::cout << "finished mallocing" << std::endl; 48 | fread((char *)inBuf, f_sz, 1, f); 49 | fclose(f); 50 | std::cout << "finished reading" << std::endl; 51 | bufPos = inBuf; 52 | bufEnd = inBuf + f_sz; 53 | } 54 | 55 | ClfrReader(const std::string& fn) : raft::kernel() 56 | { 57 | last = high_resolution_clock::now(); 58 | 59 | // Load microflows in. 60 | loadClfrs(fn.c_str()); 61 | 62 | // Configure the stream processing outputs. 63 | output.template add_port("out"); 64 | } 65 | 66 | void sendBatch(){ 67 | // Send the output vector. 68 | output["out"].send(); 69 | // Get new batch vec. 70 | auto &out( output["out"].template allocate() ); 71 | batchVec = &out; 72 | batchVec->reserve(BATCH_SIZE_READER); 73 | } 74 | 75 | raft::kstatus run() override 76 | { 77 | if (batchVec == NULL){ 78 | // Get new batch vec. 79 | auto &out( output["out"].template allocate() ); 80 | batchVec = &out; 81 | batchVec->reserve(BATCH_SIZE_READER); 82 | } 83 | 84 | uint64_t ctr = 0; 85 | // Parse CLFRs, fill, send. 86 | while (bufPosemplace_back(keyStr, val); 103 | // Send. 104 | if (batchVec->size() > BATCH_SIZE_READER){ 105 | sendBatch(); 106 | } 107 | } 108 | // std::cout << "done replaying CLFRs." << std::endl; 109 | output["out"].send(); 110 | return (raft::stop); 111 | // exit(0); 112 | 113 | // Return / push. 114 | return (raft::proceed); 115 | } 116 | }; 117 | } 118 | } 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /backend/src/kernels/old/cloner.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_CLONER 3 | #define STARFLOW_KERNELS_CLFR_CLONER 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | 15 | 16 | 17 | namespace starflow { 18 | namespace kernels { 19 | template 20 | class ClfrCloner : public raft::kernel 21 | { 22 | public: 23 | // Counts CLFRs, gives periodic statistic updates. 24 | #define BENCHMARK_CT 1000000 25 | high_resolution_clock::time_point last, cur; 26 | 27 | int outC; 28 | 29 | uint64_t counter=0; 30 | explicit ClfrCloner(int outputPortCt) 31 | : raft::kernel() 32 | { 33 | outC = outputPortCt; 34 | last = high_resolution_clock::now(); 35 | input.template addPort("in"); 36 | // Configure the stream processing outputs. 37 | for (int i=0; i(std::to_string(i)); 40 | } 41 | } 42 | 43 | raft::kstatus run() override 44 | { 45 | 46 | // some black magic to get a refrecne to the CLFR batch object. 47 | auto &clfrVector(input["in"].template peek()); 48 | counter+= clfrVector.size(); 49 | // std::cout << clfr.timeStamps[0] << endl; 50 | 51 | for (int i = 0; i() ); 53 | auto out( output[std::to_string(i)].template allocate_s() ); 54 | (*out) = clfrVector; 55 | // output[std::to_string(i)].send(); 56 | } 57 | 58 | // input["in"].unpeek(); // unpeek if it remains in the stream. 59 | input["in"].recycle(); // recycle to move to next item. 60 | 61 | // std::cout << "counter: " << counter << std::endl; 62 | if (counter > BENCHMARK_CT){ 63 | // std::cout << "read " << counter << " CLFRs " << endl; 64 | // report throughput. 65 | cur = high_resolution_clock::now(); 66 | auto duration = duration_cast( cur - last ).count(); 67 | std::cout << std::fixed << "# outputs: " << outC << " time to clone: " << BENCHMARK_CT << " clfrs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 68 | counter = 0; 69 | last = high_resolution_clock::now(); 70 | } 71 | 72 | return (raft::proceed); 73 | } 74 | }; 75 | } 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /backend/src/kernels/old/counter.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_COUNTER 3 | #define STARFLOW_KERNELS_COUNTER 4 | 5 | namespace starflow { 6 | namespace kernels { 7 | template 8 | class Counter : public raft::kernel 9 | { 10 | public: 11 | Counter() : raft::kernel() 12 | { 13 | input.template add_port("in"); 14 | output.add_port("out"); 15 | } 16 | 17 | raft::kstatus run() override 18 | { 19 | T t; 20 | input["in"].pop(t); 21 | 22 | auto out(output["out"].template allocate_s()); 23 | *out = ++_counter; 24 | 25 | return(raft::proceed); 26 | } 27 | 28 | private: 29 | unsigned long long _counter = 0; 30 | }; 31 | } 32 | } 33 | 34 | 35 | #endif -------------------------------------------------------------------------------- /backend/src/kernels/old/host_timing_profiler.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_HOST_PROFILER 3 | #define STARFLOW_KERNELS_HOST_PROFILER 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | using namespace std::chrono; 12 | 13 | #include "flat_hash_map.hpp" 14 | 15 | // Builds a timing profile of each monitored source address. 16 | // (example 1) 17 | 18 | #define DUMP 1 19 | #define STATS 1 20 | #define BENCHMARK 1 21 | #define BENCHMARK_CT 1000000 22 | 23 | 24 | 25 | namespace starflow { 26 | namespace kernels { 27 | template 28 | class HostProfiler : public raft::kernel 29 | { 30 | public: 31 | const char * outFileName; 32 | uint32_t profileDuration = 0; 33 | 34 | high_resolution_clock::time_point last, cur, start, end; 35 | ska::flat_hash_map> hostTimes; 36 | std::vector blankValue; 37 | uint32_t startTs = 0; 38 | uint32_t endTs = 0; 39 | 40 | 41 | uint64_t counter=0; 42 | 43 | // input: profile dump file name, duration of profile (ms). 44 | explicit HostProfiler(const char *of, uint32_t profDur) 45 | : raft::kernel() 46 | { 47 | outFileName = of; 48 | profileDuration = profDur; 49 | last = high_resolution_clock::now(); 50 | start = high_resolution_clock::now(); 51 | input.template add_port("in"); 52 | } 53 | 54 | // Dump profile. Format: host ip, # arrivals, timestamps (all uint_64) 55 | void dumpProfile(){ 56 | std::cout << "dumping profile to: " << outFileName << std::endl; 57 | ofstream o; 58 | o.open(outFileName, ios::binary); 59 | uint64_t tsesWritten = 0; 60 | for (auto kv : hostTimes){ 61 | uint32_t hostIp = kv.first; 62 | uint32_t tsCt = uint32_t(kv.second.size()); 63 | o.write((char *) &hostIp, sizeof(hostIp)); 64 | o.write((char *) &tsCt, sizeof(tsCt)); 65 | for (auto ts : kv.second){ 66 | o.write((char *) &ts, sizeof(ts)); 67 | tsesWritten++; 68 | } 69 | } 70 | o.close(); 71 | std::cout << "\twrote " << tsesWritten << " timestamps" << std::endl; 72 | } 73 | 74 | raft::kstatus run() override 75 | { 76 | // get a referecne to the CLFR batch object. 77 | auto &clfrVector(input["in"].template peek()); 78 | // handle a batch. 79 | for (auto kv : clfrVector){ 80 | // key is src addr. 81 | uint32_t key = *((uint32_t *) &(kv.first.c_str()[4])); 82 | 83 | auto got = hostTimes.find(key); 84 | if (got == hostTimes.end()){ 85 | hostTimes[key] = blankValue; 86 | got = hostTimes.find(key); 87 | } 88 | // update profile. 89 | for (auto pfs : kv.second.packetVector){ 90 | got->second.push_back(pfs.ts); 91 | #ifdef STATS 92 | endTs = max(pfs.ts, endTs); 93 | #endif 94 | } 95 | } 96 | 97 | // handleBatch(clfrVector); 98 | 99 | input["in"].recycle(); // recycle to move to next item. 100 | 101 | // for benchmarking. 102 | #ifdef BENCHMARK 103 | counter+= clfrVector.size(); 104 | 105 | if (counter > BENCHMARK_CT){ 106 | // std::cout << "read " << counter << " CLFRs " << endl; 107 | // report throughput. 108 | cur = high_resolution_clock::now(); 109 | auto duration = duration_cast( cur - last ).count(); 110 | std::cout << std::fixed << "time to gen host profiles with " << BENCHMARK_CT << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 111 | counter = 0; 112 | last = high_resolution_clock::now(); 113 | 114 | #ifdef STATS 115 | std::cout << "number of hosts: " << hostTimes.size() << " time interval represented: " << (endTs - startTs)/1000.0 << " (ms)" << std::endl; 116 | #endif 117 | 118 | } 119 | #endif 120 | 121 | #ifdef DUMP 122 | // Dump profile and exit (entire app for now). 123 | if ((endTs - startTs) > (profileDuration*1000)){ 124 | end = high_resolution_clock::now(); 125 | auto duration = duration_cast( end - start ).count(); 126 | std::cout << "total time to get profile: " << duration << " ms" << std::endl; 127 | dumpProfile(); 128 | // return (raft::stop); 129 | exit(0); 130 | 131 | } 132 | #endif 133 | 134 | return (raft::proceed); 135 | } 136 | 137 | // void handleBatch(std::vector batchVector){ 138 | 139 | // } 140 | 141 | 142 | }; 143 | } 144 | } 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /backend/src/kernels/old/ip_source_timestamps.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_IP_SOURCE_TIMESTAMPS 3 | #define STARFLOW_KERNELS_IP_SOURCE_TIMESTAMPS 4 | 5 | #include 6 | #include 7 | #include 8 | #include "../flow.h" 9 | #include "../flow_table.h" 10 | 11 | namespace starflow { 12 | namespace kernels { 13 | class IPSourceTimestamps : public raft::kernel 14 | { 15 | public: 16 | 17 | using input_t = std::pair; 18 | using output_t = std::pair>; 19 | 20 | IPSourceTimestamps() : raft::kernel() 21 | { 22 | input.add_port("in"); 23 | output.add_port("out"); 24 | } 25 | 26 | raft::kstatus run() override 27 | { 28 | input_t flow; 29 | input["in"].pop(flow); 30 | 31 | std::list timestamps; 32 | 33 | for (auto& packet : flow.second.packets()) 34 | timestamps.push_back(packet.ts); 35 | 36 | auto out(output["out"].allocate_s()); 37 | auto pair = std::make_pair(flow.first.ip_src, timestamps); 38 | *out = pair; 39 | 40 | std::cout << to_string(pair) << std::endl; 41 | 42 | return(raft::proceed); 43 | } 44 | 45 | static std::string to_string(const output_t& p) 46 | { 47 | std::stringstream ss; 48 | ss << FlowTable::uint32_ip_addr_to_str(p.first) << ":"; 49 | 50 | for (auto& ts : p.second) 51 | ss << " " << ts.count(); 52 | 53 | return ss.str(); 54 | } 55 | }; 56 | } 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /backend/src/kernels/old/join_printer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_PRINTER 3 | #define STARFLOW_KERNELS_PRINTER 4 | 5 | #include 6 | 7 | namespace starflow { 8 | namespace kernels { 9 | template 10 | class Printer : public raft::kernel 11 | { 12 | public: 13 | explicit Printer(std::ostream& os = std::cout, bool endl = true, bool forward = false) 14 | : raft::kernel(), 15 | _os(os), 16 | _endl(endl), 17 | _forward(forward) 18 | { 19 | input.template add_port("in"); 20 | if (_forward) 21 | output.template add_port("out"); 22 | } 23 | 24 | raft::kstatus run() override 25 | { 26 | T t{}; 27 | input["in"].pop(t); 28 | _os << t << (_endl ? '\n' : '\0'); 29 | 30 | if (_forward) { 31 | auto out(output["out"].template allocate_s()); 32 | *out = t; 33 | } 34 | 35 | return (raft::proceed); 36 | } 37 | 38 | private: 39 | std::ostream& _os; 40 | bool _endl; 41 | bool _forward; 42 | }; 43 | } 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /backend/src/kernels/old/microburst_detector.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_MICROBURST_DETECTOR 3 | #define STARFLOW_KERNELS_MICROBURST_DETECTOR 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | using namespace std::chrono; 14 | 15 | 16 | // Identifies the hosts responsible for microbursts. 17 | 18 | #define BENCHMARK_CT_MICROBURST 10000 19 | 20 | #ifndef UINT32_MAX 21 | #define UINT32_MAX (0xffffffff) 22 | #endif 23 | 24 | namespace starflow { 25 | namespace kernels { 26 | 27 | // Data structure to cache flows until they can no longer have packets in the queue. 28 | typedef std::pair CLFR_PAIR_TYPE; 29 | struct CLFR_Pair_comp { 30 | bool operator() (const CLFR_PAIR_TYPE lhs, const CLFR_PAIR_TYPE rhs) const 31 | {return lhs.second.packetVector.back().ts < rhs.second.packetVector.back().ts;} 32 | }; 33 | 34 | typedef std::pair PKT_PAIR_TYPE; 35 | // Data structure to reconstruct the queue at the point in time when a drop happened. 36 | struct Pkt_Pair_comp { 37 | bool operator() (const PKT_PAIR_TYPE lhs, const PKT_PAIR_TYPE rhs) const 38 | {return lhs.second.ts < rhs.second.ts;} 39 | }; 40 | 41 | template 42 | class MicroburstDetector : public raft::kernel 43 | { 44 | public: 45 | std::multiset orderedCache; 46 | CLFR_PAIR_TYPE blankClfrPair; 47 | std::multiset reconstructedQueue; 48 | PKT_PAIR_TYPE blankPktPair; 49 | 50 | // Which packets of each flow are currently in the reconstructed queue. 51 | std::unordered_map startPktIdx; 52 | 53 | uint16_t queueThreshold = 20; 54 | uint16_t lastQueueSize = 0; 55 | 56 | uint64_t counter=0; 57 | 58 | high_resolution_clock::time_point last, cur; 59 | 60 | explicit MicroburstDetector() 61 | : raft::kernel() 62 | { 63 | last = high_resolution_clock::now(); 64 | input.template add_port("in"); 65 | } 66 | 67 | // enqueue packets that arrived before endtime in all currently active flows. 68 | void updateQueue(uint32_t endTime){ 69 | // int oldQueueSize = reconstructedQueue.size(); 70 | for (auto kv : orderedCache){ 71 | startPktIdx.emplace(kv.first, 0); 72 | // update which packets from this flow are in the queue. 73 | for (int idx = startPktIdx[kv.first]; idx endTime){ 76 | startPktIdx[kv.first] = idx; // where to start in next update on this flow. 77 | break; 78 | } 79 | 80 | // place packet into queue reconstructor. 81 | reconstructedQueue.emplace(*(uint32_t *)(kv.first.c_str()), p); 82 | } 83 | } 84 | // cout << "\tinserted " << reconstructedQueue.size()-oldQueueSize << " packets into queue" << endl; 85 | } 86 | 87 | // arrive by start time, sort by end time. 88 | raft::kstatus run() override 89 | { 90 | // get a ref to the clfr batch. 91 | auto &clfrVector(input["in"].template peek()); 92 | counter+= clfrVector.size(); 93 | 94 | for (auto kv : clfrVector){ 95 | // Insert into cache. 96 | orderedCache.insert(kv); 97 | 98 | // calculate max queue size. 99 | uint16_t localMaxSize = 0; 100 | uint32_t localMaxTime = 0; 101 | uint32_t sizeTally =0; 102 | uint32_t numAboveThreshold = 0; 103 | for (auto p : kv.second.packetVector){ 104 | if (p.queueSize > localMaxSize){ 105 | localMaxSize = p.queueSize; 106 | localMaxTime = p.ts; 107 | } 108 | sizeTally+=p.queueSize; 109 | if (p.queueSize ==24){ 110 | numAboveThreshold++; 111 | } 112 | } 113 | double avgSize = double(sizeTally) / double(kv.second.packetVector.size()); 114 | double pctAboveThreshold = double(numAboveThreshold) / double(kv.second.packetVector.size()); 115 | // do queue processing for important flows. 116 | uint32_t src = *(uint32_t *)(kv.first.c_str()); 117 | if (src > 20){ 118 | cout << "timeseries[" << kv.second.packetVector[0].ts << "]=" << pctAboveThreshold<= queueThreshold){ 123 | // cout << "\tqueue threshold (" << queueThreshold << ") reached!" << endl; 124 | updateQueue(localMaxTime); 125 | 126 | // walk back from end of queue to find out what sources are the cause. 127 | std::vector packetSrcsInQueue; 128 | for (auto rit = reconstructedQueue.rbegin(); rit!= reconstructedQueue.rend(); ++rit){ 129 | packetSrcsInQueue.push_back((*rit).first); 130 | if (packetSrcsInQueue.size() >= localMaxSize){ 131 | break; 132 | } 133 | } 134 | std::unordered_set uniqueOffenders; 135 | for (auto h : packetSrcsInQueue){ 136 | uniqueOffenders.insert(h); 137 | } 138 | // cout << " , " << uniqueOffenders.size(); 139 | // cout << "\tHosts in queue:"; 140 | cout << "occupants["< nv; 156 | nv.push_back(kv.second.packetVector[0]); 157 | blankClfrPair.second.packetVector = nv; 158 | auto maxOldFlowIt = orderedCache.lower_bound(blankClfrPair); 159 | orderedCache.erase(orderedCache.begin(), maxOldFlowIt); 160 | 161 | // remove packets from reconstructed queue before current flow start time. 162 | blankPktPair.second.ts = kv.second.packetVector[0].ts; 163 | // (neither could be responsible for high queue sizes that future flows observe). 164 | auto maxOldPktIt = reconstructedQueue.lower_bound(blankPktPair); 165 | reconstructedQueue.erase(reconstructedQueue.begin(), maxOldPktIt); 166 | 167 | // cout << "flow cache size: " << orderedCache.size() << " reconstructedQueue size: " << reconstructedQueue.size() << endl; 168 | } 169 | 170 | input["in"].recycle(); // recycle to move to next item. 171 | 172 | // std::cout << "counter: " << counter << std::endl; 173 | if (counter > BENCHMARK_CT_MICROBURST){ 174 | // std::cout << "read " << counter << " CLFRs " << endl; 175 | // report throughput. 176 | cur = high_resolution_clock::now(); 177 | auto duration = duration_cast( cur - last ).count(); 178 | // std::cout << std::fixed << "time to process " << BENCHMARK_CT_MICROBURST << " CLFRs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 179 | counter = 0; 180 | last = high_resolution_clock::now(); 181 | } 182 | 183 | return (raft::proceed); 184 | } 185 | }; 186 | } 187 | } 188 | 189 | #endif 190 | -------------------------------------------------------------------------------- /backend/src/kernels/old/microflow_reader.h: -------------------------------------------------------------------------------- 1 | // Reads microflows from a binary file, converts them to clfrs, and streams them out. 2 | #ifndef STARFLOW_KERNELS_MICROFLOW_READER 3 | #define STARFLOW_KERNELS_MICROFLOW_READER 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include // std::max 18 | #include 19 | 20 | using namespace std; 21 | using namespace std::chrono; 22 | 23 | 24 | #include "starFlow.h" 25 | #include "flat_hash_map.hpp" 26 | 27 | #define BATCH_SIZE 200 28 | #define MF_BATCH_SIZE 500 29 | 30 | // #define DUMPCLFRS 1 31 | #define BENCHMARK 1 32 | #define BENCHMARK_CT 1000000 33 | 34 | namespace starflow { 35 | namespace kernels { 36 | class MicroflowReader : public raft::kernel 37 | { 38 | 39 | 40 | public: 41 | // output type: what the kernel emits. 42 | // A batch of CLFRs. 43 | using output_t = std::vector>; 44 | // ptr to output batch vector. 45 | std::vector> * batchVec = NULL; 46 | 47 | char * inBuf, * bufPos, * bufEnd; // Buffer where microflows from PFEs end up. 48 | 49 | // A map of CLFRs. 50 | ska::flat_hash_map CLFR_flatmap; 51 | CLFR_Value blankValue; 52 | 53 | // Timeout stuff, in usec. 54 | uint32_t timeoutCheckPeriod = 5000*1000; // 5 seconds. 55 | uint32_t timeoutThreshold = 10000*1000; // 10 seconds. 56 | uint32_t curTs = 0; 57 | uint32_t lastCheckTs = 0; 58 | 59 | 60 | // for profiling. 61 | high_resolution_clock::time_point last, cur; 62 | uint64_t mfCt = 0; 63 | uint64_t totalMfCt = 0; 64 | uint64_t finCt = 0; 65 | uint64_t timeoutCt = 0; 66 | 67 | uint64_t tmpCtr = 0; 68 | uint64_t lastMfCt = 0; 69 | 70 | uint64_t finalMfCt = 0; 71 | uint64_t finalClfrCt = 0; 72 | 73 | uint64_t total = 0; 74 | // for dumping CLFRs, if set. 75 | ofstream o; 76 | 77 | // Load the eval data set into RAM. This would be done by the NIC. 78 | void loadMicroflows(const char *inFile){ 79 | 80 | FILE *f = fopen(inFile, "rb"); 81 | fseek(f, 0, SEEK_END); 82 | long f_sz = ftell(f); 83 | fseek(f, 0, SEEK_SET); 84 | std::cout << "# loading " << f_sz << " bytes of microflows." << std::endl; 85 | inBuf = (char *) malloc(f_sz); 86 | std::cout << "# finished mallocing" << std::endl; 87 | fread((char *)inBuf, f_sz, 1, f); 88 | fclose(f); 89 | std::cout << "# finished reading" << std::endl; 90 | bufPos = inBuf; 91 | bufEnd = inBuf + f_sz; 92 | } 93 | 94 | MicroflowReader(const std::string& fn) : raft::kernel() 95 | { 96 | 97 | // Load microflows in. 98 | loadMicroflows(fn.c_str()); 99 | // Read metadata (# of microflows. ) 100 | ifstream insz; 101 | insz.open(fn + std::string(".len"), ios::binary); 102 | insz.read((char*)&totalMfCt, sizeof(totalMfCt)); 103 | insz.close(); 104 | 105 | // Configure the stream processing outputs. 106 | output.template addPort("out"); 107 | output.template addPort("stats"); 108 | 109 | // initial hash table size 110 | CLFR_flatmap.reserve(262144); 111 | 112 | blankValue.flowFeatures = {0}; 113 | blankValue.packetVector.reserve(4); 114 | #ifdef DUMPCLFRS 115 | std::cout << "dumping CLFRs to: " << fn + std::string(".clfrs") << std::endl; 116 | o.open(fn + std::string(".clfrs"), ios::binary); 117 | #endif 118 | 119 | last = high_resolution_clock::now(); 120 | 121 | } 122 | 123 | void sendBatch(){ 124 | finalClfrCt+=batchVec->size(); 125 | #ifdef DUMPCLFRS 126 | for (auto kv : (*batchVec)){ 127 | o.write(kv.first.c_str(), KEYLEN); 128 | if (kv.second.flowFeatures.pktCt != kv.second.packetVector.size()){ 129 | std::cout << "size error: " << kv.second.flowFeatures.pktCt << " vec len: " << kv.second.packetVector.size() << std::endl; 130 | exit(1); 131 | } 132 | o.write((char *)&(kv.second.flowFeatures), sizeof(kv.second.flowFeatures)); 133 | for (auto pf : kv.second.packetVector){ 134 | o.write((char *)&pf, sizeof(pf)); 135 | } 136 | 137 | } 138 | #endif 139 | // Send the output vector. 140 | output["out"].send(); 141 | // Get new batch vec. 142 | auto &out( output["out"].template allocate() ); 143 | batchVec = &out; 144 | batchVec->reserve(BATCH_SIZE); 145 | } 146 | 147 | // Check flows for timeouts. 148 | // Last update time > 149 | void timeoutFlows(){ 150 | uint64_t newTimeouts = 0; 151 | for (auto kv : CLFR_flatmap){ 152 | if (curTs - kv.second.packetVector.back().ts > timeoutThreshold){ 153 | // std::cout << " timeout: " << kv.second.packetVector.back().ts << " cur: " << curTs << std::endl; 154 | batchVec->emplace_back(kv.first, kv.second); 155 | CLFR_flatmap.erase(kv.first); 156 | timeoutCt++; 157 | newTimeouts++; 158 | if (batchVec->size() > BATCH_SIZE){ 159 | sendBatch(); 160 | } 161 | 162 | } 163 | } 164 | // std :: cout << "new timeouts: " << newTimeouts << std::endl; 165 | lastCheckTs = curTs; 166 | } 167 | 168 | // Aggregate MF_BATCH_SIZE microflow, add finished flows to output. 169 | void readMicroflows(){ 170 | 171 | char * key_chr; 172 | FlowFeatures * flow_features; 173 | PacketFeatures *pkt_features; 174 | // Parse MF_BATCH_SIZE microflows. 175 | for (int i=0; i<(MF_BATCH_SIZE-batchVec->size())+1; i++){ 176 | finalMfCt ++; 177 | // parse key. 178 | key_chr = bufPos; 179 | bufPos += KEYLEN; 180 | // parse flow features. 181 | flow_features = (FlowFeatures *) bufPos; 182 | bufPos += sizeof(FlowFeatures); 183 | 184 | // parse packet features. 185 | pkt_features = (PacketFeatures *) bufPos; 186 | bufPos+= sizeof(PacketFeatures) * flow_features->pktCt; 187 | 188 | // insert. 189 | std::string keyStr = std::string(key_chr, 13); 190 | 191 | auto got = CLFR_flatmap.find(keyStr); 192 | if (got == CLFR_flatmap.end()){ 193 | CLFR_flatmap[keyStr] = blankValue; 194 | got = CLFR_flatmap.find(keyStr); 195 | } 196 | 197 | // update flow features. 198 | got->second.flowFeatures.pktCt+= flow_features->pktCt; 199 | // append packet features to vectors. 200 | for (int i=0; ipktCt; i++){ 201 | got->second.packetVector.push_back(*pkt_features); 202 | pkt_features++; 203 | } 204 | // estimate cur ts, for timeouts. 205 | curTs = std::max(curTs, got->second.packetVector.back().ts); 206 | 207 | // std::cout << " ----" << std::endl; 208 | // Evict if fin. 209 | if (((flow_features->th_flags & TH_FIN) == TH_FIN) || ((flow_features->th_flags & TH_RST) == TH_RST)) { 210 | batchVec->emplace_back(keyStr, got->second); 211 | finCt++; 212 | CLFR_flatmap.erase(keyStr); 213 | } 214 | if (batchVec->size() > BATCH_SIZE){ 215 | sendBatch(); 216 | } 217 | 218 | } 219 | 220 | if (batchVec->size() > BATCH_SIZE){ 221 | sendBatch(); 222 | } 223 | mfCt+= MF_BATCH_SIZE; 224 | } 225 | 226 | // Read microflows from a per-port file, emit batches of CLFRs. 227 | raft::kstatus run() override 228 | { 229 | 230 | if (batchVec == NULL){ 231 | // Get new batch vec. 232 | auto &out( output["out"].template allocate() ); 233 | batchVec = &out; 234 | batchVec->reserve(BATCH_SIZE); 235 | } 236 | // Read microflows and push finished flows to batch vector. 237 | readMicroflows(); 238 | lastMfCt += MF_BATCH_SIZE; 239 | 240 | // Check timeouts, if necessary, push to batch vector. 241 | if (curTs - lastCheckTs > timeoutCheckPeriod){ 242 | timeoutFlows(); 243 | } 244 | 245 | benchmark(); 246 | if ((mfCt+MF_BATCH_SIZE) > totalMfCt){ 247 | // std::cout<<"resetting input buffer." < BENCHMARK_CT ){ 264 | total += lastMfCt; 265 | cur = high_resolution_clock::now(); 266 | auto duration = duration_cast( cur - last ).count(); 267 | // std::cout << std::fixed << "time to process BENCHMARK_CT MFs: " << duration <<" processing rate: " << 1000.0*(float(lastMfCt)/float(duration)) << std::endl; 268 | // std::cout << "fin ct: " << finCt << " timeout ct: " << timeoutCt << std::endl; 269 | // std::cout << "table size: " << CLFR_flatmap.size() << std::endl; 270 | // Push latest throughput value to stat tracker. 271 | output["stats"].push(1000.0*(float(total)/float(duration))); 272 | 273 | lastMfCt = 0; 274 | 275 | // last = high_resolution_clock::now(); 276 | } 277 | 278 | #endif 279 | } 280 | 281 | 282 | }; 283 | } 284 | } 285 | 286 | #endif 287 | -------------------------------------------------------------------------------- /backend/src/kernels/old/printer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_PRINTER 3 | #define STARFLOW_KERNELS_PRINTER 4 | 5 | #include 6 | 7 | namespace starflow { 8 | namespace kernels { 9 | template 10 | class Printer : public raft::kernel 11 | { 12 | public: 13 | explicit Printer(std::ostream& os = std::cout, bool endl = true, bool forward = false) 14 | : raft::kernel(), 15 | _os(os), 16 | _endl(endl), 17 | _forward(forward) 18 | { 19 | input.template add_port("in"); 20 | if (_forward) 21 | output.template add_port("out"); 22 | } 23 | 24 | raft::kstatus run() override 25 | { 26 | T t{}; 27 | input["in"].pop(t); 28 | _os << t << (_endl ? '\n' : '\0'); 29 | 30 | if (_forward) { 31 | auto out(output["out"].template allocate_s()); 32 | *out = t; 33 | } 34 | 35 | return (raft::proceed); 36 | } 37 | 38 | private: 39 | std::ostream& _os; 40 | bool _endl; 41 | bool _forward; 42 | }; 43 | } 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /backend/src/kernels/old/redis_flow_subscriber.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_REDIS_FLOW_SUBSCRIBER 3 | #define STARFLOW_KERNELS_REDIS_FLOW_SUBSCRIBER 4 | 5 | #include "../redis_flow_subscriber.h" 6 | #include 7 | 8 | namespace starflow { 9 | namespace kernels { 10 | class RedisFlowSubscriber : public raft::kernel 11 | { 12 | public: 13 | 14 | using output_t = std::pair; 15 | 16 | RedisFlowSubscriber(const std::string& host, unsigned port, const std::string& topic) 17 | : _redis_subscriber(host, port, topic, 18 | [this](starflow::FlowTable::key_t k, starflow::Flow f) { 19 | _new_flow(k, f); 20 | }) 21 | { 22 | output.add_port("out"); 23 | } 24 | 25 | void _new_flow(starflow::FlowTable::key_t k, starflow::Flow f) 26 | { 27 | auto out(output["out"].allocate_s()); 28 | *out = std::make_pair(k, f); 29 | } 30 | 31 | raft::kstatus run() override 32 | { 33 | _redis_subscriber(); 34 | return(raft::proceed); 35 | } 36 | 37 | private: 38 | starflow::RedisFlowSubscriber _redis_subscriber; 39 | }; 40 | } 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /backend/src/kernels/old/sink.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_SINK 3 | #define STARFLOW_KERNELS_SINK 4 | 5 | 6 | namespace starflow { 7 | namespace kernels { 8 | template 9 | class Sink : public raft::kernel 10 | { 11 | public: 12 | explicit Sink() 13 | : raft::kernel() 14 | { 15 | input.template add_port("in"); 16 | } 17 | 18 | raft::kstatus run() override 19 | { 20 | // T t{}; 21 | // input["in"].pop(t); 22 | 23 | return (raft::proceed); 24 | } 25 | }; 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /backend/src/kernels/old/starFlow.h: -------------------------------------------------------------------------------- 1 | #ifndef STARFLOW_CSTRUCTS 2 | #define STARFLOW_CSTRUCTS 3 | 4 | #include 5 | 6 | #define KEYLEN 13 7 | #define MCLFR_MAXLEN 32 8 | struct PacketFeatures{ 9 | uint16_t queueSize; 10 | uint16_t byteCt; 11 | uint32_t ts; 12 | }; 13 | 14 | struct FlowFeatures { 15 | uint32_t pktCt; 16 | u_char th_flags; 17 | }; 18 | 19 | // Format of switch export. 20 | struct Export_MCLFR { 21 | char key[KEYLEN]; 22 | FlowFeatures flowFeatures; 23 | PacketFeatures packetVector[MCLFR_MAXLEN]; 24 | }; 25 | 26 | struct CLFR_Value { 27 | FlowFeatures flowFeatures; 28 | std::vector packetVector; 29 | }; 30 | 31 | 32 | // format of a clfr. This struct isn't used in the code, 33 | // its just here for reference. In the code, we pass 34 | // a pair. 35 | struct CLFR { 36 | char key[KEYLEN]; 37 | CLFR_Value record; 38 | }; 39 | 40 | #endif -------------------------------------------------------------------------------- /backend/src/kernels/old/tap.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_CLFR_TAP 3 | #define STARFLOW_KERNELS_CLFR_TAP 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace std::chrono; 13 | 14 | 15 | 16 | 17 | namespace starflow { 18 | namespace kernels { 19 | template 20 | class ClfrTap : public raft::kernel 21 | { 22 | public: 23 | // Counts CLFRs, gives periodic statistic updates. 24 | #define BENCHMARK_CT 1000000 25 | high_resolution_clock::time_point last, cur; 26 | 27 | int outC; 28 | 29 | uint64_t counter=0; 30 | explicit ClfrTap(int inputPortCt) 31 | : raft::kernel() 32 | { 33 | outC = inputPortCt; 34 | last = high_resolution_clock::now(); 35 | // input.template addPort("out"); 36 | // Configure the stream processing outputs. 37 | for (int i=0; i(std::to_string(i)); 40 | } 41 | } 42 | 43 | raft::kstatus run() override 44 | { 45 | 46 | // some black magic to get a refrecne to the CLFR batch object. 47 | // std::cout << clfr.timeStamps[0] << endl; 48 | 49 | for (int i = 0; i()); 51 | counter+= clfrVector.size(); 52 | // auto &out( output[std::to_string(i)].template allocate() ); 53 | // auto out( output[out].template allocate_s() ); 54 | // (*out) = clfrVector; 55 | // output[std::to_string(i)].send(); 56 | input[std::to_string(i)].recycle(); // recycle to move to next item. 57 | } 58 | 59 | // std::cout << "counter: " << counter << std::endl; 60 | if (counter > BENCHMARK_CT){ 61 | // std::cout << "read " << counter << " CLFRs " << endl; 62 | // report throughput. 63 | cur = high_resolution_clock::now(); 64 | auto duration = duration_cast( cur - last ).count(); 65 | // std::cout << std::fixed << "# inputs: " << outC << " time to join: " << BENCHMARK_CT << " clfrs: " << duration <<" processing rate: " << 1000.0*(float(counter)/float(duration)) << std::endl; 66 | counter = 0; 67 | last = high_resolution_clock::now(); 68 | } 69 | 70 | return (raft::proceed); 71 | } 72 | }; 73 | } 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /backend/src/kernels/packet_rate.h: -------------------------------------------------------------------------------- 1 | // measure rate of a CLFR stream in packets per second 2 | 3 | #ifndef STARFLOW_KERNELS_PACKET_RATE 4 | #define STARFLOW_KERNELS_PACKET_RATE 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | using namespace std::chrono; 10 | 11 | namespace starflow { 12 | namespace kernels { 13 | template 14 | class MeasurePacketRate : public raft::kernel 15 | { 16 | const int BENCHMARK_CT = 1000000; 17 | 18 | public: 19 | high_resolution_clock::time_point last, cur; 20 | 21 | uint64_t flowCounter = 0; 22 | uint64_t pktCounter = 0; 23 | explicit MeasurePacketRate() 24 | : raft::kernel() 25 | { 26 | last = high_resolution_clock::now(); 27 | input.template add_port("in"); 28 | output.template addPort("stats"); 29 | } 30 | 31 | raft::kstatus run() override 32 | { 33 | auto &clfrVector(input["in"].template peek()); 34 | flowCounter+= clfrVector.size(); 35 | for (auto rec : clfrVector){ 36 | pktCounter += rec.second.packetVector.size(); 37 | } 38 | input["in"].recycle(); 39 | 40 | if (pktCounter > BENCHMARK_CT){ 41 | cur = high_resolution_clock::now(); 42 | auto duration = duration_cast( cur - last ).count(); 43 | output["stats"].push(1000.0*(float(pktCounter)/float(duration))); 44 | pktCounter = 0; 45 | last = high_resolution_clock::now(); 46 | } 47 | return (raft::proceed); 48 | } 49 | }; 50 | } 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /backend/src/kernels/sink.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STARFLOW_KERNELS_SINK 3 | #define STARFLOW_KERNELS_SINK 4 | 5 | 6 | namespace starflow { 7 | namespace kernels { 8 | template 9 | class Sink : public raft::kernel 10 | { 11 | public: 12 | explicit Sink() 13 | : raft::kernel() 14 | { 15 | input.template add_port("in"); 16 | } 17 | 18 | raft::kstatus run() override 19 | { 20 | // T t{}; 21 | // input["in"].pop(t); 22 | input["in"].recycle(); 23 | 24 | return (raft::proceed); 25 | } 26 | }; 27 | } 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /backend/src/kernels/starFlow.h: -------------------------------------------------------------------------------- 1 | #ifndef STARFLOW_CSTRUCTS 2 | #define STARFLOW_CSTRUCTS 3 | 4 | #include 5 | 6 | #define KEYLEN 13 7 | #define MCLFR_MAXLEN 32 8 | struct PacketFeatures{ 9 | uint16_t queueSize; 10 | uint16_t byteCt; 11 | uint32_t ts; 12 | }; 13 | 14 | struct FlowFeatures { 15 | uint32_t pktCt; 16 | u_char th_flags; 17 | }; 18 | 19 | // Format of switch export. 20 | struct Export_MCLFR { 21 | char key[KEYLEN]; 22 | FlowFeatures flowFeatures; 23 | PacketFeatures packetVector[MCLFR_MAXLEN]; 24 | }; 25 | 26 | struct CLFR_Value { 27 | FlowFeatures flowFeatures; 28 | std::vector packetVector; 29 | }; 30 | 31 | 32 | // format of a clfr. This struct isn't used in the code, 33 | // its just here for reference. In the code, we pass 34 | // a pair. 35 | struct CLFR { 36 | char key[KEYLEN]; 37 | CLFR_Value record; 38 | }; 39 | 40 | #endif -------------------------------------------------------------------------------- /cache/cModel/README.md: -------------------------------------------------------------------------------- 1 | #### starFlow cache C model #### 2 | 3 | This is a C model of the starFlow cache that operates on packet traces. It was used in the paper to evaluate cache performance under a range of configurations, some of which are not possible on current tofino hardware. Also, it was used in tuning scripts, to select the best partitioning of the cache. 4 | 5 | The model allows you to configure: 6 | 1. the LRU associativity parameter of the cache *(An associativity parameter of N means that each bucket of the hash table stores up to N entries. When an evict needs to occur to make room for a new entry, the program finds the N entries with the same hash as the new entry, and evicts the least recently used one. To model the Tofino, use an associativity parameter of 1 (no associativity).)* 7 | 2. the height of each partition of the cache, i.e., the number of flows slots. 8 | 3. the width of each cache partition, i.e., the number of packet features that each flow slot stores. 9 | 10 | Usage: 11 | 12 | make starflowModel 13 | ./starflowModel PCAP_FILE MAX_TRIAL_DURATION ASSOCIATIVITY_PARAM PARTITION_1_HEIGHT PARTITION_1_WIDTH PARTITION_2_HEIGHT PARTITION_2_WIDTH 14 | 15 | - run example.sh to run the model on the example pcap. 16 | 17 | Notes: 18 | 19 | - edit dumpMClfrs to enable saving grouped packet vectors to binary files. 20 | - the code structure is a bit unintuitive because it is designed to model the code structure in P4. 21 | - there is a lot of vestigial code that needs to be cleaned up. 22 | -------------------------------------------------------------------------------- /cache/cModel/example.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonch/StarFlow/08c6d65b4e4b31065a471a8bcbe29b56455b4508/cache/cModel/example.pcap -------------------------------------------------------------------------------- /cache/cModel/example.sh: -------------------------------------------------------------------------------- 1 | make starflowModel 2 | ./starflowModel example.pcap 60000 1 8192 2 2048 16 3 | -------------------------------------------------------------------------------- /cache/cModel/makefile: -------------------------------------------------------------------------------- 1 | all: starflowModel 2 | 3 | starflowModel: starflowModel.cpp 4 | g++ starflowModel.cpp -o starflowModel -lpcap -std=c++11 5 | 6 | clean: 7 | rm starflowModel 8 | -------------------------------------------------------------------------------- /cache/cModel/starFlow.h: -------------------------------------------------------------------------------- 1 | #ifndef STARFLOW_CSTRUCTS 2 | #define STARFLOW_CSTRUCTS 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include 15 | #include "MurmerHash3.h" 16 | using namespace std; 17 | uint64_t gpid = 0; 18 | 19 | // Structs and support functions for *Flow. 20 | 21 | 22 | #define KEYLEN 13 // Length of key used in any flow tables. 23 | 24 | 25 | struct GPVHeader { 26 | char key[KEYLEN]; 27 | uint8_t dpid; 28 | uint16_t pktCt; 29 | uint64_t startTs; 30 | }; 31 | 32 | struct FeatureTuple { 33 | uint32_t tsDelta : 20; 34 | uint16_t byteCt : 11; 35 | bool highQueue: 1; 36 | }; 37 | 38 | 39 | 40 | #define PKT_FTR_SZ 16 41 | // Features of individual packet, for export from switch. 42 | struct PacketFeatures{ 43 | uint16_t queueSize; 44 | uint16_t byteCt; 45 | uint64_t ts; 46 | }; 47 | 48 | 49 | struct PacketRecord{ 50 | char key[KEYLEN]; 51 | u_char th_flags; 52 | PacketFeatures features; 53 | }; 54 | 55 | // Maximum number of packet features that a micro-CLFR can hold. 56 | // (Will be truncated if < MCLFR_MAXLEN before switch export) 57 | #define MCLFR_MAXLEN 32 58 | struct MCLFR { 59 | // metadata. 60 | uint64_t hashVal; 61 | bool inUse; 62 | uint64_t lastAccessTs; 63 | uint64_t firstAccessTs; 64 | uint64_t flowId; 65 | // key and aggregate features. 66 | char key[KEYLEN]; 67 | std::string keyStr; 68 | u_char th_flags; 69 | uint16_t pktCt; 70 | bool allocAttempt; 71 | // per packet features. 72 | PacketFeatures packetVector[MCLFR_MAXLEN]; 73 | // Index of long vector, if owned. 74 | uint32_t longVectorIdx; 75 | }; 76 | 77 | 78 | // Key represented as ints for testing different hash tables. 79 | // probably should be changed back to string. 80 | struct PackedKey { 81 | uint64_t addrs; 82 | uint64_t portsproto; 83 | }; 84 | 85 | struct FlowFeatures { 86 | uint32_t pktCt; 87 | u_char th_flags; 88 | }; 89 | 90 | #define MF_HDR_SZ 24 91 | // Format of switch export. 92 | struct Export_MCLFR { 93 | PackedKey packedKey; 94 | FlowFeatures flowFeatures; 95 | PacketFeatures packetVector[MCLFR_MAXLEN]; 96 | }; 97 | 98 | struct Export_MCLFR_hdr { 99 | PackedKey packedKey; 100 | FlowFeatures flowFeatures; 101 | }; 102 | 103 | 104 | 105 | // Internal CLFR format for applications. 106 | // ( previously named struct FlowRecord ) 107 | struct CLFR { 108 | PackedKey packedKey; 109 | FlowFeatures flowFeatures; 110 | // byte counts and timeStamps of each packet in the flow. 111 | std::vector queueSizes; 112 | std::vector byteCounts; 113 | std::vector timeStamps; 114 | }; 115 | 116 | 117 | struct CLFR_Value { 118 | FlowFeatures flowFeatures; 119 | // byte counts and timeStamps of each packet in the flow. 120 | std::vector packetVector; 121 | // std::vector queueSizes; 122 | // std::vector byteCounts; 123 | // std::vector timeStamps; 124 | }; 125 | 126 | 127 | 128 | 129 | 130 | // Helpers. 131 | void setKey(char *keyBuf, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader); 132 | uint64_t getMicrosecondTs(uint32_t seconds, uint32_t microSeconds); 133 | MCLFR * newMicroflow(uint64_t curTs, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader); 134 | unsigned simpleHash(unsigned int p, const char* s, int len, int maxHashVal); 135 | std::string string_to_hex(const std::string& input); 136 | 137 | 138 | // Convert a packet into a microflow with 1 item. 139 | void initMicroflow(MCLFR * mfr, uint64_t curTs, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader){ 140 | // Set raw key. 141 | setKey(mfr->key, ipHeader, udpOrtcpHeader); 142 | // Set aggregate features. 143 | mfr->pktCt = 1; 144 | // Set features of first packet vector slot. 145 | mfr->packetVector[0].byteCt = ipHeader->ip_len; 146 | mfr->packetVector[0].ts = curTs; 147 | } 148 | 149 | 150 | // Get 64 bit timestamp. 151 | uint64_t getMicrosecondTs(uint32_t seconds, uint32_t microSeconds){ 152 | uint64_t seconds64 = seconds; 153 | uint64_t microSeconds64 = microSeconds; 154 | uint64_t ts = seconds64 * 1000000 + microSeconds64; 155 | return ts; 156 | } 157 | 158 | void setKey(char *keyBuf, const struct ip* ipHeader, const struct udphdr* udpOrtcpHeader){ 159 | memcpy(&(keyBuf[0]), &ipHeader->ip_src, 4); 160 | memcpy(&(keyBuf[4]), &ipHeader->ip_dst, 4); 161 | memcpy(&(keyBuf[8]), &udpOrtcpHeader->source, 2); 162 | memcpy(&(keyBuf[10]), &udpOrtcpHeader->dest, 2); 163 | memcpy(&(keyBuf[12]), &ipHeader->ip_p, 1); 164 | } 165 | 166 | 167 | // A simple hashing function. 168 | unsigned simpleHash(unsigned int p, const char* s, int len, int maxHashVal) 169 | { 170 | uint64_t out[2]; 171 | MurmurHash3_x64_128(s, len, p, out); 172 | return out[1] % maxHashVal; 173 | } 174 | 175 | std::string string_to_hex(const std::string& input) 176 | { 177 | static const char* const lut = "0123456789ABCDEF"; 178 | size_t len = input.length(); 179 | 180 | std::string output; 181 | output.reserve(2 * len); 182 | for (size_t i = 0; i < len; ++i) 183 | { 184 | const unsigned char c = input[i]; 185 | output.push_back(lut[c >> 4]); 186 | output.push_back(lut[c & 15]); 187 | } 188 | return output; 189 | } 190 | 191 | #endif -------------------------------------------------------------------------------- /cache/cModel/starflowModel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonch/StarFlow/08c6d65b4e4b31065a471a8bcbe29b56455b4508/cache/cModel/starflowModel -------------------------------------------------------------------------------- /cache/p4Generic/README.md: -------------------------------------------------------------------------------- 1 | # StarFlow generic P4_14 2 | *This is an implementation originally compiled for the tofino, but with all platform specific (i.e., NDA sensitive) stateful functions removed. Psuedocode for the stateful functions is in statefulFunctions.p4 -- to get this working on BMv2, implement the psuedocode as custom primitives that extend the simple_switch target.* 3 | -------------------------------------------------------------------------------- /cache/p4Generic/p4src/forwardL2.p4: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * forwardL2.p4 -- Simple layer 2 forwarding. 4 | * 5 | */ 6 | 7 | 8 | /*========================================== 9 | = Data Plane Interface = 10 | ==========================================*/ 11 | 12 | control ciForwardPacket { 13 | apply(tiL2Downstream) { 14 | aiMiss { 15 | apply(tiL2Upstream); 16 | } 17 | } 18 | } 19 | 20 | header_type L2Meta_t { 21 | fields { 22 | dstAddrMsb : 32; 23 | } 24 | } 25 | metadata L2Meta_t L2Meta; 26 | 27 | /*==== End of Data Plane Interface ======*/ 28 | 29 | 30 | /** 31 | * 32 | * Exact match forwarding to downstream based on ingress port and dest mac addr. 33 | * 34 | */ 35 | table tiL2Downstream { 36 | reads { 37 | globalMd.ingressPortId : exact; 38 | ethernet.dstAddr : exact; 39 | } 40 | actions { 41 | aiUnicastEgress; 42 | aiMulticast; 43 | aiMiss; 44 | } 45 | default_action: aiMiss(); 46 | size : 128; 47 | } 48 | 49 | /** 50 | * 51 | * default forwarding to upstream based on ingress port. Should only handle unicast. 52 | * 53 | */ 54 | table tiL2Upstream { 55 | reads { 56 | globalMd.ingressPortId : exact; 57 | } 58 | actions { 59 | aiUnicastEgress; 60 | } 61 | size : 128; 62 | } 63 | 64 | // Unicast to a port. 65 | action aiUnicastEgress(egressPort){ 66 | modify_field(ig_intr_md_for_tm.ucast_egress_port, egressPort); 67 | } 68 | 69 | // Multicast to a group. 70 | action aiMulticast(mcGroup){ 71 | modify_field(ig_intr_md_for_tm.mcast_grp_a, mcGroup); 72 | } 73 | // Miss 74 | action aiMiss() {} -------------------------------------------------------------------------------- /cache/p4Generic/p4src/genPsuedocode.py: -------------------------------------------------------------------------------- 1 | # autogen stateful function psuedocode 2 | 3 | def main(): 4 | svCount = 4 5 | print ("// short vecs") 6 | genShortVecs(svCount) 7 | 8 | lvCount = 23 9 | print ("// long vecs inline code") 10 | genLongVecsInline(lvCount) 11 | print ("// long vecs") 12 | genLongVecs(lvCount) 13 | 14 | def genShortVecs(svCount): 15 | for i in range(svCount): 16 | svRW = """ 17 | action sRWShortVec_%s() { 18 | idx = sfMeta.hashVal; 19 | sfShortVector.w%s = rShortVec_%s[idx]; 20 | rShortVec_%s[idx] = currentPfVec.w0; 21 | } 22 | """%(i, i, i, i) 23 | svR = """ 24 | action sRShortVec_%s() { 25 | idx = sfMeta.hashVal; 26 | sfShortVector.w%s = rShortVec_%s[idx]; 27 | } 28 | """%(i, i, i) 29 | print svRW 30 | print svR 31 | 32 | def genLongVecsInline(lvCount): 33 | print ("// longvec inline") 34 | for i in range(lvCount): 35 | svInline = """ 36 | 37 | /*---------- longVec[%s] ----------*/ 38 | table tiRWLongVec_%s { 39 | reads { 40 | sfMeta.pktId : ternary; 41 | } 42 | actions {aiRLongVec_%s; aiRWLongVec_%s;} 43 | } 44 | action aiRWLongVec_%s() { 45 | sRWLongVec_%s(); 46 | } 47 | action aiRLongVec_%s() { 48 | sRLongVec_%s(); 49 | } 50 | 51 | register rLongVec_%s { 52 | width : 32; 53 | instance_count : SF_LONG_TBL_SIZE; 54 | } 55 | """%(i, i, i, i, i, i, i, i, i) 56 | print svInline 57 | print ("// end longvec inline") 58 | 59 | def genLongVecs(lvCount): 60 | for i in range(lvCount): 61 | svRW = """ 62 | action sRWLongVec_%s() { 63 | idx = sfMeta.widePtr; 64 | sfLongVector.w%s = rLongVec_%s[idx]; 65 | rLongVec_%s[idx] = currentPfVec.w0; 66 | } 67 | """%(i, i, i, i) 68 | svR = """ 69 | action sRLongVec_%s() { 70 | idx = sfMeta.widePtr; 71 | sfLongVector.w%s = rLongVec_%s[idx]; 72 | } 73 | """%(i, i, i) 74 | print svRW 75 | print svR 76 | 77 | 78 | 79 | if __name__ == '__main__': 80 | main() -------------------------------------------------------------------------------- /cache/p4Generic/p4src/mainStarFlow.p4: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * mainStarFlow.p4 -- Simple 2 hop switch with StarFlow. 4 | * 5 | */ 6 | 7 | /** 8 | * 9 | * SANITIZED: tofino specific includes. 10 | * 11 | */ 12 | #include "miscUtils.p4" 13 | #include "forwardL2.p4" 14 | 15 | #define ETHERTYPE_IPV4 0x0800 16 | #define ETHERTYPE_STARFLOW_FULL 0x081A 17 | #define ETHERTYPE_STARFLOW_SHORT 0x081B 18 | 19 | 20 | 21 | #define SHORT_LEN 2 22 | 23 | // Ensure that packet ID can be have SHORT_LEN once per evict. 24 | #define TOTAL_LEN 8 25 | #define TOTAL_LEN_M1 7 26 | #define ROLLOVER_FLAG 100 27 | #define TOTAL_LEN_M1_PROLLOVER_FLAG 107 28 | 29 | 30 | #define SF_MC_GID 666 31 | #define SF_MC_RECIRC_GID 667 32 | #define SF_CLONE_MID 66 33 | #define SF_COAL_MID 1016 34 | 35 | 36 | #include "parser.p4" 37 | #include "starFlow.p4" 38 | 39 | control ingress { 40 | // Port to index mapping. Always do this. 41 | // if (ig_intr_md.resubmit_flag == 0){ 42 | // apply(tiPortToIndex); 43 | // } 44 | // // Stage 0: apply L2 forwarding. 45 | // ciForwardPacket(); // (forwardL2.p4) 46 | // Next stages: apply TurboFlow (only to IPv4 packets) 47 | if (valid(ipv4)) { 48 | ciStarFlow(); 49 | } 50 | 51 | } 52 | 53 | control egress { 54 | // Strip StarFlow headers unless its an eviction packet to the monitor port, or a recirculation packet. 55 | ceStarFlow(); 56 | } 57 | 58 | 59 | 60 | control ciStarFlow { 61 | 62 | // Stage 0: Setup Starflow headers. 63 | // apply(tiAddSfHeaders); 64 | 65 | 66 | 67 | // Stage 0: Update key fields and do preprocessing. 68 | // These tables only apply if ethertype == IPv4 69 | // tiUpdateSrcAddr sets inProcessing = 1. 70 | // tiUpdateSrcAddr also sets drop if its a recirc packet. 71 | apply(tiUpdateSrcAddr); 72 | apply(tiUpdateDstAddr); 73 | apply(tiUpdatePorts); 74 | apply(tiUpdateProtocol); 75 | 76 | // If packet is in processing, set match flag and increment packet counter. 77 | // Todo: also update start timestamp here. 78 | if (sfMeta.inProcessing == 1) { 79 | apply(tiSetMatch); 80 | } 81 | 82 | // If packet is in processing, apply stack alloc operations. 83 | if (sfMeta.inProcessing == 1) { 84 | // Stage 2, 3, 4: stack operations. (and more short vectors, optionally.) 85 | apply(tiDecrementStackTop); // Stage 2: stack top pointer. 86 | apply(tiUpdateStackArray); // Stage 3: read or write from stack, depending on stack top pointer. 87 | apply(tiUpdateWidePointerArray);// Stage 4: read or write from local extension pointer. 88 | } 89 | // else, apply stack free operations. 90 | else { 91 | apply(tiIncrementStackTop); 92 | apply(tiFreeStackArray); 93 | } 94 | 95 | // If packet is in processing, apply the vector ops and other stuff. 96 | if (sfMeta.inProcessing == 1) { 97 | // Stages 5 - 11: packet record ops. 98 | // short vector: 99 | // - always read 100 | // - write if: 101 | // 1: widePtr == 0 and (pktId % SHORT_LEN == IDX) 102 | // 2: pktId == IDX 103 | // long vector: 104 | // - always read 105 | // - write if: 106 | // 1: pktId == IDX 107 | // * note: (widePtr == 0) --> write to garbage location 108 | apply(tiRWShortVec_0); 109 | apply(tiRWShortVec_1); 110 | apply(tiRWShortVec_2); 111 | apply(tiRWShortVec_3); 112 | 113 | apply(tiRWLongVec_0); 114 | apply(tiRWLongVec_1); 115 | apply(tiRWLongVec_2); 116 | apply(tiRWLongVec_3); 117 | apply(tiRWLongVec_4); 118 | apply(tiRWLongVec_5); 119 | apply(tiRWLongVec_6); 120 | apply(tiRWLongVec_7); 121 | apply(tiRWLongVec_8); 122 | apply(tiRWLongVec_9); 123 | apply(tiRWLongVec_10); 124 | apply(tiRWLongVec_11); 125 | apply(tiRWLongVec_12); 126 | apply(tiRWLongVec_13); 127 | apply(tiRWLongVec_14); 128 | apply(tiRWLongVec_15); 129 | apply(tiRWLongVec_16); 130 | apply(tiRWLongVec_17); 131 | apply(tiRWLongVec_18); 132 | apply(tiRWLongVec_19); 133 | apply(tiRWLongVec_20); 134 | apply(tiRWLongVec_21); 135 | apply(tiRWLongVec_22); 136 | apply(tiRWLongVec_23); 137 | 138 | // Correct key for export, in case some of the key fields match the new flow's fields. 139 | // (either a rollover or a new flow that partially matches the old flow.) 140 | 141 | apply(tiFixSrcAddr); 142 | apply(tiFixDstAddr); 143 | apply(tiFixPorts); 144 | apply(tiFixProtocol); 145 | 146 | // if (sfMeta.matchFlag == 0) { 147 | // if (sfExportKey.srcAddr == 0) { 148 | // apply(tiFixSrcAddr); 149 | // } 150 | // if (sfExportKey.dstAddr == 0) { 151 | // apply(tiFixDstAddr); 152 | // } 153 | // if (sfExportKey.ports == 0) { 154 | // apply(tiFixPorts); 155 | // } 156 | // if (sfExportKey.protocol == 0) { 157 | // apply(tiFixProtocol); 158 | // } 159 | // } 160 | 161 | // Export to CPU if evict or vectors are full. 162 | if (sfMeta.matchFlag == 0) { 163 | apply(tiEvictDecision); 164 | } 165 | else { 166 | apply(tiRolloverDecision); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /cache/p4Generic/p4src/miscUtils.p4: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 4 | * Mirroring for debug. 5 | * 6 | */ 7 | #define DBG_MIRROR_ID 91 8 | field_list debugFl { 9 | globalMd.ingressPortId; 10 | } 11 | 12 | 13 | table tiFilteredMirrorToDebug { 14 | reads {ig_intr_md.ingress_port : exact;} 15 | actions {aiMirrorToSelectedDebug; aiNopPort; } 16 | default_action : aiNopPort(); 17 | } 18 | 19 | table tiMirrorToDebug { 20 | actions {aiMirrorToDebug;} 21 | default_action : aiMirrorToDebug(); 22 | } 23 | action aiMirrorToDebug() { 24 | clone_i2e(DBG_MIRROR_ID, debugFl); 25 | } 26 | 27 | action aiMirrorToSelectedDebug(mirId) { 28 | clone_i2e(mirId, debugFl); 29 | } 30 | 31 | 32 | 33 | /** 34 | * 35 | * Port to index table. Used by all applications. Should be packed into recirculate header and set before recirc. 36 | * 37 | */ 38 | header_type globalMd_t { 39 | fields { 40 | ingressPortId : 9; 41 | } 42 | } 43 | metadata globalMd_t globalMd; 44 | 45 | table tiPortToIndex { 46 | reads { 47 | ig_intr_md.ingress_port : exact; 48 | } 49 | actions { 50 | aiPortToIndex; aiNopPort; 51 | } 52 | default_action : aiNopPort(); 53 | size : 128; 54 | } 55 | action aiPortToIndex(portIndex) { 56 | modify_field(globalMd.ingressPortId, portIndex); 57 | } 58 | action aiNopPort() { no_op();} -------------------------------------------------------------------------------- /cache/p4Generic/p4src/parser.p4: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Headers, metadata, and parser. 4 | * 5 | */ 6 | 7 | // Max number of flows to track at once. 8 | #define SF_SHORT_TBL_SIZE 8192 9 | #define SF_SHORT_BIT_WIDTH 14 // log2(SF_SHORT_TBL_SIZE) 10 | 11 | // Number of "wide" slots 12 | #define SF_LONG_TBL_SIZE 4096 13 | #define SF_LONG_PTR_WIDTH 13 // log2(SF_LONG_TBL_SIZE) 14 | 15 | 16 | 17 | // Metadata for processing. 18 | metadata sfMeta_t sfMeta; 19 | 20 | // The current packet feature vector. 21 | metadata currentPfVec_t currentPfVec; 22 | 23 | // Headers for exporting an evicted flow record. 24 | header sfExportStart_t sfExportStart; 25 | header sfExportKey_t sfExportKey; 26 | header sfShortVector_t sfShortVector; 27 | header sfLongVector_t sfLongVector; 28 | 29 | /*========================================== 30 | = StarFlow Headers. = 31 | ==========================================*/ 32 | 33 | header_type currentPfVec_t { 34 | fields { 35 | w0 : 32; 36 | } 37 | } 38 | 39 | 40 | header_type sfMeta_t { 41 | fields { 42 | curTs : 32; 43 | pktId : 16; // Resets on evict. 44 | lastPktId : 16; // Filled when there is an evict. 45 | hashVal : SF_SHORT_BIT_WIDTH; 46 | matchFlag : 1; 47 | inProcessing : 1; 48 | stackPtr : SF_LONG_PTR_WIDTH; // Pointer to the top of the stack. 49 | widePtr : SF_LONG_PTR_WIDTH; // Loaded extension pointer. 50 | } 51 | } 52 | 53 | header_type sfExportStart_t { 54 | fields { 55 | realEtherType : 16; 56 | widePtr : 16; // Loaded extension pointer. 57 | } 58 | } 59 | 60 | header_type sfExportKey_t { 61 | fields { 62 | srcAddr : 32; 63 | dstAddr : 32; 64 | ports : 32; 65 | startTs : 32; 66 | pktCt : 16; 67 | protocol : 8; 68 | } 69 | } 70 | 71 | 72 | header_type sfShortVector_t { 73 | fields { 74 | w0 : 32; 75 | w1 : 32; 76 | w2 : 32; 77 | w3 : 32; 78 | } 79 | } 80 | 81 | header_type sfLongVector_t { 82 | fields { 83 | w0 : 32; 84 | w1 : 32; 85 | w2 : 32; 86 | w3 : 32; 87 | w4 : 32; 88 | w5 : 32; 89 | w6 : 32; 90 | w7 : 32; 91 | w8 : 32; 92 | w9 : 32; 93 | w10 : 32; 94 | w11 : 32; 95 | w12 : 32; 96 | w13 : 32; 97 | w14 : 32; 98 | w15 : 32; 99 | w16 : 32; 100 | w17 : 32; 101 | w18 : 32; 102 | w19 : 32; 103 | w20 : 32; 104 | w21 : 32; 105 | w22 : 32; 106 | w23 : 32; 107 | } 108 | } 109 | 110 | 111 | 112 | /*===== End of StarFlow Headers. ======*/ 113 | 114 | /*=========================================== 115 | = Forwarding Headers. = 116 | ===========================================*/ 117 | 118 | header_type ethernet_t { 119 | fields { 120 | dstAddr : 48; 121 | srcAddr : 48; 122 | etherType : 16; 123 | } 124 | } 125 | header ethernet_t ethernet; 126 | 127 | header_type ipv4_t { 128 | fields { 129 | version : 4; 130 | ihl : 4; 131 | diffserv : 8; 132 | totalLen : 16; 133 | identification : 16; 134 | flags : 3; 135 | fragOffset : 13; 136 | ttl : 8; 137 | protocol : 8; 138 | hdrChecksum : 16; // here 139 | srcAddr : 32; 140 | dstAddr: 32; 141 | } 142 | } 143 | header ipv4_t ipv4; 144 | 145 | header_type l4_ports_t { 146 | fields { 147 | ports : 32; 148 | // srcPort : 16; 149 | // dstPort : 16; 150 | } 151 | } 152 | header l4_ports_t l4_ports; 153 | 154 | 155 | /*===== End of Forwarding Headers. ======*/ 156 | 157 | 158 | 159 | 160 | parser start { 161 | return parse_ethernet; 162 | } 163 | 164 | parser parse_ethernet { 165 | extract(ethernet); 166 | return select(latest.etherType) { 167 | ETHERTYPE_STARFLOW_FULL : parse_starflow_full; // This should never ingress or egress. 168 | ETHERTYPE_STARFLOW_SHORT : parse_starflow_short; 169 | ETHERTYPE_IPV4 : parse_ipv4; 170 | default : ingress; 171 | } 172 | } 173 | 174 | // IP. 175 | parser parse_ipv4 { 176 | extract(ipv4); 177 | return parse_l4; 178 | } 179 | 180 | // TCP / UDP ports. 181 | parser parse_l4 { 182 | extract(l4_ports); 183 | 184 | return ingress; 185 | } 186 | 187 | // Parse tree for in-processing packet with both short and long headers. 188 | parser parse_starflow_full { 189 | extract(sfExportStart); 190 | extract(sfExportKey); 191 | extract(sfShortVector); 192 | extract(sfLongVector); 193 | return select(sfExportStart.realEtherType) { 194 | ETHERTYPE_IPV4 : parse_ipv4; 195 | default : ingress; 196 | } 197 | } 198 | 199 | parser parse_starflow_short { 200 | extract(sfExportStart); 201 | extract(sfExportKey); 202 | extract(sfShortVector); 203 | return select(sfExportStart.realEtherType) { 204 | ETHERTYPE_IPV4 : parse_ipv4; 205 | default : ingress; 206 | } 207 | } -------------------------------------------------------------------------------- /cache/tofino/control/controlManager.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | The main control application. Run this. 4 | """ 5 | import time, select, sys, os, re, importlib, logging, unittest, binascii, logging, json, select, signal, math, argparse 6 | 7 | # append path of common control modules. 8 | sys.path.append(os.path.dirname(os.environ['PROGPATH'])+"/modules/control") 9 | 10 | 11 | # get all the autogenerated thrift stuff. 12 | if (os.environ['PROGNAME'] == ""): 13 | print("PROGNAME environment variable not set! Please run set_sde.bash") 14 | exit() 15 | from switchThriftInterface import * 16 | 17 | # base control plane manager with functions to add rules, multicast groups, bring up ports, etc. 18 | from controlManagerBase import * 19 | 20 | # logical network topology. 21 | from topoConfig import * 22 | 23 | # function specific controllers. 24 | from forwardControllerL2 import * 25 | # from latencyMonitorController import * 26 | 27 | from starFlowController import * 28 | 29 | mgr = None 30 | DEBUG_PORT=144 31 | DEBUG_MIRROR_ID=90 32 | 33 | def main(): 34 | global mgr 35 | if (not args.SIMULATION): 36 | ports, switches = topologySetup() 37 | 38 | # manager configuration flags. 39 | if (not args.SIMULATION): 40 | portMapFile = os.environ['PROGPATH']+"/config/"+"portMap.json" 41 | activePorts = [p.getTuple() for p in ports.values()] 42 | # activePorts = [("1/0", "100G", "RS"), ("2/0", "100G", "RS")] 43 | else: 44 | portMapFile = os.environ['PROGPATH']+"/config/"+"simPortMap.json" 45 | activePorts = [] # ignored in simulation. 46 | 47 | # initialize control manager. 48 | mgr = ControlManager([os.environ['PROGNAME']], [], port_map_filename=portMapFile, simulatorMode=args.SIMULATION, activePorts=activePorts) 49 | mgr.start() 50 | 51 | if (not args.SIMULATION): 52 | mgr.setPortMap() 53 | 54 | # add mirror session to collector / debugger. 55 | 56 | # get the DPIDs of the ports from the manager. 57 | if (not args.SIMULATION): 58 | setPortsDpid(mgr, ports.values()) 59 | 60 | # L2 forwarding config. 61 | if (not args.SIMULATION): 62 | l2Module = mgr.startModule(ForwardControllerL2((mgr))) 63 | l2Module.installVswitchRules(switches[1]) 64 | l2Module.installVswitchRules(switches[2]) 65 | 66 | # fragmenter controller. 67 | starFlowModule = mgr.startModule(StarFlowController(mgr, args.SIMULATION)) 68 | 69 | # write a log for the benefit of remote processes 70 | if (not args.SIMULATION): 71 | open("startupAlert.log", "w").write("STARTUP COMPLETE") 72 | print("STARTUP COMPLETE") 73 | print('Press Ctrl+C or hang up to exit.') 74 | signal.pause() 75 | 76 | 77 | class ControlManager(ControlManagerBase): 78 | def __init__(self, p4_names, p4_prefixes, port_map_filename, simulatorMode, activePorts): 79 | ControlManagerBase.__init__(self, p4_names, p4_prefixes, port_map_filename, simulatorMode, activePorts) 80 | 81 | 82 | def topologySetup(): 83 | """ 84 | Setup the topology. This could be cleaner. 85 | """ 86 | # ports = {i:Port(i, "%s/0"%i, "100G", "RS") for i in range(1, 7)} 87 | # up all the ports to tclust servers, and in-network hops, @ 10G 88 | # ports = {i:Port(i, "%s/0"%i, "10G", "NONE") for i in range(1, 9)} 89 | ports = {i:Port(i, "%s/0"%i, "100G", "RS") for i in range(1, 9)} 90 | ports[14] = Port(14, "14/0", "100G", "RS") 91 | # tclust servers on fp ports 1 ... N 92 | macs = {1:"24:8a:07:8f:eb:41", 2:"24:8a:07:5b:15:35", 3:"7c:fe:90:1c:36:d1", 4:"7c:fe:90:1c:36:81"} 93 | endHosts = {i:Host(i, "tclust%s"%i, ports[i], macs[i], "10.1.2.%s"%i) for i in range(1, 5)} 94 | 95 | # link between vswitches. 96 | links = {1:Link(1, ports[7], ports[8])} 97 | 98 | # vswitches. 99 | switches = {i:Vswitch(i) for i in range(1, 3)} 100 | 101 | # 2 hosts on each switch. 102 | switches[1].addHost(endHosts[1]) 103 | switches[1].addHost(endHosts[3]) 104 | switches[2].addHost(endHosts[2]) 105 | switches[2].addHost(endHosts[4]) 106 | 107 | # uplinks. 108 | switches[1].addUplink(links[1], 0) 109 | switches[2].addUplink(links[1], 1) 110 | return ports, switches 111 | 112 | 113 | # exit handler 114 | def signal_handler(signal, frame): 115 | print('Exiting.') 116 | mgr.cleanupModules() 117 | if (not args.SIMULATION): 118 | mgr.clearPortMap() 119 | mgr.end() 120 | if (not args.SIMULATION): 121 | os.remove("startupAlert.log") 122 | sys.exit(0) 123 | signal.signal(signal.SIGINT, signal_handler) 124 | signal.signal(signal.SIGHUP, signal_handler) 125 | 126 | # args. 127 | # K, H, loss rate. 128 | parser = argparse.ArgumentParser(description='Parse input arguments') 129 | parser.add_argument('-hw', '--hardware', dest='SIMULATION', action='store_false', help='Run in hardware', default=True) 130 | # parser.add_argument('--lossRate', '-l', type=float,dest="lossRate",help='Loss rate. Default: 0.0', default=0.0) 131 | args = parser.parse_args() 132 | print args 133 | 134 | 135 | if __name__ == '__main__': 136 | print ("controller starting..") 137 | main() -------------------------------------------------------------------------------- /cache/tofino/p4src/forwardL2.p4: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * forwardL2.p4 -- Simple layer 2 forwarding. 4 | * 5 | */ 6 | 7 | 8 | /*========================================== 9 | = Data Plane Interface = 10 | ==========================================*/ 11 | 12 | control ciForwardPacket { 13 | apply(tiL2Downstream) { 14 | aiMiss { 15 | apply(tiL2Upstream); 16 | } 17 | } 18 | } 19 | 20 | header_type L2Meta_t { 21 | fields { 22 | dstAddrMsb : 32; 23 | } 24 | } 25 | metadata L2Meta_t L2Meta; 26 | 27 | /*==== End of Data Plane Interface ======*/ 28 | 29 | 30 | /** 31 | * 32 | * Exact match forwarding to downstream based on ingress port and dest mac addr. 33 | * 34 | */ 35 | table tiL2Downstream { 36 | reads { 37 | globalMd.ingressPortId : exact; 38 | ethernet.dstAddr : exact; 39 | } 40 | actions { 41 | aiUnicastEgress; 42 | aiMulticast; 43 | aiMiss; 44 | } 45 | default_action: aiMiss(); 46 | size : 128; 47 | } 48 | 49 | /** 50 | * 51 | * default forwarding to upstream based on ingress port. Should only handle unicast. 52 | * 53 | */ 54 | table tiL2Upstream { 55 | reads { 56 | globalMd.ingressPortId : exact; 57 | } 58 | actions { 59 | aiUnicastEgress; 60 | } 61 | size : 128; 62 | } 63 | 64 | // Unicast to a port. 65 | action aiUnicastEgress(egressPort){ 66 | modify_field(ig_intr_md_for_tm.ucast_egress_port, egressPort); 67 | } 68 | 69 | // Multicast to a group. 70 | action aiMulticast(mcGroup){ 71 | modify_field(ig_intr_md_for_tm.mcast_grp_a, mcGroup); 72 | } 73 | // Miss 74 | action aiMiss() {} -------------------------------------------------------------------------------- /cache/tofino/p4src/mainStarFlow.p4: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * mainStarFlow.p4 -- Simple 2 hop switch with StarFlow. 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "miscUtils.p4" 13 | #include "forwardL2.p4" 14 | 15 | #define ETHERTYPE_IPV4 0x0800 16 | #define ETHERTYPE_STARFLOW_FULL 0x081A 17 | #define ETHERTYPE_STARFLOW_SHORT 0x081B 18 | 19 | 20 | 21 | #define SHORT_LEN 2 22 | 23 | // Ensure that packet ID can be have SHORT_LEN once per evict. 24 | #define TOTAL_LEN 8 25 | #define TOTAL_LEN_M1 7 26 | #define ROLLOVER_FLAG 100 27 | #define TOTAL_LEN_M1_PROLLOVER_FLAG 107 28 | 29 | 30 | #define SF_MC_GID 666 31 | #define SF_MC_RECIRC_GID 667 32 | #define SF_CLONE_MID 66 33 | #define SF_COAL_MID 1016 34 | 35 | 36 | #include "parser.p4" 37 | #include "starFlow.p4" 38 | 39 | control ingress { 40 | // Port to index mapping. Always do this. 41 | // if (ig_intr_md.resubmit_flag == 0){ 42 | // apply(tiPortToIndex); 43 | // } 44 | // // Stage 0: apply L2 forwarding. 45 | // ciForwardPacket(); // (forwardL2.p4) 46 | // Next stages: apply TurboFlow (only to IPv4 packets) 47 | if (valid(ipv4)) { 48 | ciStarFlow(); 49 | } 50 | 51 | } 52 | 53 | control egress { 54 | // Strip StarFlow headers unless its an eviction packet to the monitor port, or a recirculation packet. 55 | ceStarFlow(); 56 | } 57 | 58 | 59 | 60 | control ciStarFlow { 61 | 62 | // Stage 0: Setup Starflow headers. 63 | // apply(tiAddSfHeaders); 64 | 65 | 66 | 67 | // Stage 0: Update key fields and do preprocessing. 68 | // These tables only apply if ethertype == IPv4 69 | // tiUpdateSrcAddr sets inProcessing = 1. 70 | // tiUpdateSrcAddr also sets drop if its a recirc packet. 71 | apply(tiUpdateSrcAddr); 72 | apply(tiUpdateDstAddr); 73 | apply(tiUpdatePorts); 74 | apply(tiUpdateProtocol); 75 | 76 | // If packet is in processing, set match flag and increment packet counter. 77 | // Todo: also update start timestamp here. 78 | if (sfMeta.inProcessing == 1) { 79 | apply(tiSetMatch); 80 | } 81 | 82 | // If packet is in processing, apply stack alloc operations. 83 | if (sfMeta.inProcessing == 1) { 84 | // Stage 2, 3, 4: stack operations. (and more short vectors, optionally.) 85 | apply(tiDecrementStackTop); // Stage 2: stack top pointer. 86 | apply(tiUpdateStackArray); // Stage 3: read or write from stack, depending on stack top pointer. 87 | apply(tiUpdateWidePointerArray);// Stage 4: read or write from local extension pointer. 88 | } 89 | // else, apply stack free operations. 90 | else { 91 | apply(tiIncrementStackTop); 92 | apply(tiFreeStackArray); 93 | } 94 | 95 | // If packet is in processing, apply the vector ops and other stuff. 96 | if (sfMeta.inProcessing == 1) { 97 | // Stages 5 - 11: packet record ops. 98 | // short vector: 99 | // - always read 100 | // - write if: 101 | // 1: widePtr == 0 and (pktId % SHORT_LEN == IDX) 102 | // 2: pktId == IDX 103 | // long vector: 104 | // - always read 105 | // - write if: 106 | // 1: pktId == IDX 107 | // * note: (widePtr == 0) --> write to garbage location 108 | apply(tiRWShortVec_0); 109 | apply(tiRWShortVec_1); 110 | apply(tiRWShortVec_2); 111 | apply(tiRWShortVec_3); 112 | 113 | apply(tiRWLongVec_0); 114 | apply(tiRWLongVec_1); 115 | apply(tiRWLongVec_2); 116 | apply(tiRWLongVec_3); 117 | apply(tiRWLongVec_4); 118 | apply(tiRWLongVec_5); 119 | apply(tiRWLongVec_6); 120 | apply(tiRWLongVec_7); 121 | apply(tiRWLongVec_8); 122 | apply(tiRWLongVec_9); 123 | apply(tiRWLongVec_10); 124 | apply(tiRWLongVec_11); 125 | apply(tiRWLongVec_12); 126 | apply(tiRWLongVec_13); 127 | apply(tiRWLongVec_14); 128 | apply(tiRWLongVec_15); 129 | apply(tiRWLongVec_16); 130 | apply(tiRWLongVec_17); 131 | apply(tiRWLongVec_18); 132 | apply(tiRWLongVec_19); 133 | apply(tiRWLongVec_20); 134 | apply(tiRWLongVec_21); 135 | apply(tiRWLongVec_22); 136 | apply(tiRWLongVec_23); 137 | 138 | // Correct key for export, in case some of the key fields match the new flow's fields. 139 | // (either a rollover or a new flow that partially matches the old flow.) 140 | 141 | apply(tiFixSrcAddr); 142 | apply(tiFixDstAddr); 143 | apply(tiFixPorts); 144 | apply(tiFixProtocol); 145 | 146 | // if (sfMeta.matchFlag == 0) { 147 | // if (sfExportKey.srcAddr == 0) { 148 | // apply(tiFixSrcAddr); 149 | // } 150 | // if (sfExportKey.dstAddr == 0) { 151 | // apply(tiFixDstAddr); 152 | // } 153 | // if (sfExportKey.ports == 0) { 154 | // apply(tiFixPorts); 155 | // } 156 | // if (sfExportKey.protocol == 0) { 157 | // apply(tiFixProtocol); 158 | // } 159 | // } 160 | 161 | // Export to CPU if evict or vectors are full. 162 | if (sfMeta.matchFlag == 0) { 163 | apply(tiEvictDecision); 164 | } 165 | else { 166 | apply(tiRolloverDecision); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /cache/tofino/p4src/miscUtils.p4: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 4 | * Mirroring for debug. 5 | * 6 | */ 7 | #define DBG_MIRROR_ID 91 8 | field_list debugFl { 9 | globalMd.ingressPortId; 10 | } 11 | 12 | 13 | table tiFilteredMirrorToDebug { 14 | reads {ig_intr_md.ingress_port : exact;} 15 | actions {aiMirrorToSelectedDebug; aiNopPort; } 16 | default_action : aiNopPort(); 17 | } 18 | 19 | table tiMirrorToDebug { 20 | actions {aiMirrorToDebug;} 21 | default_action : aiMirrorToDebug(); 22 | } 23 | action aiMirrorToDebug() { 24 | clone_i2e(DBG_MIRROR_ID, debugFl); 25 | } 26 | 27 | action aiMirrorToSelectedDebug(mirId) { 28 | clone_i2e(mirId, debugFl); 29 | } 30 | 31 | 32 | 33 | /** 34 | * 35 | * Port to index table. Used by all applications. Should be packed into recirculate header and set before recirc. 36 | * 37 | */ 38 | header_type globalMd_t { 39 | fields { 40 | ingressPortId : 9; 41 | } 42 | } 43 | metadata globalMd_t globalMd; 44 | 45 | table tiPortToIndex { 46 | reads { 47 | ig_intr_md.ingress_port : exact; 48 | } 49 | actions { 50 | aiPortToIndex; aiNopPort; 51 | } 52 | default_action : aiNopPort(); 53 | size : 128; 54 | } 55 | action aiPortToIndex(portIndex) { 56 | modify_field(globalMd.ingressPortId, portIndex); 57 | } 58 | action aiNopPort() { no_op();} -------------------------------------------------------------------------------- /cache/tofino/p4src/parser.p4: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Headers, metadata, and parser. 4 | * 5 | */ 6 | 7 | // Max number of flows to track at once. 8 | #define SF_SHORT_TBL_SIZE 8192 9 | #define SF_SHORT_BIT_WIDTH 14 // log2(SF_SHORT_TBL_SIZE) 10 | 11 | // Number of "wide" slots 12 | #define SF_LONG_TBL_SIZE 4096 13 | #define SF_LONG_PTR_WIDTH 13 // log2(SF_LONG_TBL_SIZE) 14 | 15 | 16 | 17 | // Metadata for processing. 18 | metadata sfMeta_t sfMeta; 19 | 20 | // The current packet feature vector. 21 | metadata currentPfVec_t currentPfVec; 22 | 23 | // Headers for exporting an evicted flow record. 24 | header sfExportStart_t sfExportStart; 25 | header sfExportKey_t sfExportKey; 26 | header sfShortVector_t sfShortVector; 27 | header sfLongVector_t sfLongVector; 28 | 29 | /*========================================== 30 | = StarFlow Headers. = 31 | ==========================================*/ 32 | 33 | header_type currentPfVec_t { 34 | fields { 35 | w0 : 32; 36 | } 37 | } 38 | 39 | 40 | header_type sfMeta_t { 41 | fields { 42 | curTs : 32; 43 | pktId : 16; // Resets on evict. 44 | lastPktId : 16; // Filled when there is an evict. 45 | hashVal : SF_SHORT_BIT_WIDTH; 46 | matchFlag : 1; 47 | inProcessing : 1; 48 | stackPtr : SF_LONG_PTR_WIDTH; // Pointer to the top of the stack. 49 | widePtr : SF_LONG_PTR_WIDTH; // Loaded extension pointer. 50 | } 51 | } 52 | 53 | header_type sfExportStart_t { 54 | fields { 55 | realEtherType : 16; 56 | widePtr : 16; // Loaded extension pointer. 57 | } 58 | } 59 | 60 | header_type sfExportKey_t { 61 | fields { 62 | srcAddr : 32; 63 | dstAddr : 32; 64 | ports : 32; 65 | startTs : 32; 66 | pktCt : 16; 67 | protocol : 8; 68 | } 69 | } 70 | 71 | 72 | header_type sfShortVector_t { 73 | fields { 74 | w0 : 32; 75 | w1 : 32; 76 | w2 : 32; 77 | w3 : 32; 78 | } 79 | } 80 | 81 | header_type sfLongVector_t { 82 | fields { 83 | w0 : 32; 84 | w1 : 32; 85 | w2 : 32; 86 | w3 : 32; 87 | w4 : 32; 88 | w5 : 32; 89 | w6 : 32; 90 | w7 : 32; 91 | w8 : 32; 92 | w9 : 32; 93 | w10 : 32; 94 | w11 : 32; 95 | w12 : 32; 96 | w13 : 32; 97 | w14 : 32; 98 | w15 : 32; 99 | w16 : 32; 100 | w17 : 32; 101 | w18 : 32; 102 | w19 : 32; 103 | w20 : 32; 104 | w21 : 32; 105 | w22 : 32; 106 | w23 : 32; 107 | } 108 | } 109 | 110 | 111 | 112 | /*===== End of StarFlow Headers. ======*/ 113 | 114 | /*=========================================== 115 | = Forwarding Headers. = 116 | ===========================================*/ 117 | 118 | header_type ethernet_t { 119 | fields { 120 | dstAddr : 48; 121 | srcAddr : 48; 122 | etherType : 16; 123 | } 124 | } 125 | header ethernet_t ethernet; 126 | 127 | header_type ipv4_t { 128 | fields { 129 | version : 4; 130 | ihl : 4; 131 | diffserv : 8; 132 | totalLen : 16; 133 | identification : 16; 134 | flags : 3; 135 | fragOffset : 13; 136 | ttl : 8; 137 | protocol : 8; 138 | hdrChecksum : 16; // here 139 | srcAddr : 32; 140 | dstAddr: 32; 141 | } 142 | } 143 | header ipv4_t ipv4; 144 | 145 | header_type l4_ports_t { 146 | fields { 147 | ports : 32; 148 | // srcPort : 16; 149 | // dstPort : 16; 150 | } 151 | } 152 | header l4_ports_t l4_ports; 153 | 154 | 155 | /*===== End of Forwarding Headers. ======*/ 156 | 157 | 158 | 159 | 160 | parser start { 161 | return parse_ethernet; 162 | } 163 | 164 | parser parse_ethernet { 165 | extract(ethernet); 166 | return select(latest.etherType) { 167 | ETHERTYPE_STARFLOW_FULL : parse_starflow_full; // This should never ingress or egress. 168 | ETHERTYPE_STARFLOW_SHORT : parse_starflow_short; 169 | ETHERTYPE_IPV4 : parse_ipv4; 170 | default : ingress; 171 | } 172 | } 173 | 174 | // IP. 175 | parser parse_ipv4 { 176 | extract(ipv4); 177 | return parse_l4; 178 | } 179 | 180 | // TCP / UDP ports. 181 | parser parse_l4 { 182 | extract(l4_ports); 183 | 184 | return ingress; 185 | } 186 | 187 | // Parse tree for in-processing packet with both short and long headers. 188 | parser parse_starflow_full { 189 | extract(sfExportStart); 190 | extract(sfExportKey); 191 | extract(sfShortVector); 192 | extract(sfLongVector); 193 | return select(sfExportStart.realEtherType) { 194 | ETHERTYPE_IPV4 : parse_ipv4; 195 | default : ingress; 196 | } 197 | } 198 | 199 | parser parse_starflow_short { 200 | extract(sfExportStart); 201 | extract(sfExportKey); 202 | extract(sfShortVector); 203 | return select(sfExportStart.realEtherType) { 204 | ETHERTYPE_IPV4 : parse_ipv4; 205 | default : ingress; 206 | } 207 | } 208 | 209 | // Parse 210 | 211 | // // e2e mirrored is always (in this example) a ethernet TurboFlow packet. 212 | // @pragma packet_entry 213 | // parser start_e2e_mirrored { 214 | // extract(ethernet); 215 | // extract(sfExportStart); 216 | // extract(sfExportKey); 217 | // extract(sfExportPacketVector); 218 | // // set_metadata(tfMeta.isClone, 1); 219 | // return select(sfExportStart.realEtherType) { 220 | // ETHERTYPE_IPV4 : parse_ipv4; 221 | // default : ingress; 222 | // } 223 | // } 224 | 225 | 226 | // @pragma packet_entry 227 | // parser start_coalesced { 228 | // // extract(ethernet); 229 | // set_metadata(tfMeta.isClone, 1); 230 | // return ingress; 231 | // } --------------------------------------------------------------------------------