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:
parent
570b44b29b
commit
050ace2fb4
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ enum {
|
|||
DRLCMACDL,
|
||||
DRLCMACUL,
|
||||
DRLCMACSCHED,
|
||||
DRLCMACBW,
|
||||
DRLCMACMEAS,
|
||||
DBSSGP,
|
||||
DPCU,
|
||||
aDebug_LastEntry
|
||||
|
|
|
@ -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, "+---------------+");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue