diff options
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/gprs/gtphub.c | 349 | ||||
-rw-r--r-- | openbsc/src/gprs/gtphub_ares.c | 2 | ||||
-rw-r--r-- | openbsc/src/gprs/gtphub_vty.c | 158 |
3 files changed, 367 insertions, 142 deletions
diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index 4200822aa..60c3cc191 100644 --- a/openbsc/src/gprs/gtphub.c +++ b/openbsc/src/gprs/gtphub.c @@ -86,9 +86,11 @@ struct gtp_packet_desc { int version; uint8_t type; uint16_t seq; + uint32_t header_tei_rx; uint32_t header_tei; int rc; /* enum gtp_rc */ unsigned int plane_idx; + unsigned int side_idx; time_t timestamp; union gtpie_member *ie[GTPIE_SIZE]; }; @@ -269,7 +271,8 @@ void validate_gtp0_header(struct gtp_packet_desc *p) p->type = ntoh8(pheader->type); p->seq = ntoh16(pheader->seq); - p->header_tei = 0; /* TODO */ + p->header_tei_rx = 0; /* TODO */ + p->header_tei = p->header_tei_rx; if (p->data_len == GTP0_HEADER_SIZE) { p->rc = GTP_RC_TINY; @@ -311,7 +314,8 @@ void validate_gtp1_header(struct gtp_packet_desc *p) } p->type = ntoh8(pheader->type); - p->header_tei = ntoh32(pheader->tei); + p->header_tei_rx = ntoh32(pheader->tei); + p->header_tei = p->header_tei_rx; p->seq = ntoh16(pheader->seq); LOG(LOGL_DEBUG, "GTPv1\n" @@ -323,7 +327,7 @@ void validate_gtp1_header(struct gtp_packet_desc *p) "| next = %" PRIu8 " 0x%02" PRIx8 "\n", p->type, p->type, ntoh16(pheader->length), ntoh16(pheader->length), - p->header_tei, p->header_tei, + p->header_tei_rx, p->header_tei_rx, p->seq, p->seq, pheader->npdu, pheader->npdu, pheader->next, pheader->next); @@ -473,6 +477,7 @@ static int get_ie_apn_str(union gtpie_member *ie[], const char **apn_str) * information to *res. res->data will point at the given data buffer. On * error, p->rc is set <= 0 (see enum gtp_rc). */ static void gtp_decode(const uint8_t *data, int data_len, + unsigned int from_side_idx, unsigned int from_plane_idx, struct gtp_packet_desc *res, time_t now) @@ -480,6 +485,7 @@ static void gtp_decode(const uint8_t *data, int data_len, ZERO_STRUCT(res); res->data = (union gtp_packet*)data; res->data_len = data_len; + res->side_idx = from_side_idx; res->plane_idx = from_plane_idx; res->timestamp = now; @@ -897,12 +903,14 @@ static int gtphub_read(const struct osmo_fd *from, inline void gtphub_port_ref_count_inc(struct gtphub_peer_port *pp) { + OSMO_ASSERT(pp); OSMO_ASSERT(pp->ref_count < UINT_MAX); pp->ref_count++; } inline void gtphub_port_ref_count_dec(struct gtphub_peer_port *pp) { + OSMO_ASSERT(pp); OSMO_ASSERT(pp->ref_count > 0); pp->ref_count--; } @@ -934,6 +942,128 @@ static struct nr_mapping *gtphub_mapping_new() return nrm; } + +#define APPEND(args...) \ + l = snprintf(pos, left, args); \ + pos += l; \ + left -= l + +static const char *gtphub_tunnel_side_str(struct gtphub_tunnel *tun, + int side_idx) +{ + static char buf[256]; + char *pos = buf; + int left = sizeof(buf); + int l; + + struct gtphub_tunnel_endpoint *c, *u; + c = &tun->endpoint[side_idx][GTPH_PLANE_CTRL]; + u = &tun->endpoint[side_idx][GTPH_PLANE_USER]; + + /* print both only if they differ. */ + if (!c->peer) { + APPEND("(uninitialized)"); + } else { + APPEND("%s", gsn_addr_to_str(&c->peer->peer_addr->addr)); + } + + if (!u->peer) { + if (c->peer) { + APPEND(" / (uninitialized)"); + } + } else if ((!c->peer) + || (!gsn_addr_same(&u->peer->peer_addr->addr, + &c->peer->peer_addr->addr))) { + APPEND(" / %s", gsn_addr_to_str(&u->peer->peer_addr->addr)); + } + + APPEND(" (TEI C %x=%x / U %x=%x)", + c->tei_orig, c->tei_repl, + u->tei_orig, u->tei_repl); + return buf; +} + +const char *gtphub_tunnel_str(struct gtphub_tunnel *tun) +{ + static char buf[512]; + char *pos = buf; + int left = sizeof(buf); + int l; + + APPEND("%s", gtphub_tunnel_side_str(tun, GTPH_SIDE_SGSN)); + APPEND(" <-> %s", gtphub_tunnel_side_str(tun, GTPH_SIDE_GGSN)); + + return buf; +} + +#undef APPEND + +void gtphub_tunnel_endpoint_set_peer(struct gtphub_tunnel_endpoint *te, + struct gtphub_peer_port *pp) +{ + if (te->peer) + gtphub_port_ref_count_dec(te->peer); + te->peer = pp; + if (te->peer) + gtphub_port_ref_count_inc(te->peer); +} + +int gtphub_tunnel_complete(struct gtphub_tunnel *tun) +{ + if (!tun) + return 0; + int side_idx; + int plane_idx; + for (side_idx = 0; side_idx < GTPH_SIDE_N; side_idx++) { + for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) { + struct gtphub_tunnel_endpoint *te = + &tun->endpoint[side_idx][plane_idx]; + if (!(te->peer && te->tei_orig && te->tei_repl)) + return 0; + } + } + return 1; +} + +static void gtphub_tunnel_del_cb(struct expiring_item *expi) +{ + struct gtphub_tunnel *tun = container_of(expi, + struct gtphub_tunnel, + expiry_entry); + LOG(LOGL_DEBUG, "expired: %s\n", gtphub_tunnel_str(tun)); + + llist_del(&tun->entry); + INIT_LLIST_HEAD(&tun->entry); /* mark unused */ + + expi->del_cb = 0; /* avoid recursion loops */ + expiring_item_del(&tun->expiry_entry); /* usually already done, but make sure. */ + + int side_idx; + int plane_idx; + for (side_idx = 0; side_idx < GTPH_SIDE_N; side_idx++) { + for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) { + /* clear ref count */ + gtphub_tunnel_endpoint_set_peer( + &tun->endpoint[side_idx][plane_idx], NULL); + } + } + + talloc_free(tun); +} + +static struct gtphub_tunnel *gtphub_tunnel_new() +{ + struct gtphub_tunnel *tun; + tun = talloc_zero(osmo_gtphub_ctx, struct gtphub_tunnel); + OSMO_ASSERT(tun); + + INIT_LLIST_HEAD(&tun->entry); + expiring_item_init(&tun->expiry_entry); + + tun->expiry_entry.del_cb = gtphub_tunnel_del_cb; + return tun; +} + static const char *gtphub_peer_strb(struct gtphub_peer *peer, char *buf, int buflen) { @@ -985,6 +1115,7 @@ static const char *gtphub_port_str2(struct gtphub_peer_port *port) static void gtphub_mapping_del_cb(struct expiring_item *expi) { expi->del_cb = 0; /* avoid recursion loops */ + expiring_item_del(expi); /* usually already done, but make sure. */ struct nr_mapping *nrm = container_of(expi, struct nr_mapping, @@ -1031,22 +1162,6 @@ static struct nr_mapping *gtphub_mapping_have(struct nr_map *map, return nrm; } -static uint32_t gtphub_tei_mapping_have(struct gtphub *hub, - int plane_idx, - struct gtphub_peer_port *from, - uint32_t orig_tei, - time_t now) -{ - struct nr_mapping *nrm = gtphub_mapping_have(&hub->tei_map[plane_idx], - from, orig_tei, now); - LOG(LOGL_DEBUG, "New %s TEI: (from %s, TEI %u) <-- TEI %u\n", - gtphub_plane_idx_names[plane_idx], - gtphub_port_str(from), - (unsigned int)orig_tei, (unsigned int)nrm->repl); - - return (uint32_t)nrm->repl; -} - static void gtphub_map_seq(struct gtp_packet_desc *p, struct gtphub_peer_port *from_port, struct gtphub_peer_port *to_port) @@ -1077,6 +1192,100 @@ static struct gtphub_peer_port *gtphub_unmap_seq(struct gtp_packet_desc *p, return nrm->origin; } +static struct gtphub_tunnel *gtphub_tun_find(struct gtphub *hub, + int side_idx, + int plane_idx, + struct gtphub_peer_port *from, + uint32_t tei_orig, + uint32_t tei_repl) +{ + OSMO_ASSERT(from); + + struct gtphub_tunnel *tun; + /* TODO: optimize: don't iterate *all* tunnels. */ + llist_for_each_entry(tun, &hub->tunnels, entry) { + struct gtphub_tunnel_endpoint *te = + &tun->endpoint[side_idx][plane_idx]; + if (((!tei_orig) || (te->tei_orig == tei_orig)) + && ((!tei_repl) || (te->tei_repl == tei_repl)) + && gsn_addr_same(&te->peer->peer_addr->addr, &from->peer_addr->addr)) + return tun; + } + return NULL; +} + +static void gtphub_expire_reused_tei(struct gtphub *hub, + int side_idx, + int plane_idx, + struct gtphub_peer_port *from, + uint32_t tei_orig, + struct gtphub_tunnel *except) +{ + struct gtphub_tunnel *exists, *e2; + + llist_for_each_entry_safe(exists, e2, &hub->tunnels, entry) { + if (exists == except) + continue; + + struct gtphub_tunnel_endpoint *te = + &exists->endpoint[side_idx][plane_idx]; + if ((te->tei_orig == tei_orig) + && gsn_addr_same(&te->peer->peer_addr->addr, + &from->peer_addr->addr)) { + + /* The peer is reusing a TEI that I believe to + * be part of another tunnel. The other tunnel + * must be stale, then. */ + LOG(LOGL_NOTICE, + "Expiring tunnel due to reused TEI:" + " peer %s sent %s TEI %x," + " previously used by tunnel %s...\n", + gtphub_port_str(from), + gtphub_plane_idx_names[plane_idx], + tei_orig, + gtphub_tunnel_str(exists)); + LOG(LOGL_NOTICE, "...while establishing tunnel %s\n", + gtphub_tunnel_str(except)); + expiring_item_del(&exists->expiry_entry); + /* continue to find more matches. There shouldn't be + * any, but let's make sure. */ + } + } +} + +static void gtphub_tunnel_refresh(struct gtphub *hub, + struct gtphub_tunnel *tun, + time_t now) +{ + expiry_add(&hub->expire_slowly, + &tun->expiry_entry, + now); +} + +static struct gtphub_tunnel_endpoint *gtphub_unmap_tei(struct gtphub *hub, + struct gtp_packet_desc *p, + struct gtphub_peer_port *from) +{ + OSMO_ASSERT(from); + int other_side = other_side_idx(p->side_idx); + + struct gtphub_tunnel *tun; + llist_for_each_entry(tun, &hub->tunnels, entry) { + struct gtphub_tunnel_endpoint *te_from = + &tun->endpoint[p->side_idx][p->plane_idx]; + struct gtphub_tunnel_endpoint *te_to = + &tun->endpoint[other_side][p->plane_idx]; + if ((te_to->tei_repl == p->header_tei_rx) + && gsn_addr_same(&te_from->peer->peer_addr->addr, + &from->peer_addr->addr)) { + gtphub_tunnel_refresh(hub, tun, p->timestamp); + return te_to; + } + } + return NULL; +} + + static void gtphub_check_restart_counter(struct gtphub *hub, struct gtp_packet_desc *p, struct gtphub_peer_port *from) @@ -1106,30 +1315,28 @@ static int gtphub_unmap_header_tei(struct gtphub_peer_port **to_port_p, /* If the header's TEI is zero, no PDP context has been established * yet. If nonzero, a mapping should actually already exist for this * TEI, since it must have been announced in a PDP context creation. */ - uint32_t tei = p->header_tei; - if (!tei) + if (!p->header_tei_rx) return 0; /* to_peer has previously announced a TEI, which was stored and - * mapped in from_peer's tei_map. */ - struct nr_mapping *nrm; - nrm = nr_map_get_inv(&hub->tei_map[p->plane_idx], tei); - if (!nrm) { - LOG(LOGL_ERROR, "Received unknown TEI %" PRIu32 " from %s\n", - tei, gtphub_port_str(from_port)); + * mapped in a tunnel struct. */ + struct gtphub_tunnel_endpoint *to; + to = gtphub_unmap_tei(hub, p, from_port); + if (!to) { + LOG(LOGL_ERROR, "Received unknown TEI %" PRIx32 " from %s\n", + p->header_tei_rx, gtphub_port_str(from_port)); return -1; } - struct gtphub_peer_port *to_port = nrm->origin; - uint32_t unmapped_tei = nrm->orig; + uint32_t unmapped_tei = to->tei_orig; set_tei(p, unmapped_tei); - LOG(LOGL_DEBUG, "Unmapped TEI coming from %s: %u -> %u (to %s)\n", - gtphub_port_str(from_port), - (unsigned int)tei, (unsigned int)unmapped_tei, - gtphub_port_str2(to_port)); + LOG(LOGL_DEBUG, "Unmapped TEI coming from %s: %" PRIx32 " -> %" PRIx32 " (to %s)\n", + gtphub_port_str(from_port), p->header_tei_rx, unmapped_tei, + gtphub_port_str2(to->peer)); + + *to_port_p = to->peer; - *to_port_p = to_port; return 0; } @@ -1140,6 +1347,8 @@ static int gtphub_unmap_header_tei(struct gtphub_peer_port **to_port_p, static int gtphub_handle_pdp_ctx_ies(struct gtphub *hub, struct gtphub_bind from_bind_arr[], struct gtphub_bind to_bind_arr[], + struct gtphub_peer_port *sgsn_ctrl, + struct gtphub_peer_port *ggsn_ctrl, struct gtp_packet_desc *p) { OSMO_ASSERT(p->plane_idx == GTPH_PLANE_CTRL); @@ -1162,15 +1371,41 @@ static int gtphub_handle_pdp_ctx_ies(struct gtphub *hub, osmo_static_assert((GTPH_PLANE_CTRL == 0) && (GTPH_PLANE_USER == 1), plane_nrs_match_GSN_addr_IE_indices); + struct gtphub_tunnel *tun = NULL; + + if (p->type == GTP_CREATE_PDP_REQ) { + /* A new tunnel. */ + tun = gtphub_tunnel_new(); + llist_add(&tun->entry, &hub->tunnels); + gtphub_tunnel_refresh(hub, tun, p->timestamp); + gtphub_tunnel_endpoint_set_peer(&tun->endpoint[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL], + ggsn_ctrl); + } else if (p->type == GTP_CREATE_PDP_RSP) { + /* Find the tunnel created during request */ + OSMO_ASSERT(sgsn_ctrl); + tun = gtphub_tun_find(hub, other_side_idx(p->side_idx), + p->plane_idx, sgsn_ctrl, 0, p->header_tei_rx); + + if (!tun) { + LOG(LOGL_ERROR, "Create PDP Context Response: cannot" + " find matching request from SGSN %s, mapped TEI %x.\n", + gtphub_port_str(sgsn_ctrl), p->header_tei_rx); + return -1; + } + } + uint8_t ie_type[] = { GTPIE_TEI_C, GTPIE_TEI_DI }; int ie_mandatory = (p->type == GTP_CREATE_PDP_REQ); + unsigned int side_idx = p->side_idx; for (plane_idx = 0; plane_idx < 2; plane_idx++) { struct gsn_addr addr_from_ie; uint32_t tei_from_ie; int ie_idx; - /* Fetch GSN Address and TEI from IEs */ + /* Fetch GSN Address and TEI from IEs. As ensured by above + * static asserts, plane_idx corresponds to the GSN Address IE + * index (the first one = 0 = ctrl, second one = 1 = user). */ rc = gsn_addr_get(&addr_from_ie, p, plane_idx); if (rc) { LOG(LOGL_ERROR, "Cannot read %s GSN Address IE\n", @@ -1203,14 +1438,20 @@ static int gtphub_handle_pdp_ctx_ies(struct gtphub *hub, &addr_from_ie, gtphub_plane_idx_default_port[plane_idx]); + gtphub_tunnel_endpoint_set_peer(&tun->endpoint[side_idx][plane_idx], + peer_from_ie); + if (tei_from_ie) { /* Create TEI mapping and replace in GTP packet IE */ - uint32_t mapped_tei = - gtphub_tei_mapping_have(hub, plane_idx, - peer_from_ie, - tei_from_ie, - p->timestamp); + uint32_t mapped_tei = nr_pool_next(&hub->tei_pool[plane_idx]); + + tun->endpoint[side_idx][plane_idx].tei_orig = tei_from_ie; + tun->endpoint[side_idx][plane_idx].tei_repl = mapped_tei; p->ie[ie_idx]->tv4.v = hton32(mapped_tei); + + gtphub_expire_reused_tei(hub, side_idx, plane_idx, + peer_from_ie, tei_from_ie, + tun); } /* Replace the GSN address to reflect gtphub. */ @@ -1223,6 +1464,14 @@ static int gtphub_handle_pdp_ctx_ies(struct gtphub *hub, } } + if (p->type == GTP_CREATE_PDP_REQ) { + LOG(LOGL_DEBUG, "New tunnel, first half: %s\n", + gtphub_tunnel_str(tun)); + } else if (p->type == GTP_CREATE_PDP_REQ) { + LOG(LOGL_DEBUG, "New tunnel: %s\n", + gtphub_tunnel_str(tun)); + } + return 0; } @@ -1319,7 +1568,7 @@ static int gtphub_unmap(struct gtphub *hub, gtphub_peer_str(from_peer), (int)p->seq, gtphub_port_str(from_seq), - (unsigned int)p->header_tei, + (unsigned int)p->header_tei_rx, gtphub_port_str2(from_tei) ); } @@ -1341,9 +1590,6 @@ static int gtphub_unmap(struct gtphub *hub, return 0; } - LOG(LOGL_DEBUG, "from seq %p; from tei %p; unmapped => %p\n", - from_seq, from_tei, unmapped); - if (unmapped_from_seq) *unmapped_from_seq = from_seq; if (unmapped_from_tei) @@ -1420,7 +1666,7 @@ int gtphub_from_ggsns_handle_buf(struct gtphub *hub, osmo_sockaddr_to_str(from_addr)); static struct gtp_packet_desc p; - gtp_decode(buf, received, plane_idx, &p, now); + gtp_decode(buf, received, GTPH_SIDE_GGSN, plane_idx, &p, now); if (p.rc <= 0) return -1; @@ -1502,7 +1748,7 @@ int gtphub_from_ggsns_handle_buf(struct gtphub *hub, * are other addresses in the GTP message to set up apart from * the sender. */ if (gtphub_handle_pdp_ctx_ies(hub, from_bind_arr, to_bind_arr, - &p) + sgsn, ggsn, &p) != 0) return -1; } @@ -1585,7 +1831,7 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub, osmo_sockaddr_to_str(from_addr)); static struct gtp_packet_desc p; - gtp_decode(buf, received, plane_idx, &p, now); + gtp_decode(buf, received, GTPH_SIDE_SGSN, plane_idx, &p, now); if (p.rc <= 0) return -1; @@ -1684,11 +1930,11 @@ int gtphub_from_sgsns_handle_buf(struct gtphub *hub, } if (plane_idx == GTPH_PLANE_CTRL) { - /* This may be a Create PDP Context requst. If it is, there are + /* This may be a Create PDP Context request. If it is, there are * other addresses in the GTP message to set up apart from the * sender. */ if (gtphub_handle_pdp_ctx_ies(hub, from_bind_arr, to_bind_arr, - &p) + sgsn, ggsn, &p) != 0) return -1; } @@ -1848,15 +2094,14 @@ void gtphub_init(struct gtphub *hub) { gtphub_zero(hub); + INIT_LLIST_HEAD(&hub->tunnels); + expiry_init(&hub->expire_quickly, GTPH_EXPIRE_QUICKLY_SECS); expiry_init(&hub->expire_slowly, GTPH_EXPIRE_SLOWLY_MINUTES * 60); int plane_idx; for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) { nr_pool_init(&hub->tei_pool[plane_idx], 1, 0xffffffff); - nr_map_init(&hub->tei_map[plane_idx], - &hub->tei_pool[plane_idx], - &hub->expire_slowly); gtphub_bind_init(&hub->to_ggsns[plane_idx]); gtphub_bind_init(&hub->to_sgsns[plane_idx]); diff --git a/openbsc/src/gprs/gtphub_ares.c b/openbsc/src/gprs/gtphub_ares.c index 7688b4788..947f2ddd5 100644 --- a/openbsc/src/gprs/gtphub_ares.c +++ b/openbsc/src/gprs/gtphub_ares.c @@ -214,7 +214,7 @@ struct gtphub_peer_port *gtphub_resolve_ggsn_addr(struct gtphub *hub, llist_add(&lookup->entry, &hub->ggsn_lookups); lookup->expiry_entry.del_cb = ggsn_lookup_del_cb; - expiry_add(&hub->expire_seq_maps, &lookup->expiry_entry, gtphub_now()); + expiry_add(&hub->expire_quickly, &lookup->expiry_entry, gtphub_now()); start_ares_query(lookup); diff --git a/openbsc/src/gprs/gtphub_vty.c b/openbsc/src/gprs/gtphub_vty.c index 602508854..f99f81803 100644 --- a/openbsc/src/gprs/gtphub_vty.c +++ b/openbsc/src/gprs/gtphub_vty.c @@ -280,132 +280,112 @@ static void show_peers_summary(struct vty *vty) } */ -static void show_tei_maps_summary(struct vty *vty) +static void show_tunnels_summary(struct vty *vty) { time_t now = gtphub_now(); - unsigned long long int count_all = 0; /* ...just joking. */ - const int w = 36; - int max_expiry = g_hub->expire_tei_maps.expiry_in_seconds; + int max_expiry = g_hub->expire_slowly.expiry_in_seconds; float seconds_per_step = ((float)max_expiry) / w; /* Print TEI mapping expiry in an ASCII histogram, like: TEI map summary Legend: '_'=0 '.'<=1% ':'<=2% '|'<=10% '#'>10% (10.0 m/step) - CTRL: 30 mappings, valid for 360m[#__:.____|___.____:__.______________]1m - USER: 30 mappings, valid for 360m[#__:.____|___.____:__.______________]1m + CTRL: 30 mappings, valid for 360m[# :. | . : . ]1m + USER: 30 mappings, valid for 360m[# :. | . : . ]1m 4 TEI mappings in total, last expiry in 359.4 min */ vty_out(vty, - "TEI map summary%s" - " Legend: '_'=0 '.'<=1%% ':'<=2%% '|'<=10%% '#'>10%% (%.1f m/step)%s", + "Tunnels summary%s" + " Legend: ' '=0 '.'<=1%% ':'<=2%% '|'<=10%% '#'>10%% (%.1f m/step)%s", VTY_NEWLINE, seconds_per_step / 60., VTY_NEWLINE); int last_expiry = 0; - int plane_idx; - for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) { - unsigned int count = 0; + unsigned int count = 0; - int histogram[w]; - memset(histogram, 0, sizeof(histogram)); + int histogram[w]; + memset(histogram, 0, sizeof(histogram)); - struct nr_mapping *m; - llist_for_each_entry(m, &g_hub->tei_map[plane_idx].mappings, entry) { - count ++; - int expiry = m->expiry_entry.expiry - now; - last_expiry = (last_expiry > expiry) ? last_expiry : expiry; + struct gtphub_tunnel *t; + llist_for_each_entry(t, &g_hub->tunnels, entry) { + count ++; + int expiry = t->expiry_entry.expiry - now; + last_expiry = (last_expiry > expiry) ? last_expiry : expiry; - int hi = ((float)expiry) / seconds_per_step; - if (hi < 0) - hi = 0; - if (hi > (w - 1)) - hi = w - 1; - histogram[hi] ++; - } + int hi = ((float)expiry) / seconds_per_step; + if (hi < 0) + hi = 0; + if (hi > (w - 1)) + hi = w - 1; + histogram[hi] ++; + } - vty_out(vty, - " %4s: %u mappings, valid for %dm[", - gtphub_plane_idx_names[plane_idx], - count, max_expiry / 60); - - int i; - for (i = w - 1; i >= 0; i--) { - char c; - int val = histogram[i]; - int percent = 100. * val / count; - if (!val) - c = '_'; - else if (percent <= 1) - c = '.'; - else if (percent <= 2) - c = ':'; - else if (percent <= 10) - c = '|'; - else c = '#'; - vty_out(vty, "%c", c); - } - vty_out(vty, "]1m%s", VTY_NEWLINE); - - count_all += count; + vty_out(vty, + " %u tunnels, valid for %dm[", + count, max_expiry / 60); + + int i; + for (i = w - 1; i >= 0; i--) { + char c; + int val = histogram[i]; + int percent = 100. * val / count; + if (!val) + c = ' '; + else if (percent <= 1) + c = '.'; + else if (percent <= 2) + c = ':'; + else if (percent <= 10) + c = '|'; + else c = '#'; + vty_out(vty, "%c", c); } - vty_out(vty, " %llu TEI mappings in total, last expiry in %.1f min%s", - count_all, + vty_out(vty, "]1m%s", VTY_NEWLINE); + + vty_out(vty, " last expiry in %.1f min%s", ((float)last_expiry) / 60., VTY_NEWLINE); } -static void show_tei_maps_all(struct vty *vty) +static void show_tunnels_all(struct vty *vty) { time_t now = gtphub_now(); - unsigned long long int count_all = 0; /* ...just joking. */ + vty_out(vty, "All tunnels:%s" + "Legend: SGSN <-> GGSN, with each:%s" + " <IP-Ctrl>[/<IP-User>] (<TEI-Ctrl>=<mapped>/<TEI-User>=<mapped>)%s", + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - vty_out(vty, "All TEI mappings:%s", VTY_NEWLINE); - int plane_idx; - for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) { + unsigned int count = 0; + unsigned int incomplete = 0; + struct gtphub_tunnel *t; + llist_for_each_entry(t, &g_hub->tunnels, entry) { vty_out(vty, - "- %s Plane:%s" - " (timeout) replaced-TEI <--> original-TEI from-peer%s", - gtphub_plane_idx_names[plane_idx], - VTY_NEWLINE, VTY_NEWLINE); - - unsigned int count = 0; - struct nr_mapping *m; - llist_for_each_entry(m, &g_hub->tei_map[plane_idx].mappings, entry) { - struct gtphub_peer_port *pp = m->origin; - vty_out(vty, - " (%4dm) %8x <--> %8x %s", - -(int)((m->expiry_entry.expiry - now) / 60), - (uint32_t)m->repl, - (uint32_t)m->orig, - gsn_addr_to_str(&pp->peer_addr->addr)); - if (pp->port != gtphub_plane_idx_default_port[plane_idx]) - vty_out(vty, " port %d", (int)pp->port); - vty_out(vty, VTY_NEWLINE); - count ++; - } - vty_out(vty, " (%u %s TEI mappings)%s", count, - gtphub_plane_idx_names[plane_idx], VTY_NEWLINE); - count_all += count; + "(%4dm) %s%s", + -(int)((t->expiry_entry.expiry - now) / 60), + gtphub_tunnel_str(t), + VTY_NEWLINE); + count ++; + if (!gtphub_tunnel_complete(t)) + incomplete ++; } - vty_out(vty, "- %llu TEI mappings in total%s", count_all, VTY_NEWLINE); + vty_out(vty, "Total: %u tunnels%s", count, VTY_NEWLINE); } -DEFUN(show_gtphub_tei_summary, show_gtphub_tei_summary_cmd, "show gtphub tei summary", - SHOW_STR "TEI mappings summary") +DEFUN(show_gtphub_tunnels_summary, show_gtphub_tunnels_summary_cmd, "show gtphub tunnels summary", + SHOW_STR "Summary of all tunnels") { - show_tei_maps_summary(vty); + show_tunnels_summary(vty); return CMD_SUCCESS; } -DEFUN(show_gtphub_tei_dump, show_gtphub_tei_dump_cmd, "show gtphub tei dump", - SHOW_STR "Dump all current TEI mappings") +DEFUN(show_gtphub_tunnels_list, show_gtphub_tunnels_list_cmd, "show gtphub tunnels list", + SHOW_STR "List all tunnels") { - show_tei_maps_all(vty); + show_tunnels_all(vty); return CMD_SUCCESS; } @@ -413,7 +393,7 @@ DEFUN(show_gtphub, show_gtphub_cmd, "show gtphub all", SHOW_STR "Display information about the GTP hub") { show_bind_stats_all(vty); - show_tei_maps_summary(vty); + show_tunnels_summary(vty); return CMD_SUCCESS; } @@ -424,8 +404,8 @@ int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg) g_cfg = global_cfg; install_element_ve(&show_gtphub_cmd); - install_element_ve(&show_gtphub_tei_summary_cmd); - install_element_ve(&show_gtphub_tei_dump_cmd); + install_element_ve(&show_gtphub_tunnels_summary_cmd); + install_element_ve(&show_gtphub_tunnels_list_cmd); install_element(CONFIG_NODE, &cfg_gtphub_cmd); install_node(>phub_node, config_write_gtphub); |