bssgp: Add VTY command to Limit the bucket size by time

Currently the bucket size is by default being computed based on the
leak rate and the expected life time of LLC frames. The latter is
either taken from 'queue lifetime' (if given) or a fixed value is
used. Using 'queue lifetime' has the drawback that it sets a 'hard'
limit, since frames will be dropped if they stay in the queue
for a longer time.

This commit adds a VTY command to specifically set the time used for
the computation of the bucket size advertised to the SGSN. It does
not affect the PCUs queue handling in any way. If the bucket time is
not set (or if the 'no' command has been used), the old behaviour
(see above) is applied.

The following VTY commands are added (config-pcu node):

- flow-control bucket-time <1-65534>  Sets the time in centisecs
- no flow-control bucket-time         Don't use this time

Ticket: OW#1432
Sponsored-by: On-Waves ehf
diff --git a/src/bts.h b/src/bts.h
index ebb7cbf..1277846 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -111,6 +111,7 @@
 struct gprs_rlcmac_bts {
 	uint8_t bsic;
 	uint8_t fc_interval;
+	uint16_t fc_bucket_time;
 	uint32_t fc_bvc_bucket_size;
 	uint32_t fc_bvc_leak_rate;
 	uint32_t fc_ms_bucket_size;
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index 3737438..bb6f7c5 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -530,12 +530,16 @@
 	uint32_t leak_rate, uint32_t fallback)
 {
 	uint32_t bucket_size = 0;
+	uint16_t bucket_time = bts->fc_bucket_time;
 
-	if (bts->force_llc_lifetime == 0xffff)
+	if (bucket_time == 0)
+		bucket_time = bts->force_llc_lifetime;
+
+	if (bucket_time == 0xffff)
 		bucket_size = FC_MAX_BUCKET_SIZE;
 
-	if (bucket_size == 0 && bts->force_llc_lifetime && leak_rate)
-		bucket_size = (uint64_t)leak_rate * bts->force_llc_lifetime / 100;
+	if (bucket_size == 0 && bucket_time && leak_rate)
+		bucket_size = (uint64_t)leak_rate * bucket_time / 100;
 
 	if (bucket_size == 0 && leak_rate)
 		bucket_size = leak_rate * FC_DEFAULT_LIFE_TIME_SECS;
diff --git a/src/pcu_vty.c b/src/pcu_vty.c
index bddcacc..a08ec36 100644
--- a/src/pcu_vty.c
+++ b/src/pcu_vty.c
@@ -222,6 +222,32 @@
 	return CMD_SUCCESS;
 }
 
+#define FC_BTIME_STR "Set target downlink maximum queueing time (only affects the advertised bucket size)\n"
+DEFUN(cfg_pcu_fc_bucket_time,
+      cfg_pcu_fc_bucket_time_cmd,
+      "flow-control bucket-time <1-65534>",
+      FC_STR FC_BTIME_STR "Time in centi-seconds\n")
+{
+	struct gprs_rlcmac_bts *bts = bts_main_data();
+
+	bts->fc_bucket_time = atoi(argv[0]);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_pcu_no_fc_bucket_time,
+      cfg_pcu_no_fc_bucket_time_cmd,
+      "no flow-control bucket-time",
+      NO_STR FC_STR FC_BTIME_STR)
+{
+	struct gprs_rlcmac_bts *bts = bts_main_data();
+
+	bts->fc_bucket_time = 0;
+
+	return CMD_SUCCESS;
+}
+
+
 DEFUN(cfg_pcu_cs,
       cfg_pcu_cs_cmd,
       "cs <1-4> [<1-4>]",
@@ -515,6 +541,8 @@
 	install_element(PCU_NODE, &cfg_pcu_alloc_cmd);
 	install_element(PCU_NODE, &cfg_pcu_two_phase_cmd);
 	install_element(PCU_NODE, &cfg_pcu_fc_interval_cmd);
+	install_element(PCU_NODE, &cfg_pcu_fc_bucket_time_cmd);
+	install_element(PCU_NODE, &cfg_pcu_no_fc_bucket_time_cmd);
 	install_element(PCU_NODE, &cfg_pcu_fc_bvc_bucket_size_cmd);
 	install_element(PCU_NODE, &cfg_pcu_no_fc_bvc_bucket_size_cmd);
 	install_element(PCU_NODE, &cfg_pcu_fc_bvc_leak_rate_cmd);