Introduce new file for various measurements

The measurements include:
- DL bandwidth usage
- DL packet loss rate
- DL measurements by mobile
- UL measurements by BTS

In order to receive DL measurements from mobile, it must be enabled via
system information message at BSC.
This commit is contained in:
Andreas Eversberg 2013-03-16 16:22:02 +01:00 committed by Harald Welte
parent 570b44b29b
commit 050ace2fb4
8 changed files with 271 additions and 49 deletions

View File

@ -36,6 +36,7 @@ libgprs_la_SOURCES = \
gprs_rlcmac.cpp \
gprs_rlcmac_data.cpp \
gprs_rlcmac_sched.cpp \
gprs_rlcmac_meas.cpp \
gsm_timer.cpp \
bitvector.cpp \
pcu_l1_if.cpp \

View File

@ -244,6 +244,9 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
gprs_rlcmac_trigger_downlink_assignment(tbf, old_tbf, imsi);
}
/* store IMSI for debugging purpose */
strncpy(tbf->meas.imsi, imsi, sizeof(tbf->meas.imsi) - 1);
return 0;
}

View File

@ -40,7 +40,7 @@ static const struct log_info_cat default_categories[] = {
{"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACBW", "\033[1;31m", "GPRS RLC/MAC layer Bandwidth (RLCMAC)", LOGL_INFO, 1},
{"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1},
{"DBSSGP","\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO , 1},
{"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1},
};

View File

@ -38,7 +38,7 @@ enum {
DRLCMACDL,
DRLCMACUL,
DRLCMACSCHED,
DRLCMACBW,
DRLCMACMEAS,
DBSSGP,
DPCU,
aDebug_LastEntry

View File

@ -384,7 +384,9 @@ next_diagram:
}
/* set timestamp */
gettimeofday(&tbf->bw_tv, NULL);
gettimeofday(&tbf->meas.dl_bw_tv, NULL);
gettimeofday(&tbf->meas.rssi_tv, NULL);
gettimeofday(&tbf->meas.dl_loss_tv, NULL);
INIT_LLIST_HEAD(&tbf->llc_queue);
if (dir == GPRS_RLCMAC_UL_TBF)
@ -914,6 +916,10 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
{
struct msgb *msg;
/* Give final measurement report */
gprs_rlcmac_rssi_rep(tbf);
gprs_rlcmac_lost_rep(tbf);
debug_diagram(tbf->diag, "+---------------+");
debug_diagram(tbf->diag, "| THE END |");
debug_diagram(tbf->diag, "+---------------+");

View File

@ -226,8 +226,21 @@ struct gprs_rlcmac_tbf {
unsigned int fT; /* fTxxxx number */
unsigned int num_fT_exp; /* number of consecutive fT expirations */
struct timeval bw_tv; /* timestamp for bandwidth calculation */
uint32_t bw_octets; /* number of octets transmitted since bw_tv */
struct {
char imsi[16];
struct timeval dl_bw_tv; /* timestamp for dl bw calculation */
uint32_t dl_bw_octets; /* number of octets since bw_tv */
struct timeval rssi_tv; /* timestamp for rssi calculation */
int32_t rssi_sum; /* sum of rssi values */
int rssi_num; /* number of rssi values added since rssi_tv */
struct timeval dl_loss_tv; /* timestamp for loss calculation */
uint16_t dl_loss_lost; /* sum of lost packets */
uint16_t dl_loss_received; /* sum of received packets */
} meas;
uint8_t cs; /* current coding scheme */
@ -278,6 +291,19 @@ void debug_diagram(int diag, const char *format, ...);
#define debug_diagram(a, b, args...) ;
#endif
int gprs_rlcmac_received_lost(struct gprs_rlcmac_tbf *tbf, uint16_t received,
uint16_t lost);
int gprs_rlcmac_lost_rep(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_meas_rep(Packet_Measurement_Report_t *pmr);
int gprs_rlcmac_rssi(struct gprs_rlcmac_tbf *tbf, int8_t rssi);
int gprs_rlcmac_rssi_rep(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_dl_bw(struct gprs_rlcmac_tbf *tbf, uint16_t octets);
int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta);
struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn);

View File

@ -468,6 +468,9 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
}
LOGP(DRLCMAC, LOGL_ERROR, "RX: [PCU <- BTS] %s TFI: %u TLLI: 0x%08x FIXME: Packet ressource request\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli);
break;
case MT_PACKET_MEASUREMENT_REPORT:
gprs_rlcmac_meas_rep(&ul_control_block->u.Packet_Measurement_Report);
break;
default:
LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] unknown control block received\n");
}
@ -846,6 +849,9 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts,
LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA TBF=%d received (V(Q)=%d .. "
"V(R)=%d)\n", rh->tfi, tbf->dir.ul.v_q, tbf->dir.ul.v_r);
/* process RSSI */
gprs_rlcmac_rssi(tbf, rssi);
/* get TLLI */
if (!tbf->tlli_valid) {
struct gprs_rlcmac_tbf *dl_tbf, *ul_tbf;
@ -1213,29 +1219,6 @@ static struct msgb *llc_dequeue(struct gprs_rlcmac_tbf *tbf)
return msg;
}
static int gprs_rlcmac_debug_bw(struct gprs_rlcmac_tbf *tbf, uint16_t octets)
{
struct timeval now_tv, *bw_tv = &tbf->bw_tv;
uint32_t elapsed;
tbf->bw_octets += octets;
gettimeofday(&now_tv, NULL);
elapsed = ((now_tv.tv_sec - bw_tv->tv_sec) << 7)
+ ((now_tv.tv_usec - bw_tv->tv_usec) << 7) / 1000000;
if (elapsed < 128)
return 0;
LOGP(DRLCMACBW, LOGL_DEBUG, "DL Bandwitdh of TLLI=0x%08x: %d KBits/s\n",
tbf->tlli, tbf->bw_octets / elapsed);
/* reset bandwidth values timestamp */
memcpy(bw_tv, &now_tv, sizeof(struct timeval));
tbf->bw_octets = 0;
return 0;
}
/* send DL data block
*
* The messages are fragmented and forwarded as data blocks.
@ -1380,7 +1363,7 @@ do_resend:
LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for "
"TBF=%d that fits precisely in last block: "
"len=%d\n", tbf->tfi, tbf->llc_length);
gprs_rlcmac_debug_bw(tbf, tbf->llc_length);
gprs_rlcmac_dl_bw(tbf, tbf->llc_length);
/* block is filled, so there is no extension */
*e_pointer |= 0x01;
/* fill space */
@ -1440,7 +1423,7 @@ do_resend:
space -= chunk;
LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for TBF=%d: "
"len=%d\n", tbf->tfi, tbf->llc_length);
gprs_rlcmac_debug_bw(tbf, tbf->llc_length);
gprs_rlcmac_dl_bw(tbf, tbf->llc_length);
/* reset LLC frame */
tbf->llc_index = tbf->llc_length = 0;
/* dequeue next LLC frame, if any */
@ -1568,6 +1551,7 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
uint8_t bit;
uint16_t bsn;
struct msgb *msg;
uint16_t lost = 0, received = 0;
LOGP(DRLCMACDL, LOGL_DEBUG, "TBF=%d downlink acknowledge\n",
tbf->tfi);
@ -1587,25 +1571,7 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
/* calculate distance of ssn from V(S) */
dist = (tbf->dir.dl.v_s - ssn) & mod_sns;
/* check if distance is less than distance V(A)..V(S) */
if (dist < ((tbf->dir.dl.v_s - tbf->dir.dl.v_a) & mod_sns)) {
/* SSN - 1 is in range V(A)..V(S)-1 */
for (i = 63, bsn = (ssn - 1) & mod_sns;
i >= 0 && bsn != ((tbf->dir.dl.v_a - 1) & mod_sns);
i--, bsn = (bsn - 1) & mod_sns) {
bit = (rbb[i >> 3] >> (7 - (i&7))) & 1;
if (bit) {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got "
"ack for BSN=%d\n", bsn);
tbf->dir.dl.v_b[bsn & mod_sns_half]
= 'A';
} else {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got "
"NACK for BSN=%d\n", bsn);
tbf->dir.dl.v_b[bsn & mod_sns_half]
= 'N';
}
}
} else {
if (dist >= ((tbf->dir.dl.v_s - tbf->dir.dl.v_a) & mod_sns)) {
/* this might happpen, if the downlink assignment
* was not received by ms and the ack refers
* to previous TBF
@ -1616,6 +1582,27 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
tbf->tfi);
return 1; /* indicate to free TBF */
}
/* SSN - 1 is in range V(A)..V(S)-1 */
for (i = 63, bsn = (ssn - 1) & mod_sns;
i >= 0 && bsn != ((tbf->dir.dl.v_a - 1) & mod_sns);
i--, bsn = (bsn - 1) & mod_sns) {
bit = (rbb[i >> 3] >> (7 - (i&7))) & 1;
if (bit) {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got "
"ack for BSN=%d\n", bsn);
if (tbf->dir.dl.v_b[bsn & mod_sns_half]
!= 'A')
received++;
tbf->dir.dl.v_b[bsn & mod_sns_half] = 'A';
} else {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got "
"NACK for BSN=%d\n", bsn);
tbf->dir.dl.v_b[bsn & mod_sns_half] = 'N';
lost++;
}
}
/* report lost and received packets */
gprs_rlcmac_received_lost(tbf, received, lost);
/* raise V(A), if possible */
for (i = 0, bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s;
@ -1653,6 +1640,15 @@ int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
debug_diagram(tbf->diag, "got Final ACK");
/* range V(A)..V(S)-1 */
for (bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s;
bsn = (bsn + 1) & mod_sns) {
if (tbf->dir.dl.v_b[bsn & mod_sns_half] != 'A')
received++;
}
/* report all outstanding packets as received */
gprs_rlcmac_received_lost(tbf, received, lost);
/* check for LLC PDU in the LLC Queue */
msg = llc_dequeue(tbf);

190
src/gprs_rlcmac_meas.cpp Normal file
View File

@ -0,0 +1,190 @@
/* Measurements
*
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
*
* 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.
*/
#include <gprs_rlcmac.h>
#include <gprs_debug.h>
#include <pcu_l1_if.h>
#include <string.h>
#include <errno.h>
/*
* downlink measurement
*/
/* received Measurement Report */
int gprs_rlcmac_meas_rep(Packet_Measurement_Report_t *pmr)
{
NC_Measurement_Report_t *ncr;
NC_Measurements_t *nc;
int i;
LOGP(DRLCMACMEAS, LOGL_INFO, "Measuement Report of TLLI=0x%08x:",
pmr->TLLI);
switch (pmr->UnionType) {
case 0:
ncr = &pmr->u.NC_Measurement_Report;
LOGPC(DRLCMACMEAS, LOGL_INFO, " NC%u Serv %d dbm",
ncr->NC_MODE + 1,
ncr->Serving_Cell_Data.RXLEV_SERVING_CELL - 110);
for (i = 0; i < ncr->NUMBER_OF_NC_MEASUREMENTS; i++) {
nc = &ncr->NC_Measurements[i];
LOGPC(DRLCMACMEAS, LOGL_DEBUG, ", Neigh %u %d dbm",
nc->FREQUENCY_N, nc->RXLEV_N - 110);
}
LOGPC(DRLCMACMEAS, LOGL_INFO, "\n");
break;
case 1:
LOGPC(DRLCMACMEAS, LOGL_INFO,
" <EXT Reporting not supported!>\n");
break;
}
return 0;
}
/*
* uplink measurement
*/
/* RSSI values received from MS */
int gprs_rlcmac_rssi(struct gprs_rlcmac_tbf *tbf, int8_t rssi)
{
struct timeval now_tv, *rssi_tv = &tbf->meas.rssi_tv;
uint32_t elapsed;
tbf->meas.rssi_sum += rssi;
tbf->meas.rssi_num++;
gettimeofday(&now_tv, NULL);
elapsed = ((now_tv.tv_sec - rssi_tv->tv_sec) << 7)
+ ((now_tv.tv_usec - rssi_tv->tv_usec) << 7) / 1000000;
if (elapsed < 128)
return 0;
gprs_rlcmac_rssi_rep(tbf);
/* reset rssi values and timestamp */
memcpy(rssi_tv, &now_tv, sizeof(struct timeval));
tbf->meas.rssi_sum = 0;
tbf->meas.rssi_num = 0;
return 0;
}
/* Give RSSI report */
int gprs_rlcmac_rssi_rep(struct gprs_rlcmac_tbf *tbf)
{
/* No measurement values */
if (!tbf->meas.rssi_num)
return -EINVAL;
LOGP(DRLCMACMEAS, LOGL_INFO, "UL RSSI of TLLI=0x%08x: %d dBm\n",
tbf->tlli, tbf->meas.rssi_sum / tbf->meas.rssi_num);
return 0;
}
/*
* lost frames
*/
/* Lost frames reported from RLCMAC layer */
int gprs_rlcmac_received_lost(struct gprs_rlcmac_tbf *tbf, uint16_t received,
uint16_t lost)
{
struct timeval now_tv, *loss_tv = &tbf->meas.dl_loss_tv;
uint32_t elapsed;
uint16_t sum = received + lost;
/* No measurement values */
if (!sum)
return -EINVAL;
LOGP(DRLCMACMEAS, LOGL_DEBUG, "DL Loss of TLLI 0x%08x: Received: %4d "
"Lost: %4d Sum: %4d\n", tbf->tlli, received, lost, sum);
tbf->meas.dl_loss_received += received;
tbf->meas.dl_loss_lost += lost;
gettimeofday(&now_tv, NULL);
elapsed = ((now_tv.tv_sec - loss_tv->tv_sec) << 7)
+ ((now_tv.tv_usec - loss_tv->tv_usec) << 7) / 1000000;
if (elapsed < 128)
return 0;
gprs_rlcmac_lost_rep(tbf);
/* reset lost values and timestamp */
memcpy(loss_tv, &now_tv, sizeof(struct timeval));
tbf->meas.dl_loss_received = 0;
tbf->meas.dl_loss_lost = 0;
return 0;
}
/* Give Lost report */
int gprs_rlcmac_lost_rep(struct gprs_rlcmac_tbf *tbf)
{
uint16_t sum = tbf->meas.dl_loss_lost + tbf->meas.dl_loss_received;
/* No measurement values */
if (!sum)
return -EINVAL;
LOGP(DRLCMACMEAS, LOGL_INFO, "DL packet loss of IMSI=%s / TLLI=0x%08x: "
"%d%%\n", tbf->meas.imsi, tbf->tlli,
tbf->meas.dl_loss_lost * 100 / sum);
return 0;
}
/*
* downlink bandwidth
*/
int gprs_rlcmac_dl_bw(struct gprs_rlcmac_tbf *tbf, uint16_t octets)
{
struct timeval now_tv, *bw_tv = &tbf->meas.dl_bw_tv;
uint32_t elapsed;
tbf->meas.dl_bw_octets += octets;
gettimeofday(&now_tv, NULL);
elapsed = ((now_tv.tv_sec - bw_tv->tv_sec) << 7)
+ ((now_tv.tv_usec - bw_tv->tv_usec) << 7) / 1000000;
if (elapsed < 128)
return 0;
LOGP(DRLCMACMEAS, LOGL_INFO, "DL Bandwitdh of IMSI=%s / TLLI=0x%08x: "
"%d KBits/s\n", tbf->meas.imsi, tbf->tlli,
tbf->meas.dl_bw_octets / elapsed);
/* reset bandwidth values timestamp */
memcpy(bw_tv, &now_tv, sizeof(struct timeval));
tbf->meas.dl_bw_octets = 0;
return 0;
}