llc: Separate LLC queue handling from gprs_llc

Currently the gprs_llc class handles both LLC queueing and the
partition into smaller pieces for RLC/MAC encapsulation. This hinders
the separation of TBF and MS related data, since LLC queueing belongs
to the MS related code while the RLC/MAC encoding/decoding belongs to
the TBF layer.

This commits takes the LLC queueing related methods and members and
puts them into a new class gprs_llc_queue. It puts the queueing
object into gprs_rlcmac_tbf and adds accessor functions. The
implementation in tbf.cpp and tbf_dl.cpp is adapted accordingly.

Ticket: #1674
Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2015-05-29 10:37:09 +02:00
parent b3f713bd7b
commit 6dbe822062
5 changed files with 92 additions and 55 deletions

View File

@ -42,12 +42,6 @@ void gprs_llc::reset_frame_space()
m_index = 0;
}
void gprs_llc::enqueue(struct msgb *llc_msg)
{
m_queue_size += 1;
msgb_enqueue(&queue, llc_msg);
}
/* Put an Unconfirmed Information (UI) Dummy command, see GSM 44.064, 6.4.2.2 */
void gprs_llc::put_dummy_frame(size_t req_len)
{
@ -82,36 +76,62 @@ void gprs_llc::append_frame(const uint8_t *data, size_t len)
m_length += len;
}
void gprs_llc::clear(BTS *bts)
void gprs_llc::init()
{
reset();
}
bool gprs_llc::is_user_data_frame(uint8_t *data, size_t len)
{
if (len < 2)
return false;
if ((data[0] & 0x0f) == 1 /* GPRS_SAPI_GMM */)
return false;
if ((data[0] & 0x0e) != 0xc0 /* LLC UI */)
/* It is not an LLC UI frame */
return false;
return true;
}
void gprs_llc_queue::init()
{
INIT_LLIST_HEAD(&m_queue);
m_queue_size = 0;
m_avg_queue_delay = 0;
}
void gprs_llc_queue::enqueue(struct msgb *llc_msg)
{
m_queue_size += 1;
msgb_enqueue(&m_queue, llc_msg);
}
void gprs_llc_queue::clear(BTS *bts)
{
struct msgb *msg;
while ((msg = msgb_dequeue(&queue))) {
bts->llc_dropped_frame();
while ((msg = msgb_dequeue(&m_queue))) {
if (bts)
bts->llc_dropped_frame();
msgb_free(msg);
}
m_queue_size = 0;
}
void gprs_llc::init()
{
INIT_LLIST_HEAD(&queue);
m_queue_size = 0;
m_avg_queue_delay = 0;
reset();
}
#define ALPHA 0.5f
struct msgb *gprs_llc::dequeue()
struct msgb *gprs_llc_queue::dequeue()
{
struct msgb *msg;
struct timeval *tv, tv_now, tv_result;
uint32_t lifetime;
msg = msgb_dequeue(&queue);
msg = msgb_dequeue(&m_queue);
if (!msg)
return NULL;
@ -128,8 +148,7 @@ struct msgb *gprs_llc::dequeue()
return msg;
}
void gprs_llc::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv)
void gprs_llc_queue::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv)
{
uint16_t delay_csec;
if (bts->bts_data()->force_llc_lifetime)
@ -152,7 +171,7 @@ void gprs_llc::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct
timeradd(&now, &csec, tv);
}
bool gprs_llc::is_frame_expired(struct timeval *tv_now, struct timeval *tv)
bool gprs_llc_queue::is_frame_expired(struct timeval *tv_now, struct timeval *tv)
{
/* Timeout is infinite */
if (tv->tv_sec == 0 && tv->tv_usec == 0)
@ -160,18 +179,3 @@ bool gprs_llc::is_frame_expired(struct timeval *tv_now, struct timeval *tv)
return timercmp(tv_now, tv, >);
}
bool gprs_llc::is_user_data_frame(uint8_t *data, size_t len)
{
if (len < 2)
return false;
if ((data[0] & 0x0f) == 1 /* GPRS_SAPI_GMM */)
return false;
if ((data[0] & 0x0e) != 0xc0 /* LLC UI */)
/* It is not an LLC UI frame */
return false;
return true;
}

View File

