Harald Welte has submitted this change and it was merged. ( 
https://gerrit.osmocom.org/c/osmo-msc/+/14069 )

Change subject: libmsc/msc_vty.c: refactor 'show subscr / conn / trans' commands
......................................................................

libmsc/msc_vty.c: refactor 'show subscr / conn / trans' commands

The current way of printing subscriber, connection, and transaction
info is ugly (sorry) and has several problems:

  - the terminal width should be large enough to fit quite long lines,
    otherwise the output is unreadable and looks misaligned;

  - some fields (such as subscriber name) can be larger than it's
    expected, so either they're getting truncated, or again, the
    output is misaligned and unreadable;

  - adding new info fields would require one to think about the
    alignment and would make the output even more cumbersome.

Here is an example output of 'show connection' command:

  _Subscriber_______________________________________ _LAC_ 
_RAN___________________ _MSC-A_state_________ _MSC-A_use_
  IMSI-123456789012345:MSISDN-12345:TMSI-0x12345678      1 
GERAN-A-4294967295:A5-3 WAIT_CLASSMARK_UPDATE 2=cm_service,trans_cc
  IMSI-123456789012356:MSISDN-234567:TMSI-0x123ABC78 65535     
UTRAN-Iu-4294967295         COMMUNICATING 2=cm_service,trans_sms
  IMSI-262073993158656:MSISDN-123456:TMSI-0x493026BA     1               
GERAN-A-1 MSC_A_ST_COMMUNICATING 1=1 (silent_call)

Another 'show subscriber' command mixes the information about
subscriber, its connections and transactions without any alignment,
what also decreases the readability.

This change introduces a hierarchical approach, based on the old
'field per line' formatting. First of all, the VTY commands were
extended with optional flags:

  show connection [trans]
  show subscriber cache [(conn|trans|conn+trans)]
  show subscriber TYPE ID [(conn|trans|conn+trans)]

so it can be decided, whether to print child connections and/or
transaction, or not. For example:

  show connection trans

would print all connections and their child transactions with
hierarchical alignment:

  Connection #00:
    Subscriber: IMSI-262073993158656:MSISDN-123456:TMSI-0x76760B75
    RAN connection: GERAN-A-1
    RAN connection state: MSC_A_ST_COMMUNICATING
    LAC / cell ID: 1 / 0
    Use count total: 1
    Use count: 1 (silent_call)
    Transaction #00:
      Unique (global) identifier: 0x00000000
      GSM 04.07 identifier (MT): 0
      Type: silent-call

another example is:

  show subscriber cache conn+trans

which would print all known subscribers,
their active connections and transactions:

  Subscriber #00:
    MSISDN: 123456
    LAC / cell ID: 1 / 0
    RAN type: GERAN-A
    IMSI: 262073993158656
    TMSI: 76760B75
    ...
    Connection:
      RAN connection: GERAN-A-1
      RAN connection state: MSC_A_ST_COMMUNICATING
      ...
      Transaction #00:
        Unique (global) identifier: 0x00000000
        GSM 04.07 identifier (MT): 0
        Type: silent-call
      Transaction #01:
        Unique (global) identifier: 0x00000001
        GSM 04.07 identifier (MO): 0
        Type: SMS
      Transaction #02:
        Unique (global) identifier: 0x00000002
        GSM 04.07 identifier (MT): 0
        Type: SMS

Please note that we don't print redundant info in child nodes
(i.e. connection and transaction info), such as subscriber name
in connection info, nor connection name in transaction info - it
is clear from the hierarchical formatting.

Change-Id: I5e58b56204c3f3d019e8d4c3c96cefdbb4af4d47
---
M src/libmsc/msc_vty.c
1 file changed, 291 insertions(+), 170 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  osmith: Looks good to me, but someone else must approve
  Jenkins Builder: Verified



diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c
index 0c07bc2..5b0cfc4 100644
--- a/src/libmsc/msc_vty.c
+++ b/src/libmsc/msc_vty.c
@@ -661,58 +661,6 @@
        return CMD_SUCCESS;
 }

-/*
-_Subscriber_______________________________________ _LAC_ 
_RAN___________________ _MSC-A_state_________ _MSC-A_use_
-IMSI-123456789012345:MSISDN-12345:TMSI-0x12345678  1     
GERAN-A-4294967295:A5-3 WAIT_CLASSMARK_UPDATE 2=cm_service,trans_cc
-IMSI-123456789012356:MSISDN-234567:TMSI-0x123ABC78 65535 UTRAN-Iu-4294967295   
  COMMUNICATING         2=cm_service,trans_sms
-IMSI-123456789012367:MSISDN-98712345890:TMSI-0xF.. -     EUTRAN-SGs            
  RELEASING             0=none
-IMSI-123456789012378:HONR-12345432101              2     MSC-901-700-423:9876  
  REMOTE_MSC_A          1=inter_msc
-*/
-static void vty_dump_one_conn(struct vty *vty, const struct msub *msub, int 
*idx)
-{
-       struct msc_a *msc_a = msub_msc_a(msub);
-       struct vlr_subscr *vsub = msub_vsub(msub);
-       char buf[128];
-
-       if (!(*idx))
-               vty_out(vty,
-                       "_Subscriber_______________________________________ 
_LAC_ _RAN___________________"
-                       " _MSC-A_state_________ _MSC-A_use_%s",
-                       VTY_NEWLINE);
-       (*idx)++;
-
-       vty_out(vty, "%50s %5u %23s %20s %d=%s%s",
-               vlr_subscr_short_name(msub_vsub(msub), 50),
-               vsub ? vsub->cgi.lai.lac : 0,
-               msub_ran_conn_name(msub),
-               osmo_fsm_inst_state_name(msc_a->c.fi),
-               osmo_use_count_total(&msc_a->use_count),
-               osmo_use_count_name_buf(buf, sizeof(buf), &msc_a->use_count),
-               VTY_NEWLINE);
-}
-
-DEFUN(show_msc_conn, show_msc_conn_cmd,
-       "show connection", SHOW_STR "Subscriber Connections\n")
-{
-       struct msub *msub;
-       int idx = 0;
-       llist_for_each_entry(msub, &msub_list, entry) {
-               vty_dump_one_conn(vty, msub, &idx);
-       }
-       return CMD_SUCCESS;
-}
-
-static void vty_trans_hdr(struct vty *vty)
-{
-       if (llist_empty(&gsmnet->trans_list))
-               return;
-
-       vty_out(vty,
-               "_Subscriber_______________________________________ 
_RAN___________________"
-               " _P__ TI CallRef_ _state_%s",
-               VTY_NEWLINE);
-}
-
 static const char *get_trans_proto_str(const struct gsm_trans *trans)
 {
        static char buf[256];
@@ -725,146 +673,311 @@
                         trans->cc.T308_second);
                break;
        case TRANS_SMS:
-               snprintf(buf, sizeof(buf), "%s %s",
+               snprintf(buf, sizeof(buf), "CP:%s RP:%s",
                        gsm411_cp_state_name(trans->sms.smc_inst.cp_state),
                        gsm411_rp_state_name(trans->sms.smr_inst.rp_state));
                break;
        default:
-               buf[0] = '\0';
-               break;
+               return NULL;
        }

        return buf;
 }

