diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
index 7e6d83f74882d437d5bf6db37d48437b4edf23ed..1feafd99541dad3cdd8a05b2df3058ebabf35d3e 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c
@@ -573,6 +573,79 @@ int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply)
   return 0;
 }
 
+int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id,
+      const report_config_t *report_config,
+      Protocol__FlexUeStatsReport **ue_report,
+      Protocol__FlexCellStatsReport **cell_report) {
+  /* This function fills the GTP part of the statistics. The necessary
+   * information is, for our purposes, completely maintained in the RRC layer.
+   * It would be possible to add a GTP module that handles this, though. */
+  if (report_config->nr_ue > 0) {
+    rnti_t rntis[report_config->nr_ue];
+    flexran_get_rrc_rnti_list(mod_id, rntis, report_config->nr_ue);
+    for (int i = 0; i < report_config->nr_ue; i++) {
+      const rnti_t rnti = rntis[i];
+
+      /* Check flag for creation of buffer status report */
+      if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS) {
+
+        /* get number of rabs for this UE */
+        const int num_e_rab = flexran_agent_rrc_gtp_num_e_rab(mod_id, rnti);
+        Protocol__FlexGtpStats **gtp_stats = NULL;
+        if (num_e_rab > 0) {
+          gtp_stats = calloc(num_e_rab, sizeof(Protocol__FlexGtpStats *));
+          if (!gtp_stats) goto error;
+          for (int r = 0; r < num_e_rab; ++r) {
+            gtp_stats[r] = malloc(sizeof(Protocol__FlexGtpStats));
+            if (!gtp_stats[r]) goto error;
+            protocol__flex_gtp_stats__init(gtp_stats[r]);
+            gtp_stats[r]->e_rab_id = flexran_agent_rrc_gtp_get_e_rab_id(mod_id, rnti, r);
+            gtp_stats[r]->has_e_rab_id = 1;
+            gtp_stats[r]->teid_enb = flexran_agent_rrc_gtp_get_teid_enb(mod_id, rnti, r);
+            gtp_stats[r]->has_teid_enb = 1;
+            gtp_stats[r]->addr_enb = NULL;
+            gtp_stats[r]->teid_sgw = flexran_agent_rrc_gtp_get_teid_sgw(mod_id, rnti, r);
+            gtp_stats[r]->has_teid_sgw = 1;
+            gtp_stats[r]->addr_sgw = NULL;
+          }
+        }
+        ue_report[i]->n_gtp_stats = num_e_rab;
+        ue_report[i]->gtp_stats = gtp_stats;
+        ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS;
+      }
+    }
+  }
+  return 0;
+error:
+  for (int i = 0; i < report_config->nr_ue; i++) {
+    if (!ue_report[i]->gtp_stats) continue;
+    for (int r = 0; r < ue_report[i]->n_gtp_stats; ++r) {
+      if (ue_report[i]->gtp_stats[r]) {
+        free(ue_report[i]->gtp_stats[r]);
+        ue_report[i]->gtp_stats[r] = NULL;
+      }
+    }
+    free(ue_report[i]->gtp_stats);
+    ue_report[i]->gtp_stats = NULL;
+  }
+  return -1;
+}
+
+int flexran_agent_rrc_gtp_destroy_stats_reply(Protocol__FlexStatsReply *reply) {
+  for (int i = 0; i < reply->n_ue_report; ++i) {
+    if (!reply->ue_report[i]->n_gtp_stats == 0) continue;
+
+    for (int r = 0; r < reply->ue_report[i]->n_gtp_stats; ++r) {
+      //if (reply->ue_report[i]->gtp_stats[r]->addr_enb)
+      //  free(reply->ue_report[i]->gtp_stats[r]->addr_enb);
+      //if (reply->ue_report[i]->gtp_stats[r]->addr_sgw)
+      //  free(reply->ue_report[i]->gtp_stats[r]->addr_sgw);
+      free(reply->ue_report[i]->gtp_stats[r]);
+    }
+  }
+  return 0;
+}
+
 void flexran_agent_fill_rrc_ue_config(mid_t mod_id, rnti_t rnti,
     Protocol__FlexUeConfig *ue_conf)
 {
diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
index 4b9cec861427871ec0c4973f03062564c78e081a..fdf00ff84175ae4c3e2ccede40985be679f37ef4 100644
--- a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
+++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h
@@ -60,6 +60,11 @@ void flexran_trigger_rrc_measurements (mid_t mod_id, LTE_MeasResults_t *);
 int flexran_agent_rrc_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report);
 int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply);
 
+/* Statistic reply for GTP statistics which OAI stores also in the RRC layer.
+ * This might be moved to a separate GTP module in the future */
+int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report);
+int flexran_agent_rrc_gtp_destroy_stats_reply(Protocol__FlexStatsReply *reply);
+
 /* Fill the RRC part of a ue_config message */
 void flexran_agent_fill_rrc_ue_config(mid_t mod_id, rnti_t rnti,
     Protocol__FlexUeConfig *ue_conf);
diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
index ee286981f52f89bf4fe979d1b165fb220b7efa4e..b56ad8eea1c01832ca61ce1e771c08ba4d4fe2cd 100644
--- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto
@@ -305,3 +305,15 @@ message flex_mac_sdus_dl {
     optional uint32 sdu_length = 1; 
     optional uint32 lcid = 2;
 }
+
+//
+// GTP stats
+//
+
+message flex_gtp_stats {
+    optional uint32 e_rab_id = 1;
+    optional uint32 teid_enb = 2;
+    optional string addr_enb = 3;
+    optional uint32 teid_sgw = 4;
+    optional string addr_sgw = 5;
+}
diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
index 8eb6510de3ca0c78a3a90bdec955616a29924875..7cceb04a01cf61f020ca55f2b1b7de09d9e6a5dd 100644
--- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
+++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto
@@ -50,6 +50,7 @@ message flex_ue_stats_report {
 	optional flex_rrc_measurements rrc_measurements = 10;
         optional flex_pdcp_stats pdcp_stats = 11;
         optional flex_mac_stats mac_stats = 12;
+    repeated flex_gtp_stats gtp_stats = 13;
 }
 
 //
@@ -89,6 +90,7 @@ enum flex_ue_stats_type {
      FLUST_MAC_STATS = 128;
 
      FLUST_PDCP_STATS = 1024;     
+     FLUST_GTP_STATS = 2048;
      FLUST_RRC_MEASUREMENTS = 65536;
      // To be extended with more types of stats
 
diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c
index 65663e20a8ae1fcbe1f0e01ebe7fd9331f4e2eab..e089675b622257c728ac948775b5c1d515322d22 100644
--- a/openair2/ENB_APP/flexran_agent_handler.c
+++ b/openair2/ENB_APP/flexran_agent_handler.c
@@ -511,7 +511,13 @@ int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *re
     goto error;
   }
 
-       
+  /* GTP reply split, currently performed through RRC module */
+  if (flexran_agent_get_rrc_xface(enb_id)
+      && flexran_agent_rrc_gtp_stats_reply(enb_id, report_config, ue_report, cell_report) < 0) {
+    err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD;
+    goto error;
+  }
+
   stats_reply_msg->cell_report = cell_report;
   stats_reply_msg->ue_report = ue_report;
 
diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c
index 1465f468548aeabc5b26aa7bc8c1336be6a5a310..9f08623aa8333d51cd2e1d732eeb4bfd13bb8fa2 100644
--- a/openair2/ENB_APP/flexran_agent_ran_api.c
+++ b/openair2/ENB_APP/flexran_agent_ran_api.c
@@ -2119,6 +2119,34 @@ int flexran_get_rrc_num_adj_cells(mid_t mod_id) {
   return RC.rrc[mod_id]->num_neigh_cells;
 }
 
+int flexran_agent_rrc_gtp_num_e_rab(mid_t mod_id, rnti_t rnti) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  return ue_context_p->ue_context.setup_e_rabs;
+}
+
+int flexran_agent_rrc_gtp_get_e_rab_id(mid_t mod_id, rnti_t rnti, int index) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  return ue_context_p->ue_context.e_rab[index].param.e_rab_id;
+}
+
+int flexran_agent_rrc_gtp_get_teid_enb(mid_t mod_id, rnti_t rnti, int index) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  return ue_context_p->ue_context.enb_gtp_teid[index];
+}
+
+int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index) {
+  if (!rrc_is_present(mod_id)) return 0;
+  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
+  if (!ue_context_p) return 0;
+  return ue_context_p->ue_context.e_rab[index].param.gtp_teid;
+}
+
 /**************************** SLICING ****************************/
 int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id)
 {
diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h
index 7dd6b69b6182a5b73933340c5c171cf75da87ee3..e18c55c4bfd24bff610582e8e2867c056ba44a3a 100644
--- a/openair2/ENB_APP/flexran_agent_ran_api.h
+++ b/openair2/ENB_APP/flexran_agent_ran_api.h
@@ -638,6 +638,19 @@ int flexran_set_x2_ho_net_control(mid_t mod_id, int x2_ho_net_control);
 
 /* Get number of adjacent cells via X2 interface */
 int flexran_get_rrc_num_adj_cells(mid_t mod_id);
+
+/* Get the number of E-RABs for UE */
+int flexran_agent_rrc_gtp_num_e_rab(mid_t mod_id, rnti_t rnti);
+
+/* Get the e-RAB ID for UE */
+int flexran_agent_rrc_gtp_get_e_rab_id(mid_t mod_id, rnti_t rnti, int index);
+
+/* Get the TEID at the eNB for UE */
+int flexran_agent_rrc_gtp_get_teid_enb(mid_t mod_id, rnti_t rnti, int index);
+
+/* Get the TEID at the SGW for UE */
+int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index);
+
 /************************** Slice configuration **************************/
 
 /* Get the DL slice ID for a UE */