@ -27,24 +27,18 @@
* I represent the LLC data to a MS
*/
struct gprs_llc {
static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv);
static bool is_frame_expired(struct timeval *now, struct timeval *tv);
static bool is_user_data_frame(uint8_t *data, size_t len);
void init();
void reset();
void reset_frame_space();
void enqueue(struct msgb *llc_msg);
struct msgb *dequeue();
void put_frame(const uint8_t *data, size_t len);
void put_dummy_frame(size_t req_len);
void append_frame(const uint8_t *data, size_t len);
void consume(size_t len);
void consume(uint8_t *data, size_t len);
void clear(BTS *bts);
uint16_t chunk_size() const;
uint16_t remaining_space() const;
@ -55,12 +49,31 @@ struct gprs_llc {
uint8_t frame[LLC_MAX_LEN]; /* current DL or UL frame */
uint16_t m_index; /* current write/read position of frame */
uint16_t m_length; /* len of current DL LLC_frame, 0 == no frame */
struct llist_head queue; /* queued LLC DL data */
};
/**
* I store the LLC frames that come from the SGSN.
*/
struct gprs_llc_queue {
static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv);
static bool is_frame_expired(struct timeval *now, struct timeval *tv);
static bool is_user_data_frame(uint8_t *data, size_t len);
void init();
void enqueue(struct msgb *llc_msg);
struct msgb *dequeue();
void clear(BTS *bts);
size_t size() const;
private:
uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */
size_t m_queue_size;
struct llist_head m_queue; /* queued LLC DL data */
};
inline uint16_t gprs_llc::chunk_size() const
{
return m_length - m_index;
@ -92,3 +105,8 @@ inline bool gprs_llc::fits_in_current_frame(uint8_t chunk_size) const
{
return m_length + chunk_size <= LLC_MAX_LEN;
}
inline size_t gprs_llc_queue::size() const
{
return this ? m_queue_size : 0;
}

View File

@ -219,7 +219,7 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
tbf_name(tbf));
tbf->stop_timer();
#warning "TODO: Could/Should generate bssgp_tx_llc_discarded"
tbf->m_llc.clear(tbf->bts);
tbf->llc_queue()->clear(tbf->bts);
tbf_unlink_pdch(tbf);
llist_del(&tbf->list.list);
@ -451,6 +451,7 @@ static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
gettimeofday(&tbf->meas.rssi_tv, NULL);
tbf->m_llc.init();
tbf->llc_queue()->init();
return 0;
}

View File

@ -151,6 +151,8 @@ struct gprs_rlcmac_tbf {
void assign_imsi(const char *imsi);
uint8_t ta() const;
void set_ta(uint8_t);
gprs_llc_queue *llc_queue();
const gprs_llc_queue *llc_queue() const;
time_t created_ts() const;
@ -229,6 +231,8 @@ protected:
/* Field to take the TA value if no MS is associated */
uint8_t m_ta;
gprs_llc_queue m_llc_queue;
private:
mutable char m_name_buf[60];
};
@ -285,6 +289,16 @@ inline GprsMs *gprs_rlcmac_tbf::ms()
return m_ms;
}
inline gprs_llc_queue *gprs_rlcmac_tbf::llc_queue()
{
return &m_llc_queue;
}
inline const gprs_llc_queue *gprs_rlcmac_tbf::llc_queue() const
{
return &m_llc_queue;
}
inline bool gprs_rlcmac_tbf::is_tlli_valid() const
{
return tlli() != 0;

View File

@ -122,11 +122,11 @@ int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class,
if (!llc_msg)
return -ENOMEM;
tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
gprs_llc::calc_pdu_lifetime(bts, pdu_delay_csec, tv);
gprs_llc_queue::calc_pdu_lifetime(bts, pdu_delay_csec, tv);
tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
gettimeofday(tv, NULL);
memcpy(msgb_put(llc_msg, len), data, len);
m_llc.enqueue(llc_msg);
llc_queue()->enqueue(llc_msg);
tbf_update_ms_class(this, ms_class);
start_llc_timer();
}
@ -253,7 +253,7 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
gettimeofday(&tv_now, NULL);
timeradd(&tv_now, &hyst_delta, &tv_now2);
while ((msg = m_llc.dequeue())) {
while ((msg = llc_queue()->dequeue())) {
tv_disc = (struct timeval *)msg->data;
msgb_pull(msg, sizeof(*tv_disc));
tv_recv = (struct timeval *)msg->data;
@ -262,11 +262,11 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
gprs_bssgp_update_queue_delay(tv_recv, &tv_now);
/* Is the age below the low water mark? */
if (!gprs_llc::is_frame_expired(&tv_now2, tv_disc))
if (!gprs_llc_queue::is_frame_expired(&tv_now2, tv_disc))
break;
/* Is the age below the high water mark */
if (!gprs_llc::is_frame_expired(&tv_now, tv_disc)) {
if (!gprs_llc_queue::is_frame_expired(&tv_now, tv_disc)) {
/* Has the previous message not been dropped? */
if (frames == 0)
break;
@ -297,7 +297,7 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
LOGP(DRLCMACDL, LOGL_NOTICE, "%s Discarding LLC PDU "
"because lifetime limit reached, "
"count=%u new_queue_size=%zu\n",
tbf_name(this), frames, m_llc.m_queue_size);
tbf_name(this), frames, llc_queue()->size());
if (frames > 0xff)
frames = 0xff;
if (octets > 0xffffff)
@ -463,7 +463,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t
break;
}
/* if FINAL chunk would fit precisely in space left */
if (chunk == space && llist_empty(&m_llc.queue) && !keep_open(fn))
if (chunk == space && llc_queue()->size() == 0 && !keep_open(fn))
{
LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
"would exactly fit into space (%d): because "
@ -794,8 +794,8 @@ void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
new_tbf->m_llc.put_frame(data, len);
bts->llc_frame_sched();
while ((msg = m_llc.dequeue()))
new_tbf->m_llc.enqueue(msg);
while ((msg = llc_queue()->dequeue()))
new_tbf->llc_queue()->enqueue(msg);
/* reset rlc states */
m_tx_counter = 0;
@ -836,7 +836,7 @@ bool gprs_rlcmac_dl_tbf::need_control_ts() const
bool gprs_rlcmac_dl_tbf::have_data() const
{
return m_llc.chunk_size() > 0 || !llist_empty(&m_llc.queue);
return m_llc.chunk_size() > 0 || llc_queue()->size() > 0;
}
int gprs_rlcmac_dl_tbf::frames_since_last_poll(unsigned fn) const