-static void vty_dump_one_trans(struct vty *vty, const struct gsm_trans *trans)
+/* Prefix a given format string with a given amount of spaces */
+#define MSC_VTY_DUMP(vty, offset, fmt, args...) \
+       vty_out(vty, "%*s" fmt, offset, "", ##args)
+
+#define MSC_VTY_DUMP_FLAG(vty, offset, name, flag) \
+       MSC_VTY_DUMP(vty, offset + 2, "%s: %*s%s%s", \
+                    name, 30 - (int)strlen(name), "", \
+                    flag ? "true" : "false", \
+                    VTY_NEWLINE)
+
+enum msc_vty_dump_flags {
+       MSC_VTY_DUMP_F_SUBSCR           = (1 << 0),
+       MSC_VTY_DUMP_F_CONNECTION       = (1 << 1),
+       MSC_VTY_DUMP_F_TRANSACTION      = (1 << 2),
+};
+
+static void vty_dump_one_trans(struct vty *vty, const struct gsm_trans *trans,
+                              int offset, uint8_t dump_flags)
 {
-       vty_out(vty, "%50s %23s %4s %02u %08x %s%s",
-               vlr_subscr_short_name(msc_a_vsub(trans->msc_a), 50),
-               msub_ran_conn_name(trans->msc_a->c.msub),
-               trans_type_name(trans->type),
-               trans->transaction_id,
-               trans->callref,
-               get_trans_proto_str(trans),
-               VTY_NEWLINE);
+       const char *proto_str;
+
+       if (dump_flags & MSC_VTY_DUMP_F_SUBSCR) {
+               MSC_VTY_DUMP(vty, offset, "Subscriber: %s%s",
+                            vlr_subscr_name(msc_a_vsub(trans->msc_a)),
+                            VTY_NEWLINE);
+       }
+
+       if (dump_flags & MSC_VTY_DUMP_F_CONNECTION) {
+               MSC_VTY_DUMP(vty, offset, "RAN connection: %s%s",
+                            trans->msc_a ? 
msub_ran_conn_name(trans->msc_a->c.msub)
+                                         : "(not established)",
+                            VTY_NEWLINE);
+       }
+
+       MSC_VTY_DUMP(vty, offset, "Unique (global) identifier: 0x%08x%s",
+                    trans->callref, VTY_NEWLINE);
+       MSC_VTY_DUMP(vty, offset, "GSM 04.07 identifier (%s): %u%s",
+                    (trans->transaction_id & 0x08) ? "MO" : "MT",
+                    trans->transaction_id,
+                    VTY_NEWLINE);
+
+       MSC_VTY_DUMP(vty, offset, "Type: %s%s",
+                    trans_type_name(trans->type),
+                    VTY_NEWLINE);
+
+       if ((proto_str = get_trans_proto_str(trans))) {
+               MSC_VTY_DUMP(vty, offset, "Protocol specific: %s%s",
+                            proto_str, VTY_NEWLINE);
+       }
+}
+
+static void vty_dump_one_conn(struct vty *vty, const struct msub *msub,
+                             int offset, uint8_t dump_flags)
+{
+       struct vlr_subscr *vsub = msub_vsub(msub);
+       struct msc_a *msc_a = msub_msc_a(msub);
+       char buf[128];
+
+       if (dump_flags & MSC_VTY_DUMP_F_SUBSCR) {
+               dump_flags = dump_flags &~ MSC_VTY_DUMP_F_SUBSCR;
+               MSC_VTY_DUMP(vty, offset, "Subscriber: %s%s",
+                            vlr_subscr_name(vsub),
+                            VTY_NEWLINE);
+       }
+
+       MSC_VTY_DUMP(vty, offset, "RAN connection: %s%s",
+                    msub_ran_conn_name(msub),
+                    VTY_NEWLINE);
+       MSC_VTY_DUMP(vty, offset, "RAN connection state: %s%s",
+                    osmo_fsm_inst_state_name(msc_a->c.fi),
+                    VTY_NEWLINE);
+
+       if (vsub) {
+               MSC_VTY_DUMP(vty, offset, "LAC / cell ID: %u / %u%s",
+                            vsub->cgi.lai.lac, vsub->cgi.cell_identity,
+                            VTY_NEWLINE);
+       }
+
+       MSC_VTY_DUMP(vty, offset, "Use count total: %d%s",
+                    osmo_use_count_total(&msc_a->use_count),
+                    VTY_NEWLINE);
+       MSC_VTY_DUMP(vty, offset, "Use count: %s%s",
+                    osmo_use_count_name_buf(buf, sizeof(buf), 
&msc_a->use_count),
+                    VTY_NEWLINE);
+
+       /* Transactions of this connection */
+       if (dump_flags & MSC_VTY_DUMP_F_TRANSACTION) {
+               struct gsm_trans *trans;
+               unsigned int i = 0;
+
+               /* Both subscriber and connection info is already printed */
+               dump_flags = dump_flags &~ MSC_VTY_DUMP_F_CONNECTION;
+               dump_flags = dump_flags &~ MSC_VTY_DUMP_F_SUBSCR;
+
+               llist_for_each_entry(trans, &gsmnet->trans_list, entry) {
+                       if (trans->msc_a != msc_a)
+                               continue;
+                       MSC_VTY_DUMP(vty, offset, "Transaction #%02u: %s",
+                                    i++, VTY_NEWLINE);
+                       vty_dump_one_trans(vty, trans, offset + 2, dump_flags);
+               }
+       }
+}
+
+static void vty_dump_one_subscr(struct vty *vty, struct vlr_subscr *vsub,
+                               int offset, uint8_t dump_flags)
+{
+       char buf[128];
+
+       if (strlen(vsub->name)) {
+               MSC_VTY_DUMP(vty, offset, "Name: '%s'%s",
+                            vsub->name, VTY_NEWLINE);
+       }
+       if (strlen(vsub->msisdn)) {
+               MSC_VTY_DUMP(vty, offset, "MSISDN: %s%s",
+                            vsub->msisdn, VTY_NEWLINE);
+       }
+
+       MSC_VTY_DUMP(vty, offset, "LAC / cell ID: %u / %u%s",
+                    vsub->cgi.lai.lac, vsub->cgi.cell_identity,
+                    VTY_NEWLINE);
+       MSC_VTY_DUMP(vty, offset, "RAN type: %s%s",
+                    osmo_rat_type_name(vsub->cs.attached_via_ran),
+                    VTY_NEWLINE);
+
+       MSC_VTY_DUMP(vty, offset, "IMSI: %s%s",
+                    vsub->imsi, VTY_NEWLINE);
+       if (vsub->tmsi != GSM_RESERVED_TMSI) {
+               MSC_VTY_DUMP(vty, offset, "TMSI: %08X%s",
+                            vsub->tmsi, VTY_NEWLINE);
+       }
+       if (vsub->tmsi_new != GSM_RESERVED_TMSI) {
+               MSC_VTY_DUMP(vty, offset, "New TMSI: %08X%s",
+                            vsub->tmsi_new, VTY_NEWLINE);
+       }
+       if (vsub->imei[0] != '\0') {
+               MSC_VTY_DUMP(vty, offset, "IMEI: %s%s",
+                            vsub->imei, VTY_NEWLINE);
+       }
+       if (vsub->imeisv[0] != '\0') {
+               MSC_VTY_DUMP(vty, offset, "IMEISV: %s%s",
+                            vsub->imeisv, VTY_NEWLINE);
+       }
+
+       MSC_VTY_DUMP(vty, offset, "Flags: %s", VTY_NEWLINE);
+       MSC_VTY_DUMP_FLAG(vty, offset, "IMSI detached",
+                         vsub->imsi_detached_flag);
+       MSC_VTY_DUMP_FLAG(vty, offset, "Conf. by radio contact",
+                         vsub->conf_by_radio_contact_ind);
+       MSC_VTY_DUMP_FLAG(vty, offset, "Subscr. data conf. by HLR",
+                         vsub->sub_dataconf_by_hlr_ind);
+       MSC_VTY_DUMP_FLAG(vty, offset, "Location conf. in HLR",
+                         vsub->loc_conf_in_hlr_ind);
+       MSC_VTY_DUMP_FLAG(vty, offset, "Subscriber dormant",
+                         vsub->dormant_ind);
+       MSC_VTY_DUMP_FLAG(vty, offset, "Received cancel location",
+                         vsub->cancel_loc_rx);
+       MSC_VTY_DUMP_FLAG(vty, offset, "MS not reachable",
+                         vsub->ms_not_reachable_flag);
+       MSC_VTY_DUMP_FLAG(vty, offset, "LA allowed",
+                         vsub->la_allowed);
+
+       if (vsub->last_tuple) {
+               struct vlr_auth_tuple *t = vsub->last_tuple;
+               MSC_VTY_DUMP(vty, offset, "A3A8 last tuple (used %d times): %s",
+                            t->use_count, VTY_NEWLINE);
+               MSC_VTY_DUMP(vty, offset + 2, "seq # : %d%s",
+                            t->key_seq, VTY_NEWLINE);
+               MSC_VTY_DUMP(vty, offset + 2, "RAND  : %s%s",
+                            osmo_hexdump(t->vec.rand, sizeof(t->vec.rand)),
+                            VTY_NEWLINE);
+               MSC_VTY_DUMP(vty, offset + 2, "SRES  : %s%s",
+                            osmo_hexdump(t->vec.sres, sizeof(t->vec.sres)),
+                            VTY_NEWLINE);
+               MSC_VTY_DUMP(vty, offset + 2, "Kc    : %s%s",
+                            osmo_hexdump(t->vec.kc, sizeof(t->vec.kc)),
+                            VTY_NEWLINE);
+       }
+
+       MSC_VTY_DUMP(vty, offset, "Paging: %s paging for %d requests%s",
+                    vsub->cs.is_paging ? "is" : "not",
+                    llist_count(&vsub->cs.requests),
+                    VTY_NEWLINE);
+
+       /* SGs related */
+       MSC_VTY_DUMP(vty, offset, "SGs-state: %s%s",
+                    osmo_fsm_inst_state_name(vsub->sgs_fsm),
+                    VTY_NEWLINE);
+       MSC_VTY_DUMP(vty, offset, "SGs-MME: %s%s",
+                    strlen(vsub->sgs.mme_name) ?
+                            vsub->sgs.mme_name : "(none)",
+                    VTY_NEWLINE);
+
+       MSC_VTY_DUMP(vty, offset, "Use count total: %d%s",
+                    osmo_use_count_total(&vsub->use_count),
+                    VTY_NEWLINE);
+       MSC_VTY_DUMP(vty, offset, "Use count: %s%s",
+                    osmo_use_count_name_buf(buf, sizeof(buf), 
&vsub->use_count),
+                    VTY_NEWLINE);
+
+       /* Connection(s) and/or transactions of this subscriber */
+       if (dump_flags & MSC_VTY_DUMP_F_CONNECTION) {
+               struct msub *msub = msub_for_vsub(vsub);
+               if (!msub)
+                       return;
+
+               /* Subscriber info is already printed */
+               dump_flags = dump_flags &~ MSC_VTY_DUMP_F_SUBSCR;
+
+               MSC_VTY_DUMP(vty, offset, "Connection: %s", VTY_NEWLINE);
+               vty_dump_one_conn(vty, msub, offset + 2, dump_flags);
+       } else if (dump_flags & MSC_VTY_DUMP_F_TRANSACTION) {
+               struct gsm_trans *trans;
+               unsigned int i = 0;
+
+               /* Subscriber info is already printed */
+               dump_flags = dump_flags &~ MSC_VTY_DUMP_F_SUBSCR;
+               /* Do not print connection info, but mention it */
+               dump_flags |= MSC_VTY_DUMP_F_CONNECTION;
+
+               llist_for_each_entry(trans, &gsmnet->trans_list, entry) {
+                       if (trans->vsub != vsub)
+                               continue;
+                       MSC_VTY_DUMP(vty, offset, "Transaction #%02u: %s",
+                                    i++, VTY_NEWLINE);
+                       vty_dump_one_trans(vty, trans, offset + 2, dump_flags);
+               }
+       }
 }

 DEFUN(show_msc_transaction, show_msc_transaction_cmd,
-       "show transaction", SHOW_STR "Transactions\n")
+       "show transaction",
+       SHOW_STR "Transactions\n")
 {
        struct gsm_trans *trans;
+       uint8_t flags = 0x00;
+       unsigned int i = 0;
 
-       vty_trans_hdr(vty);
-       llist_for_each_entry(trans, &gsmnet->trans_list, entry)
-               vty_dump_one_trans(vty, trans);
+       flags |= MSC_VTY_DUMP_F_CONNECTION;
+       flags |= MSC_VTY_DUMP_F_SUBSCR;
+
+       llist_for_each_entry(trans, &gsmnet->trans_list, entry) {
+               vty_out(vty, "  Transaction #%02u: %s", i++, VTY_NEWLINE);
+               vty_dump_one_trans(vty, trans, 4, flags);
+       }

        return CMD_SUCCESS;
 }

