//===================================================== file = lb1_csim.c ==== //= A CSIM18 simulation of a byte-based leaky bucket for packet traffic = //= - Can be used for shaping or policing (testing for conformance) = //============================================================================ //= Notes: 1) Time unit is the millisecond = //= 2) Assumes an input trace file with pairs = //= with delta_time in real millisec and pkt_len in integer bytes = //= 3) Assumes MEDIA_RATE is in bits per millsec = //= 4) The trace input file is TRACE_FILE and the shapted output = //= file is SHAPE_FILE = //= 5) Must manually set MEDIA_RATE, MEAN_RATE, and MAX_BURST. = //= MAX_BURST must be divisible by 8. = //= 6) Must manually set CUMUL_FLAG (if FALSE then delta time will = //= be output to SHAPE_FILE) = //= 7) Must manually set POLICE_FLAG. = //= 8) If a packet leaves at the exact time a byte is supposed to = //= increment in the token bucket, a race condition makes the = //= result unpredictable (i.e., whether the byte will increment = //= before or after the packet transmission). = //=--------------------------------------------------------------------------= //= History: KJC (07/04/01) - Genesis (from lb_csim.c) = //============================================================================ #pragma warn -pro // Disable function prototype warning #pragma warn -stu // Disable undefined structure warning #pragma warn -rch // Disable unreachable code warning #pragma warn -ccc // Disable condition always true warning //----- Includes ------------------------------------------------------------- #include // Needed for printf(), feof(), and fscanf() #include // Needed for exit() and ato*() #include "csim.h" // Needed for CSIM18 stuff //----- Defines --------------------------------------------------------------- #define FALSE 0 // Boolean false #define TRUE 1 // Boolean true #define TRACE_FILE "trace.dat" // Name of trace file #define SHAPE_FILE "shape.dat" // Name of shaped traffic file #define MEDIA_RATE 10.0e3 // Output link rate in bits per millisec #define MEAN_RATE 5.0e3 // Mean rate in bits per millisec #define MAX_BURST 120000 // Max burst size in bits (token bucket size) #define CUMUL_FLAG FALSE // Flag for cumulative or delta time #define POLICE_FLAG TRUE // Flag to output non-conformance messages //----- Globals --------------------------------------------------------------- FILE *Tf; // Trace (input) file pointer FILE *Sf; // Shaped (output) file pointer FACILITY Server; // Server facility TABLE Bits_sent; // Bits sent table EVENT Done; // Done event EVENT Pkt_release_event; // Packet release event int Eof_flag; // End-of-file flag for trace file int Total_count; // Total count of packets int Byte_count; // Byte counter for token bucket double Last_clock; // Clock value at last transmit int Conf_count; // Counter for non-conformance events //----- Prototypes ------------------------------------------------------------ void generate(void); // Trace file traffic generator void leaky_bucket(int pkt_len); // Leaky bucket shaper void byte_gen(void); // Byte generator for token bucket //============================================================================= //== Main program == //============================================================================= void sim(void) { // Create the simulation create("sim"); // Increase max_processes max_processes(10000L); // Open the trace and shape files (clobbers any existing shape file) Tf = fopen(TRACE_FILE, "r"); if (Tf == NULL) { printf(" >>> ERROR in opening trace file '%s' \n", TRACE_FILE); exit(1); } Sf = fopen(SHAPE_FILE, "w"); if (Sf == NULL) { printf(" >>> ERROR in opening shape file '%s' \n", SHAPE_FILE); exit(1); } // CSIM initializations Server = facility("Server"); Done = event("Done event"); Bits_sent = table("Bits sent table"); Pkt_release_event = event("Packet release event"); // Variable initializations (always start with a full token bucket) Total_count = 0; Byte_count = MAX_BURST / 8; Last_clock = 0.0; Conf_count = 0; // Initiate byte_gen() and generate() and wait for Done event to be set byte_gen(); generate(); wait(Done); // Output results printf("============================================================= \n"); printf("== *** CSIM18 leaky bucket simulation *** == \n"); printf("============================================================= \n"); printf("= >>> Traffic trace input from file %s \n", TRACE_FILE); printf("= >>> Shaped traffic output to file %s \n", SHAPE_FILE); if (POLICE_FLAG == TRUE) printf("= >>> Policing is TRUE \n"); printf("= Media rate = %9.2f bits/msc \n", MEDIA_RATE); printf("= Leaky bucket mean rate = %9.2f bits/msc \n", MEAN_RATE); printf("= Leaky bucket burst size = %9d bits (%d bytes) \n", MAX_BURST, (MAX_BURST / 8)); printf("============================================================= \n"); printf("= Total simulation time = %9.2f msec \n", clock); printf("= Number of packets = %9d pkts \n", Total_count); printf("= Non-conformance events = %9d events \n", Conf_count); printf("= Throughput = %9.2f bits/msec \n", table_sum(Bits_sent) / clock); printf("= Mean response time = %9.2f msec \n", resp(Server)); printf("= Mean length = %9.2f pkts \n", qlen(Server)); printf("============================================================= \n"); return; } //============================================================================= //== Function to generate packets from a trace file == //============================================================================= void generate(void) { char in_string1[256]; // Input string #1 char in_string2[256]; // Input string #2 double time_stamp; // Delta time in seconds from trace file int pkt_len; // Packet length in bytes from trace file create("generate"); // Read and generate packets until end-of-file Eof_flag = FALSE; while(!feof(Tf)) { fscanf(Tf, "%s %s \n", in_string1, in_string2); time_stamp = atof(in_string1); pkt_len = atoi(in_string2); if ((time_stamp < 0.0) || (pkt_len <= 0)) { printf(" >>> ERROR in input value (time_stamp = %f pkt_len = %d) \n", time_stamp, pkt_len); exit(1); } hold(time_stamp); leaky_bucket(pkt_len); if (feof(Tf)) Eof_flag = TRUE; } return; } //============================================================================= //== Leaky bucket process == //============================================================================= void leaky_bucket(int pkt_len) { create("leaky_bucket"); // Increment total arriving packets counter Total_count++; // Reserve the server reserve(Server); // DEBUG... printf("%f -- %5d -----> ", clock, Byte_count); // Do the "token matching" by bytes Byte_count = Byte_count - pkt_len; if (Byte_count < 0) { Conf_count++; if (POLICE_FLAG == TRUE) { fprintf(Sf,"*** non-conformance at %f msec -- ", clock); fprintf(Sf,"Byte_count = %d bytes \n", Byte_count); } clear(Pkt_release_event); queue(Pkt_release_event); } // Transmit the matched packet and record the number of bits sent hold((8.0 * pkt_len) / MEDIA_RATE); record(8.0 * pkt_len, Bits_sent); // Output to shape file if (CUMUL_FLAG == TRUE) fprintf(Sf, "%f %d \n", clock, pkt_len); else { fprintf(Sf, "%f %d \n", (clock - Last_clock), pkt_len); Last_clock = clock; } // DEBUG... printf("%f -- %5d \n", clock, Byte_count); // Release the server release(Server); // Check for Done condition if (Eof_flag == TRUE) { hold(0.0); if (status(Server) == FREE) set(Done); } return; } //============================================================================= //== Token generation process == //== - Tokens are generated per byte == //============================================================================= void byte_gen(void) { create("byte_gen"); // Increment Byte_count up to BUCKET SIZE while(1) { hold(8.0 / MEAN_RATE); if (Byte_count < (MAX_BURST / 8)) Byte_count++; if (Byte_count >= 0) set(Pkt_release_event); } }