[GPSR] SGSN: Keep traffic counters for each PDP context
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index 8cfa073..0801150 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -42,6 +42,13 @@
 	GMM_CTR_RA_UPDATE,
 };
 
+enum gprs_pdp_ctx {
+	PDP_CTR_PKTS_UDATA_IN,
+	PDP_CTR_PKTS_UDATA_OUT,
+	PDP_CTR_BYTES_UDATA_IN,
+	PDP_CTR_BYTES_UDATA_OUT,
+};
+
 enum gprs_t3350_mode {
 	GMM_T3350_MODE_ATT,
 	GMM_T3350_MODE_RAU,
@@ -137,6 +144,7 @@
 	struct llist_head	g_list;	/* list_head for global list */
 	struct sgsn_mm_ctx	*mm;	/* back pointer to MM CTX */
 	struct sgsn_ggsn_ctx	*ggsn;	/* which GGSN serves this PDP */
+	struct rate_ctr_group	*ctrg;
 
 	//unsigned int		id;
 	struct pdp_t		*lib;	/* pointer to libgtp PDP ctx */
diff --git a/openbsc/src/gprs/gprs_bssgp_vty.c b/openbsc/src/gprs/gprs_bssgp_vty.c
index 9da02ab..dc1f65c 100644
--- a/openbsc/src/gprs/gprs_bssgp_vty.c
+++ b/openbsc/src/gprs/gprs_bssgp_vty.c
@@ -110,7 +110,7 @@
 
 DEFUN(show_bvc, show_bvc_cmd, "show bssgp nsei <0-65535> [stats]",
 	SHOW_STR BSSGP_STR
-	"Show all BVCSE by its NSE Identifier\n"
+	"Show all BVCs on one NSE\n"
 	"The NSEI\n" "Include Statistics\n")
 {
 	struct bssgp_bvc_ctx *bvc;
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index d104c4e..9a76cee 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -61,6 +61,20 @@
 	.ctr_desc = mmctx_ctr_description,
 };
 
+static const struct rate_ctr_desc pdpctx_ctr_description[] = {
+	{ "udata.packets.in",	"User Data  Messages ( In)" },
+	{ "udata.packets.out",	"User Data  Messages (Out)" },
+	{ "udata.bytes.in",	"User Data  Bytes    ( In)" },
+	{ "udata.bytes.out",	"User Data  Bytes    (Out)" },
+};
+
+static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
+	.group_name_prefix = "sgsn.pdpctx",
+	.group_description = "SGSN PDP Context Statistics",
+	.num_ctr = ARRAY_SIZE(pdpctx_ctr_description),
+	.ctr_desc = pdpctx_ctr_description,
+};
+
 static int ra_id_equals(const struct gprs_ra_id *id1,
 			const struct gprs_ra_id *id2)
 {
@@ -182,6 +196,7 @@
 
 	pdp->mm = mm;
 	pdp->nsapi = nsapi;
+	pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi);
 	llist_add(&pdp->list, &mm->pdp_list);
 	llist_add(&pdp->g_list, &sgsn_pdp_ctxts);
 
diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c
index a1d233a..a28790a 100644
--- a/openbsc/src/gprs/sgsn_libgtp.c
+++ b/openbsc/src/gprs/sgsn_libgtp.c
@@ -393,6 +393,7 @@
 		pinfo.drx_params = mm->drx_parms;
 		pinfo.qos[0] = 0; // FIXME
 		rc = gprs_bssgp_tx_paging(mm->nsei, 0, &pinfo);
+		rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PAGING_PS]);
 		/* FIXME: queue the packet we received from GTP */
 		break;
 	case GMM_REGISTERED_NORMAL:
@@ -404,6 +405,11 @@
 		return -1;
 	}
 
+	rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_OUT]);
+	rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_OUT], len);
+	rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_UDATA_OUT]);
+	rate_ctr_add(&mm->ctrg->ctr[GMM_CTR_BYTES_UDATA_OUT], len);
+
 	return sndcp_unitdata_req(msg, &mm->llme->lle[pdp->sapi],
 				  pdp->nsapi, mm);
 }
@@ -435,6 +441,14 @@
 		LOGP(DGPRS, LOGL_ERROR, "PDP CTX without libgtp\n");
 		return -EIO;
 	}
+
+	rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_IN]);
+	rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_IN], npdu_len);
+	rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_UDATA_IN]);
+	rate_ctr_add(&mmctx->ctrg->ctr[GMM_CTR_BYTES_UDATA_IN], npdu_len);
+
+	return gtp_data_req(pdp->ggsn->gsn, pdp->lib, npdu, npdu_len);
+
 	return gtp_data_req(pdp->ggsn->gsn, pdp->lib, npdu, npdu_len);
 }
 
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
index 3c7d064..873fa20 100644
--- a/openbsc/src/gprs/sgsn_vty.c
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -149,8 +149,7 @@
 	vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s",
 		pfx, pdp->mm->imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
 	vty_out(vty, "%s  APN: %s\n", pfx, pdp->lib->apn_use.v);
-	/* FIXME: statistics */
-	//vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
+	vty_out_rate_ctr_group(vty, " ", pdp->ctrg);
 }
 
 static void vty_dump_mmctx(struct vty *vty, const char *pfx,