-static void subscr_dump_full_vty(struct vty *vty, struct vlr_subscr *vsub)
+DEFUN(show_msc_conn, show_msc_conn_cmd,
+       "show connection [trans]",
+       SHOW_STR "Subscriber Connections\n"
+       "Show child transactions of each connection\n")
 {
-       struct gsm_trans *trans;
-       char buf[128];
+       uint8_t flags = 0x00;
+       unsigned int i = 0;
+       struct msub *msub;

-       if (strlen(vsub->name))
-               vty_out(vty, "    Name: '%s'%s", vsub->name, VTY_NEWLINE);
-       if (strlen(vsub->msisdn))
-               vty_out(vty, "    Extension: %s%s", vsub->msisdn,
-                       VTY_NEWLINE);
-       vty_out(vty, "    LAC: %d/0x%x%s",
-               vsub->cgi.lai.lac, vsub->cgi.lai.lac, VTY_NEWLINE);
-       vty_out(vty, "    RAN: %s%s",
-               osmo_rat_type_name(vsub->cs.attached_via_ran), VTY_NEWLINE);
-       vty_out(vty, "    IMSI: %s%s", vsub->imsi, VTY_NEWLINE);
-       if (vsub->tmsi != GSM_RESERVED_TMSI)
-               vty_out(vty, "    TMSI: %08X%s", vsub->tmsi,
-                       VTY_NEWLINE);
-       if (vsub->tmsi_new != GSM_RESERVED_TMSI)
-               vty_out(vty, "    new TMSI: %08X%s", vsub->tmsi_new,
-                       VTY_NEWLINE);
-       if (vsub->imei[0] != '\0')
-               vty_out(vty, "    IMEI: %s%s", vsub->imei, VTY_NEWLINE);
-       if (vsub->imeisv[0] != '\0')
-               vty_out(vty, "    IMEISV: %s%s", vsub->imeisv, VTY_NEWLINE);
+       if (argc > 0)
+               flags |= MSC_VTY_DUMP_F_TRANSACTION;
+       flags |= MSC_VTY_DUMP_F_SUBSCR;

-       vty_out(vty, "    Flags: %s", VTY_NEWLINE);
-       vty_out(vty, "     IMSI detached:             %s%s",
-               vsub->imsi_detached_flag ? "true" : "false", VTY_NEWLINE);
-       vty_out(vty, "     Conf. by radio contact:    %s%s",
-               vsub->conf_by_radio_contact_ind ? "true" : "false",
-               VTY_NEWLINE);
-       vty_out(vty, "     Subscr. data conf. by HLR: %s%s",
-               vsub->sub_dataconf_by_hlr_ind ? "true" : "false", VTY_NEWLINE);
-       vty_out(vty, "     Location conf. in HLR:     %s%s",
-               vsub->loc_conf_in_hlr_ind ? "true" : "false", VTY_NEWLINE);
-       vty_out(vty, "     Subscriber dormant:        %s%s",
-               vsub->dormant_ind ? "true" : "false", VTY_NEWLINE);
-       vty_out(vty, "     Received cancel locataion: %s%s",
-               vsub->cancel_loc_rx ? "true" : "false", VTY_NEWLINE);
-       vty_out(vty, "     MS not reachable:          %s%s",
-               vsub->ms_not_reachable_flag ? "true" : "false", VTY_NEWLINE);
-       vty_out(vty, "     LA allowed:                %s%s",
-               vsub->la_allowed ? "true" : "false", VTY_NEWLINE);
-
-       if (vsub->last_tuple) {
-               struct vlr_auth_tuple *t = vsub->last_tuple;
-               vty_out(vty, "    A3A8 last tuple (used %d times):%s",
-                       t->use_count, VTY_NEWLINE);
-               vty_out(vty, "     seq # : %d%s",
-                       t->key_seq, VTY_NEWLINE);
-               vty_out(vty, "     RAND  : %s%s",
-                       osmo_hexdump(t->vec.rand, sizeof(t->vec.rand)),
-                       VTY_NEWLINE);
-               vty_out(vty, "     SRES  : %s%s",
-                       osmo_hexdump(t->vec.sres, sizeof(t->vec.sres)),
-                       VTY_NEWLINE);
-               vty_out(vty, "     Kc    : %s%s",
-                       osmo_hexdump(t->vec.kc, sizeof(t->vec.kc)),
-                       VTY_NEWLINE);
+       llist_for_each_entry(msub, &msub_list, entry) {
+               vty_out(vty, "  Connection #%02u: %s", i++, VTY_NEWLINE);
+               vty_dump_one_conn(vty, msub, 4, flags);
        }

-       vty_out(vty, "    Paging: %s paging for %d requests%s",
-               vsub->cs.is_paging ? "is" : "not",
-               llist_count(&vsub->cs.requests),
-               VTY_NEWLINE);
-
-       /* SGs related */
-       vty_out(vty, "    SGs-state: %s%s",
-               osmo_fsm_inst_state_name(vsub->sgs_fsm), VTY_NEWLINE);
-       if (strlen(vsub->sgs.mme_name))
-               vty_out(vty, "    SGs-MME: %s%s", vsub->sgs.mme_name, 
VTY_NEWLINE);
-       else
-               vty_out(vty, "    SGs-MME: (none)%s", VTY_NEWLINE);
-
-       vty_out(vty, "    Use: %s%s", osmo_use_count_name_buf(buf, sizeof(buf), 
&vsub->use_count), VTY_NEWLINE);
-
-       /* Connection */
-       if (vsub->msc_conn_ref) {
-               struct msub *msub = msub_for_vsub(vsub);
-               int idx = 0;
-               if (msub) {
-                       vty_dump_one_conn(vty, msub, &idx);
-               }
-       }
-
-       /* Transactions */
-       vty_trans_hdr(vty);
-       llist_for_each_entry(trans, &gsmnet->trans_list, entry) {
-               if (trans->vsub != vsub)
-                       continue;
-               vty_dump_one_trans(vty, trans);
-       }
+       return CMD_SUCCESS;
 }

+#define SUBSCR_FLAGS "[(conn|trans|conn+trans)]"
+#define SUBSCR_FLAGS_HELP \
+       "Show child connections\n" \
+       "Show child transactions\n" \
+       "Show child connections and transactions\n"
+
 /* Subscriber */
-DEFUN(show_subscr_cache,
-      show_subscr_cache_cmd,
-      "show subscriber cache",
+DEFUN(show_subscr_cache, show_subscr_cache_cmd,
+       "show subscriber cache " SUBSCR_FLAGS,
        SHOW_STR "Show information about subscribers\n"
-       "Display contents of subscriber cache\n")
+       "Display contents of subscriber cache\n"
+       SUBSCR_FLAGS_HELP)
 {
        struct vlr_subscr *vsub;
-       int count = 0;
+       unsigned int count = 0;
+       uint8_t flags = 0x00;
+       unsigned int i = 0;
+
+       if (argc && strcmp(argv[0], "conn") == 0)
+               flags |= MSC_VTY_DUMP_F_CONNECTION;
+       else if (argc && strcmp(argv[0], "trans") == 0)
+               flags |= MSC_VTY_DUMP_F_TRANSACTION;
+       else if (argc && strcmp(argv[0], "conn+trans") == 0)
+               flags |= MSC_VTY_DUMP_F_CONNECTION | MSC_VTY_DUMP_F_TRANSACTION;

        llist_for_each_entry(vsub, &gsmnet->vlr->subscribers, list) {
                if (++count > 100) {
@@ -872,8 +985,8 @@
                                " stopping here.%s", count-1, VTY_NEWLINE);
                        break;
                }
-               vty_out(vty, "  Subscriber:%s", VTY_NEWLINE);
-               subscr_dump_full_vty(vty, vsub);
+               vty_out(vty, "  Subscriber #%02u: %s", i++, VTY_NEWLINE);
+               vty_dump_one_subscr(vty, vsub, 4, flags);
        }

        return CMD_SUCCESS;
@@ -982,14 +1095,14 @@
        "Legacy alias for 'imsi'\n"                                     \
        "Identifier for the subscriber\n"

-DEFUN(show_subscr,
-      show_subscr_cmd,
-      "show subscriber " SUBSCR_TYPES " ID",
-       SHOW_STR SUBSCR_HELP)
+DEFUN(show_subscr, show_subscr_cmd,
+       "show subscriber " SUBSCR_TYPES " ID " SUBSCR_FLAGS,
+       SHOW_STR SUBSCR_HELP SUBSCR_FLAGS_HELP)
 {
-       struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0],
-                                                      argv[1]);
+       struct vlr_subscr *vsub;
+       uint8_t flags = 0x00;

