/* $Id: mcl_flid_sl.cpp,v 1.1.1.1 2003/09/03 12:45:43 chneuman Exp $ */ /* * Copyright (c) 1999-2003 INRIA - Universite Paris 6 - All rights reserved * (main authors: Julien Laboure - julien.laboure@inrialpes.fr * Vincent Roca - vincent.roca@inrialpes.fr) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* * LCC congestion control module FLID SL (Static Layer). */ #include "mcl_includes.h" #ifdef FLIDS /* { */ int CheckSequence(mclcb_t *mclcb, u_int8_t layer, u_int16_t seqid, u_int8_t tsi); void ComputeTSI(mclcb_t *mclcb); /**** FLIDs_InitSession **** * Init. the FLID Static congestion control mechanism for a given session * This must be the called before any other calls * Parameters: mclcb: points to the session Control Block * mode : unused * Return Value: N/A */ void FLIDs_InitSession( mclcb_t *mclcb ) { int i; flids_cb_t *cb; TRACELVL( 5, (mcl_stdout, "-> FLIDs: FLIDs_InitSession: mclcb=x%x\n", (int) mclcb)) /* WARNING: no use of modes? */ cb = &(mclcb->flids_cb); memset((void *)cb, 0, sizeof(flids_cb_t)); cb->SessionState = 1; /* Initial State */ cb->tsd = FLIDS_TSD; cb->tsi = 0; cb->long_tsi = 0; cb->rx_CongestionDetected = 0; cb->rx_DeafPeriod = 0; cb->flids_deaf_period = FLIDS_DEAF_PERIOD; cb->flids_tx_timer_count = 0; for( i=0; irx_LayerState[i] = 1; cb->tx_LayerSeq[i] = 0; cb->rx_IncreaseTrigger[i] = 0; cb->rx_WaitFor[i] = 0; cb->tx_LayerTrig[i] = 0; } TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_InitSession\n")) } /**** FLIDs_EndSession **** * Must be called when ending a session * Parameters: mclcb: points to the session Control Block * Return Value: N/A */ void FLIDs_EndSession( mclcb_t *mclcb ) { TRACELVL(5, (mcl_stdout, "-> FLIDs: FLIDs_EndSession\n")) // Nothing... TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_EndSession\n")) } void FLIDs_TxTimer(mclcb_t *mclcb) { FLIDs_NewTimeSlot(mclcb); } /* Increase Time Slot Index (TSI) periodically (period=tsd) */ void FLIDs_NewTimeSlot(mclcb_t *mclcb) { flids_cb_t *cb; TRACELVL(5, (mcl_stdout, "-> FLIDs: FLIDs_NewTimeSlot\n")) ASSERT(mclcb!=NULL) cb = &(mclcb->flids_cb); cb->tsi = (cb->tsi+1)%128; /* WARNING: why not using 8bits for TSI ??? */ cb->long_tsi++; if (mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tnew_TS %d\n", time.tv_sec, time.tv_usec, cb->long_tsi)) } ComputeTSI(mclcb); TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_NewTimeSlot\n")) } /**** FLIDs_tx_FillHeader **** * Build the FLIDs header for each packet to send * * Parameters: * mclcb : points to the session Control Block * hdr_buff: points to a buffer receiving the FLIDs header * grp_idx : Index of the group within the set of groups used for that session * Return Value: MCL_OK (0) if success, else the corresponding error code */ int FLIDs_tx_FillHeader( mclcb_t *mclcb, flids_hdr_t *hdr_buff, u_int8_t grp_idx) { u_int16_t hdr_seqno; flids_cb_t *cb; TRACELVL(5, (mcl_stdout, "-> FLIDs: FLIDs_tx_FillHeader: mclcb=x%x, grp_idx=%d\n", (int) mclcb, grp_idx)) ASSERT(mclcb!=NULL) cb = &(mclcb->flids_cb); ASSERT(grp_idx < MAX_TX_LEVEL && grp_idx < mclcb->nb_level) ASSERT(hdr_buff!=NULL) hdr_seqno = cb->tx_LayerSeq[grp_idx]; (cb->tx_LayerSeq[grp_idx])++; hdr_buff->seqno = htons(hdr_seqno); /* Sequence number */ hdr_buff->gn = grp_idx; /* Index of the group */ hdr_buff->tsi = cb->tsi; /* Time Slot Index */ hdr_buff->trigger = cb->tx_LayerTrig[grp_idx]; if (mclcb->verbose == 2 && (hdr_seqno%10==0)) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tist_bit %d %d\n", time.tv_sec, time.tv_usec, hdr_buff->trigger, grp_idx)) } TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_tx_FillHeader: ok\n")) return MCL_OK; } /**** FLIDs_rx_AnalyzePacket **** * Analyze header for each packet. * * Return Value: layer >=0 if success, else the error code as defined * in mcl_error.h. */ int FLIDs_rx_AnalyzePacket ( mclcb_t *mclcb, flids_hdr_t *hdr_buff ) { u_int8_t groupn; u_int16_t seqno; u_int8_t pkt_tsi; u_int8_t new_tsi; u_int8_t trigger; flids_cb_t *cb; ASSERT(hdr_buff!=NULL) TRACELVL(5, (mcl_stdout, "-> FLIDs: FLIDs_rx_AnalyzePacket\n")) ASSERT(mclcb!=NULL) cb = &(mclcb->flids_cb); pkt_tsi = hdr_buff->tsi; new_tsi = pkt_tsi; trigger = hdr_buff->trigger; groupn = hdr_buff->gn; seqno = ntohs(hdr_buff->seqno); // printf("FLIDs_PKT layer=%d seq=%d\n", groupn, seqno); if(groupn >= mclcb->nb_level) { /* Bad group number, so ignore... */ TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_rx_AnalyzePacket (BAD_LAYER)\n")) return ERR_BAD_LAYER; } if (mclcb->verbose == 2 && (seqno%10==0)) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tist_bit %d %d\n", time.tv_sec, time.tv_usec, trigger, groupn)) } if( cb->SessionState == 1 ) { // Session First Packet cb->tsi = pkt_tsi; cb->SessionState = 2; cb->rx_WaitFor[groupn] = seqno + 1; cb->rx_LayerState[groupn] = 3; cb->rx_IncreaseTrigger[groupn] = trigger; goto end; } if( cb->rx_LayerState[groupn] == 1) { /* First packet on this group... (or first packet for a readded group) */ cb->rx_WaitFor[groupn] = seqno + 1; cb->rx_LayerState[groupn]=3; cb->rx_IncreaseTrigger[groupn] = trigger; goto end; } else { /* check if some pkts have been lost or not */ new_tsi = CheckSequence(mclcb, groupn, seqno, pkt_tsi); } /* First Packet (no matter the group) for this TimeSlot... DECISION HERE */ if( new_tsi != cb->tsi ) { int i = 0; if( new_tsi != (cb->tsi+1)%128 ) { PRINT_OUT((mcl_stdout, "FLIDs WARNING! Unexpected TSI Value (Old=%d, New=%d)\n",cb->tsi, new_tsi)) } cb->tsi = new_tsi; TRACELVL(3, (mcl_stdout, "FLIDs: Entering NEW Time Slot (tsi=%d, trigger was %d)\n", cb->tsi, cb->rx_IncreaseTrigger[mclcb->nb_level-1])) if (mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tnew_TS %d\n", time.tv_sec, time.tv_usec, cb->tsi)) } if (cb->rx_DeafPeriod > 0 ) { cb->rx_DeafPeriod--; if (cb->rx_DeafPeriod == 0 && mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT(( stdout, "\n%ld.%06ld\tend_deaf\n", time.tv_sec, time.tv_usec)) } } for( i=0; irx_LayerState[i] = 2; } if ( cb->rx_CongestionDetected ) { if(!cb->rx_DeafPeriod) { /* too many losses... drop a layer! */ if (mcl_drop_layer(mclcb, MCL_HIGHEST_LAYER, MCL_DO_IT ) < 0) { /* error, cannot drop layer */ TRACELVL(3, (mcl_stdout, "<- FLIDs: cant drop layer, ignore\n")) } else { TRACELVL(2, (mcl_stdout, " FLIDs: congestion detected, highest layer dropped, now receiving from %d layers\n", mclcb->nb_level)) /* Entering Deaf Period... */ cb->rx_DeafPeriod = cb->flids_deaf_period; /* initial state for futur potential use of this layer*/ cb->rx_LayerState[mclcb->nb_level]=1; } } cb->rx_CongestionDetected = 0; goto end; } else if(cb->rx_IncreaseTrigger[mclcb->nb_level-1]) { mcl_add_layer(mclcb, MCL_HIGHEST_LAYER); cb->rx_LayerState[mclcb->nb_level-1]=1; TRACELVL(2, (mcl_stdout, " FLIDs: adding a new layer, now receiving from %d layers\n", mclcb->nb_level)) } cb->rx_CongestionDetected = 0; } ASSERT(cb->tsi == new_tsi) // HACK: if no packets received during a complete timeslot then FLIDs should [MAYBE] crash HERE ;) if(cb->rx_LayerState[groupn]==2) { // First Packet ON THIS GROUP FOR THIS TIMESLOT cb->rx_IncreaseTrigger[groupn] = trigger; cb->rx_LayerState[groupn]=3; TRACELVL(3, (mcl_stdout, "First Packet for Layer %d for Timeslot %d\n", groupn, new_tsi)) } else { ASSERT( cb->rx_LayerState[groupn]==3 ) if(cb->rx_IncreaseTrigger[groupn] != trigger) { TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_rx_AnalyzePacket (BAD_TRIGGER)\n")) return ERR_BAD_TRIGGER; } } end: TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_rx_AnalyzePacket (ok)\n")) return groupn; } // Return NEW CURRENT TSI... int CheckSequence(mclcb_t *mclcb, u_int8_t layer, u_int16_t seqid, u_int8_t tsi) { flids_cb_t *cb; u_int16_t Delta1, Delta2 = 0; u_int8_t NewTSI = tsi; TRACELVL(5, (mcl_stdout, "-> FLIDs: CheckSequence\n")) ASSERT(mclcb!=NULL) cb = &(mclcb->flids_cb); if( cb->rx_WaitFor[layer] == seqid || (cb->rx_WaitFor[layer]>0 && cb->rx_WaitFor[layer]==seqid+1) || (cb->rx_WaitFor[layer]==0 && seqid==128)) { /* This is the packet we're waiting for, let's go on! */ (cb->rx_WaitFor[layer])++; TRACELVL(5, (mcl_stdout, "<- FLIDs: CheckSequence (good seq)\n")) return NewTSI; } /* This is not the one we're waiting for... */ if( cb->rx_WaitFor[layer] < seqid ) { Delta1 = seqid - cb->rx_WaitFor[layer]; Delta2 = 65535 - Delta1; if ( Delta1 < Delta2 ) { /* Some packet(s) are missing */ /* eg. wait seq 1512 and get 1513, so 1512 is missing */ cb->rx_WaitFor[layer] = seqid +1; NewTSI = tsi; } else { /* Late arrival packet (uint16 overflow) */ /* eg. we're waiting seq 4 and we get seq 65532 */ NewTSI = cb->tsi; } } else /* rx_WaitFor > seqid */ { Delta1 = cb->rx_WaitFor[layer] - seqid; Delta2 = 65535 - Delta1; if ( Delta1 < Delta2 ) { /* Late arrival packet */ /* ie: we're waiting seq 501 and we get seq 498 */ NewTSI = cb->tsi; } else { /* Some packet(s) are missing (uint16 overflow) */ /* ie: waiting seq 65531 and get seq 3 */ cb->rx_WaitFor[layer] = seqid +1; NewTSI = tsi; } } if( !cb->rx_CongestionDetected ) { cb->rx_CongestionDetected = 1; if (mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tloss_detected %d %d %d\n", time.tv_sec, time.tv_usec, layer, seqid, cb->rx_CongestionDetected)) } } TRACELVL(5, (mcl_stdout, "<- FLIDs: CheckSequence (seq broken)\n")) return NewTSI; } void ComputeTSI(mclcb_t *mclcb) { flids_cb_t *cb; double P = 0.0; long B = 0; double BB=0.0; txlvl_t txlvl; int LevelTotBw = 0; int i=0; ASSERT(mclcb!=NULL) cb = &(mclcb->flids_cb); for( i=0; itx_LayerTrig[i] = 0; } B = cb->long_tsi; for(i=1; B!=0; i++) { BB += ((double)(B%2)) / pow(2.0, i); B >>= 1; } for( i=0; i < mclcb->nb_level; i++) { txlvl = mclcb->txlvl_tab[i]; LevelTotBw = txlvl.rate * mclcb->datagram_sz * mclcb->rate_l0; // Byte per sec if ( i+1 == mclcb->nb_level) /* Last Layer */ { P = 0.0; } else { P = min( 1.0, (20.0*(float)mclcb->datagram_sz* (cb->tsd/1000000))/(float)LevelTotBw ); } if(BB<=P) { cb->tx_LayerTrig[i] = 1; /* Increase Signal Trigger */ } else { cb->tx_LayerTrig[i] = 0; } } #ifdef DEBUG for( i=mclcb->nb_level-1; i>0; i--) { if(cb->tx_LayerTrig[i] == 1) { ASSERT(cb->tx_LayerTrig[i-1]==1) } } #endif /* DEBUG */ } /**** FLIDs_ctl () **** * Used to set various FLIDs options and parameters. * Parameters: mclcb : point to the mclcl structure of the session. optname : a defined option name -> FLIDS_OPT_* optvalue : the value for the option. optlen : size of optvalue. * Return Value: 1 if success. */ int FLIDs_ctl (mclcb_t *mclcb, int optname, void *optvalue, int optlen) { flids_cb_t *cb = &(mclcb->flids_cb); TRACELVL(5, (mcl_stdout, "-> FLIDs: FLIDs_ctl: optname=%d, optvalue=x%x, optlen=%d\n", optname, (int)optvalue, optlen)) switch (optname) { case FLIDS_OPT_DEAF_PERIOD: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR(( stderr, "FLIDs_ctl ERROR FLIDS_OPT_DEAF_PERIOD: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr, "FLIDs_ctl ERROR: FLIDS_OPT_DEAF_PERIOD must be positive (got %d)\n",(*(int*)optvalue))) goto error; } cb->flids_deaf_period = *(int*)optvalue; break; case FLIDS_OPT_TSD: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR(( stderr, "FLIDs_ctl ERROR FLIDS_OPT_TSD: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr, "FLIDs_ctl ERROR: FLIDS_OPT_TSD must be positive (got %d)\n",(*(int*)optvalue))) goto error; } cb->tsd = *(int*)optvalue; break; default: TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_ctl (Unknown option)\n")) return ERR_OPT_UNKNOWN; break; } TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_ctl (ok)\n")) return MCL_OK; error: TRACELVL(5, (mcl_stdout, "<- FLIDs: FLIDs_ctl (Failure)\n")) return MCL_ERROR; } #endif /* } FLIDS */