+       vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
        if (!vsub) {
                vty_out(vty, "%% No subscriber found for %s %s%s",
                        argv[0], argv[1], VTY_NEWLINE);
@@ -1001,7 +1114,15 @@
         * this, and since this is not multi-threaded, this vlr_subscr_put() 
cannot possibly reach a count of 0. */
        vlr_subscr_put(vsub, VSUB_USE_VTY);

-       subscr_dump_full_vty(vty, vsub);
+       if (argc > 2 && strcmp(argv[2], "conn") == 0)
+               flags |= MSC_VTY_DUMP_F_CONNECTION;
+       else if (argc > 2 && strcmp(argv[2], "trans") == 0)
+               flags |= MSC_VTY_DUMP_F_TRANSACTION;
+       else if (argc > 2 && strcmp(argv[2], "conn+trans") == 0)
+               flags |= MSC_VTY_DUMP_F_CONNECTION | MSC_VTY_DUMP_F_TRANSACTION;
+
+       vty_out(vty, "  Subscriber: %s", VTY_NEWLINE);
+       vty_dump_one_subscr(vty, vsub, 4, flags);

        return CMD_SUCCESS;
 }

--
To view, visit https://gerrit.osmocom.org/c/osmo-msc/+/14069
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-msc
Gerrit-Branch: master
Gerrit-Change-Id: I5e58b56204c3f3d019e8d4c3c96cefdbb4af4d47
Gerrit-Change-Number: 14069
Gerrit-PatchSet: 5
Gerrit-Owner: fixeria <[email protected]>
Gerrit-Reviewer: Harald Welte <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <[email protected]>
Gerrit-Reviewer: Pau Espin Pedrol <[email protected]>
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: osmith <[email protected]>
Gerrit-MessageType: merged

Reply via email to