diff mbox series

[v6] libibverbs: display gid type in ibv_devinfo

Message ID 1580809644-5979-1-git-send-email-devesh.sharma@broadcom.com (mailing list archive)
State Superseded
Headers show
Series [v6] libibverbs: display gid type in ibv_devinfo | expand

Commit Message

Devesh Sharma Feb. 4, 2020, 9:47 a.m. UTC
It becomes difficult to make out from the output of ibv_devinfo
if a particular gid index is RoCE v2 or not.

Adding a string to the output of ibv_devinfo -v to display the
gid type at the end of gid.

The output would look something like below:
$ ibv_devinfo -v -d bnxt_re2
hca_id: bnxt_re2
 transport:             InfiniBand (0)
 fw_ver:                216.0.220.0
 node_guid:             b226:28ff:fed3:b0f0
 sys_image_guid:        b226:28ff:fed3:b0f0
  .
  .
  .
  .
	phys_state:     LINK_UP (5)
	GID[  0]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, IB/RoCE v1
	GID[  1]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, RoCE v2
	GID[  1]:       fe80::b226:28ff:fed3:b0f0
	GID[  2]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, IB/RoCE v1
	GID[  3]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, RoCE v2
	GID[  3]:       ::ffff:192.170.1.101
$
$
$

Reviewed-by: Jason Gunthrope <jgg@ziepe.ca>
Reviewed-by: Leon Romanovsky <leon@kernel.org>
Reviewed-by: Gal Pressman <galpress@amazon.com>
Reviewed-by: Parav Pandit <parav@mellanox.com>
Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
---
 libibverbs/examples/devinfo.c | 60 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 48 insertions(+), 12 deletions(-)

Comments

Leon Romanovsky Feb. 4, 2020, 1:08 p.m. UTC | #1
On Tue, Feb 04, 2020 at 04:47:24AM -0500, Devesh Sharma wrote:
> It becomes difficult to make out from the output of ibv_devinfo
> if a particular gid index is RoCE v2 or not.
>
> Adding a string to the output of ibv_devinfo -v to display the
> gid type at the end of gid.
>
> The output would look something like below:
> $ ibv_devinfo -v -d bnxt_re2
> hca_id: bnxt_re2
>  transport:             InfiniBand (0)
>  fw_ver:                216.0.220.0
>  node_guid:             b226:28ff:fed3:b0f0
>  sys_image_guid:        b226:28ff:fed3:b0f0
>   .
>   .
>   .
>   .
> 	phys_state:     LINK_UP (5)
> 	GID[  0]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, IB/RoCE v1
> 	GID[  1]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, RoCE v2
> 	GID[  1]:       fe80::b226:28ff:fed3:b0f0
> 	GID[  2]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, IB/RoCE v1
> 	GID[  3]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, RoCE v2
> 	GID[  3]:       ::ffff:192.170.1.101
> $
> $
> $
>
> Reviewed-by: Jason Gunthrope <jgg@ziepe.ca>
> Reviewed-by: Leon Romanovsky <leon@kernel.org>

At least with my ROB tag, you was too fast :)

> Reviewed-by: Gal Pressman <galpress@amazon.com>
> Reviewed-by: Parav Pandit <parav@mellanox.com>
> Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
> ---
>  libibverbs/examples/devinfo.c | 60 ++++++++++++++++++++++++++++++++++---------
>  1 file changed, 48 insertions(+), 12 deletions(-)
>
> diff --git a/libibverbs/examples/devinfo.c b/libibverbs/examples/devinfo.c
> index bf53eac..83acc22 100644
> --- a/libibverbs/examples/devinfo.c
> +++ b/libibverbs/examples/devinfo.c
> @@ -40,6 +40,7 @@
>  #include <getopt.h>
>  #include <endian.h>
>  #include <inttypes.h>
> +#include <arpa/inet.h>
>
>  #include <infiniband/verbs.h>
>  #include <infiniband/driver.h>
> @@ -162,12 +163,49 @@ static const char *vl_str(uint8_t vl_num)
>  	}
>  }
>
> -static int print_all_port_gids(struct ibv_context *ctx, uint8_t port_num, int tbl_len)
> +#define DEVINFO_INVALID_GID_TYPE	2
> +static const char *gid_type_str(enum ibv_gid_type type)
>  {
> +	switch (type) {
> +	case IBV_GID_TYPE_IB_ROCE_V1: return "IB/RoCE v1";
> +	case IBV_GID_TYPE_ROCE_V2: return "RoCE v2";
> +	default: return "Invalid gid type";
> +	}
> +}
> +
> +static void print_formated_gid(union ibv_gid *gid, int i,
> +			       enum ibv_gid_type type, int ll)
> +{
> +	char gid_str[INET6_ADDRSTRLEN] = {};
> +	char str[20] = {};
> +
> +	if (ll == IBV_LINK_LAYER_ETHERNET) {
> +		sprintf(str, ", %s", gid_type_str(type));
> +		printf("\t\t\tGID[%3d]:\t\t%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x%s\n",
> +		       i, gid->raw[0], gid->raw[1], gid->raw[2],
> +		       gid->raw[3], gid->raw[4], gid->raw[5], gid->raw[6],
> +		       gid->raw[7], gid->raw[8], gid->raw[9], gid->raw[10],
> +		       gid->raw[11], gid->raw[12], gid->raw[13], gid->raw[14],
> +		       gid->raw[15], str);
> +	}
> +
> +	if (type == IBV_GID_TYPE_ROCE_V2) {
> +		inet_ntop(AF_INET6, gid->raw, gid_str, sizeof(gid_str));
> +		printf("\t\t\tGID[%3d]:\t\t%s\n", i, gid_str);
> +	}
> +}
> +
> +static int print_all_port_gids(struct ibv_context *ctx,
> +			       struct ibv_port_attr *port_attr,
> +			       uint8_t port_num)
> +{
> +	enum ibv_gid_type type;
>  	union ibv_gid gid;
> +	int tbl_len;
>  	int rc = 0;
>  	int i;
>
> +	tbl_len = port_attr->gid_tbl_len;
>  	for (i = 0; i < tbl_len; i++) {
>  		rc = ibv_query_gid(ctx, port_num, i, &gid);
>  		if (rc) {
> @@ -175,17 +213,15 @@ static int print_all_port_gids(struct ibv_context *ctx, uint8_t port_num, int tb
>  			       port_num, i);
>  			return rc;
>  		}
> +
> +		rc = ibv_query_gid_type(ctx, port_num, i, &type);
> +		if (rc) {
> +			rc = 0;
> +			type = DEVINFO_INVALID_GID_TYPE;
> +		}
>  		if (!null_gid(&gid))
> -			printf("\t\t\tGID[%3d]:\t\t%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
> -			       i,
> -			       gid.raw[ 0], gid.raw[ 1],
> -			       gid.raw[ 2], gid.raw[ 3],
> -			       gid.raw[ 4], gid.raw[ 5],
> -			       gid.raw[ 6], gid.raw[ 7],
> -			       gid.raw[ 8], gid.raw[ 9],
> -			       gid.raw[10], gid.raw[11],
> -			       gid.raw[12], gid.raw[13],
> -			       gid.raw[14], gid.raw[15]);
> +			print_formated_gid(&gid, i, type,
> +					   port_attr->link_layer);
>  	}
>  	return rc;
>  }
> @@ -614,7 +650,7 @@ static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port)
>  				printf("\t\t\tphys_state:\t\t%s (%d)\n",
>  				       port_phy_state_str(port_attr.phys_state), port_attr.phys_state);
>
> -			if (print_all_port_gids(ctx, port, port_attr.gid_tbl_len))
> +			if (print_all_port_gids(ctx, &port_attr, port))
>  				goto cleanup;
>  		}
>  		printf("\n");
> --
> 1.8.3.1
>
Parav Pandit Feb. 4, 2020, 2:31 p.m. UTC | #2
Hi Devesh,

> From: linux-rdma-owner@vger.kernel.org <linux-rdma-
> owner@vger.kernel.org> On Behalf Of Devesh Sharma
> 	phys_state:     LINK_UP (5)
> 	GID[  0]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, IB/RoCE v1
> 	GID[  1]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, RoCE v2
> 	GID[  1]:       fe80::b226:28ff:fed3:b0f0
Showing two entries as individual raw like this is surely confusing to user.
Either all content should be in single raw or as Leon said just single different format for RoCEv2 is fine.

> 	GID[  2]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, IB/RoCE v1
> 	GID[  3]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, RoCE v2
> 	GID[  3]:       ::ffff:192.170.1.101
Devesh Sharma Feb. 4, 2020, 3:26 p.m. UTC | #3
On Tue, Feb 4, 2020 at 8:01 PM Parav Pandit <parav@mellanox.com> wrote:
>
> Hi Devesh,
>
> > From: linux-rdma-owner@vger.kernel.org <linux-rdma-
> > owner@vger.kernel.org> On Behalf Of Devesh Sharma
> >       phys_state:     LINK_UP (5)
> >       GID[  0]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, IB/RoCE v1
> >       GID[  1]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, RoCE v2
> >       GID[  1]:       fe80::b226:28ff:fed3:b0f0
> Showing two entries as individual raw like this is surely confusing to user.
> Either all content should be in single raw or as Leon said just single different format for RoCEv2 is fine.
Yes, I liked the single display in new format, I would wait for Jason
to agree/disagree and then send a rev.
>
> >       GID[  2]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, IB/RoCE v1
> >       GID[  3]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, RoCE v2
> >       GID[  3]:       ::ffff:192.170.1.101
Devesh Sharma Feb. 4, 2020, 3:41 p.m. UTC | #4
On Tue, Feb 4, 2020 at 3:17 PM Devesh Sharma <devesh.sharma@broadcom.com> wrote:
>
> It becomes difficult to make out from the output of ibv_devinfo
> if a particular gid index is RoCE v2 or not.
>
> Adding a string to the output of ibv_devinfo -v to display the
> gid type at the end of gid.
>
> The output would look something like below:
> $ ibv_devinfo -v -d bnxt_re2
> hca_id: bnxt_re2
>  transport:             InfiniBand (0)
>  fw_ver:                216.0.220.0
>  node_guid:             b226:28ff:fed3:b0f0
>  sys_image_guid:        b226:28ff:fed3:b0f0
>   .
>   .
>   .
>   .
>         phys_state:     LINK_UP (5)
>         GID[  0]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, IB/RoCE v1
>         GID[  1]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, RoCE v2
>         GID[  1]:       fe80::b226:28ff:fed3:b0f0
>         GID[  2]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, IB/RoCE v1
>         GID[  3]:       0000:0000:0000:0000:0000:ffff:c0aa:0165, RoCE v2
>         GID[  3]:       ::ffff:192.170.1.101
> $
> $
> $
>
> Reviewed-by: Jason Gunthrope <jgg@ziepe.ca>
> Reviewed-by: Leon Romanovsky <leon@kernel.org>
> Reviewed-by: Gal Pressman <galpress@amazon.com>
> Reviewed-by: Parav Pandit <parav@mellanox.com>
> Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
> ---
>  libibverbs/examples/devinfo.c | 60 ++++++++++++++++++++++++++++++++++---------
>  1 file changed, 48 insertions(+), 12 deletions(-)
>
> diff --git a/libibverbs/examples/devinfo.c b/libibverbs/examples/devinfo.c
> index bf53eac..83acc22 100644
> --- a/libibverbs/examples/devinfo.c
> +++ b/libibverbs/examples/devinfo.c
> @@ -40,6 +40,7 @@
>  #include <getopt.h>
>  #include <endian.h>
>  #include <inttypes.h>
> +#include <arpa/inet.h>
>
>  #include <infiniband/verbs.h>
>  #include <infiniband/driver.h>
> @@ -162,12 +163,49 @@ static const char *vl_str(uint8_t vl_num)
>         }
>  }
>
> -static int print_all_port_gids(struct ibv_context *ctx, uint8_t port_num, int tbl_len)
> +#define DEVINFO_INVALID_GID_TYPE       2
> +static const char *gid_type_str(enum ibv_gid_type type)
>  {
> +       switch (type) {
> +       case IBV_GID_TYPE_IB_ROCE_V1: return "IB/RoCE v1";
> +       case IBV_GID_TYPE_ROCE_V2: return "RoCE v2";
> +       default: return "Invalid gid type";
> +       }
> +}
> +
> +static void print_formated_gid(union ibv_gid *gid, int i,
> +                              enum ibv_gid_type type, int ll)
> +{
> +       char gid_str[INET6_ADDRSTRLEN] = {};
> +       char str[20] = {};
> +
> +       if (ll == IBV_LINK_LAYER_ETHERNET) {
> +               sprintf(str, ", %s", gid_type_str(type));
> +               printf("\t\t\tGID[%3d]:\t\t%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x%s\n",
> +                      i, gid->raw[0], gid->raw[1], gid->raw[2],
> +                      gid->raw[3], gid->raw[4], gid->raw[5], gid->raw[6],
> +                      gid->raw[7], gid->raw[8], gid->raw[9], gid->raw[10],
> +                      gid->raw[11], gid->raw[12], gid->raw[13], gid->raw[14],
> +                      gid->raw[15], str);
> +       }
Opps!! this needs a rev in anycase, for IB devices gid won't be
printed at all, my bad!
> +
> +       if (type == IBV_GID_TYPE_ROCE_V2) {
> +               inet_ntop(AF_INET6, gid->raw, gid_str, sizeof(gid_str));
> +               printf("\t\t\tGID[%3d]:\t\t%s\n", i, gid_str);
> +       }
> +}
> +
> +static int print_all_port_gids(struct ibv_context *ctx,
> +                              struct ibv_port_attr *port_attr,
> +                              uint8_t port_num)
> +{
> +       enum ibv_gid_type type;
>         union ibv_gid gid;
> +       int tbl_len;
>         int rc = 0;
>         int i;
>
> +       tbl_len = port_attr->gid_tbl_len;
>         for (i = 0; i < tbl_len; i++) {
>                 rc = ibv_query_gid(ctx, port_num, i, &gid);
>                 if (rc) {
> @@ -175,17 +213,15 @@ static int print_all_port_gids(struct ibv_context *ctx, uint8_t port_num, int tb
>                                port_num, i);
>                         return rc;
>                 }
> +
> +               rc = ibv_query_gid_type(ctx, port_num, i, &type);
> +               if (rc) {
> +                       rc = 0;
> +                       type = DEVINFO_INVALID_GID_TYPE;
> +               }
>                 if (!null_gid(&gid))
> -                       printf("\t\t\tGID[%3d]:\t\t%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
> -                              i,
> -                              gid.raw[ 0], gid.raw[ 1],
> -                              gid.raw[ 2], gid.raw[ 3],
> -                              gid.raw[ 4], gid.raw[ 5],
> -                              gid.raw[ 6], gid.raw[ 7],
> -                              gid.raw[ 8], gid.raw[ 9],
> -                              gid.raw[10], gid.raw[11],
> -                              gid.raw[12], gid.raw[13],
> -                              gid.raw[14], gid.raw[15]);
> +                       print_formated_gid(&gid, i, type,
> +                                          port_attr->link_layer);
>         }
>         return rc;
>  }
> @@ -614,7 +650,7 @@ static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port)
>                                 printf("\t\t\tphys_state:\t\t%s (%d)\n",
>                                        port_phy_state_str(port_attr.phys_state), port_attr.phys_state);
>
> -                       if (print_all_port_gids(ctx, port, port_attr.gid_tbl_len))
> +                       if (print_all_port_gids(ctx, &port_attr, port))
>                                 goto cleanup;
>                 }
>                 printf("\n");
> --
> 1.8.3.1
>
Jason Gunthorpe Feb. 5, 2020, 7:07 p.m. UTC | #5
On Tue, Feb 04, 2020 at 08:56:54PM +0530, Devesh Sharma wrote:
> On Tue, Feb 4, 2020 at 8:01 PM Parav Pandit <parav@mellanox.com> wrote:
> >
> > Hi Devesh,
> >
> > > From: linux-rdma-owner@vger.kernel.org <linux-rdma-
> > > owner@vger.kernel.org> On Behalf Of Devesh Sharma
> > >       phys_state:     LINK_UP (5)
> > >       GID[  0]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, IB/RoCE v1
> > >       GID[  1]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, RoCE v2
> > >       GID[  1]:       fe80::b226:28ff:fed3:b0f0
> > Showing two entries as individual raw like this is surely confusing to user.
> > Either all content should be in single raw or as Leon said just single different format for RoCEv2 is fine.
> Yes, I liked the single display in new format, I would wait for Jason
> to agree/disagree and then send a rev.

Well, I wasn't thinking to display the GID[xx] prefix for the 2nd
entry

It seems like other people want to just show one, that seems OK too

Jason
Devesh Sharma Feb. 6, 2020, 5:29 a.m. UTC | #6
On Thu, Feb 6, 2020 at 12:37 AM Jason Gunthorpe <jgg@ziepe.ca> wrote:
>
> On Tue, Feb 04, 2020 at 08:56:54PM +0530, Devesh Sharma wrote:
> > On Tue, Feb 4, 2020 at 8:01 PM Parav Pandit <parav@mellanox.com> wrote:
> > >
> > > Hi Devesh,
> > >
> > > > From: linux-rdma-owner@vger.kernel.org <linux-rdma-
> > > > owner@vger.kernel.org> On Behalf Of Devesh Sharma
> > > >       phys_state:     LINK_UP (5)
> > > >       GID[  0]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, IB/RoCE v1
> > > >       GID[  1]:       fe80:0000:0000:0000:b226:28ff:fed3:b0f0, RoCE v2
> > > >       GID[  1]:       fe80::b226:28ff:fed3:b0f0
> > > Showing two entries as individual raw like this is surely confusing to user.
> > > Either all content should be in single raw or as Leon said just single different format for RoCEv2 is fine.
> > Yes, I liked the single display in new format, I would wait for Jason
> > to agree/disagree and then send a rev.
>
> Well, I wasn't thinking to display the GID[xx] prefix for the 2nd
> entry
>
> It seems like other people want to just show one, that seems OK too
Thanks for confirming, sending down V7 shortly please review.
>
> Jason
diff mbox series

Patch

diff --git a/libibverbs/examples/devinfo.c b/libibverbs/examples/devinfo.c
index bf53eac..83acc22 100644
--- a/libibverbs/examples/devinfo.c
+++ b/libibverbs/examples/devinfo.c
@@ -40,6 +40,7 @@ 
 #include <getopt.h>
 #include <endian.h>
 #include <inttypes.h>
+#include <arpa/inet.h>
 
 #include <infiniband/verbs.h>
 #include <infiniband/driver.h>
@@ -162,12 +163,49 @@  static const char *vl_str(uint8_t vl_num)
 	}
 }
 
-static int print_all_port_gids(struct ibv_context *ctx, uint8_t port_num, int tbl_len)
+#define DEVINFO_INVALID_GID_TYPE	2
+static const char *gid_type_str(enum ibv_gid_type type)
 {
+	switch (type) {
+	case IBV_GID_TYPE_IB_ROCE_V1: return "IB/RoCE v1";
+	case IBV_GID_TYPE_ROCE_V2: return "RoCE v2";
+	default: return "Invalid gid type";
+	}
+}
+
+static void print_formated_gid(union ibv_gid *gid, int i,
+			       enum ibv_gid_type type, int ll)
+{
+	char gid_str[INET6_ADDRSTRLEN] = {};
+	char str[20] = {};
+
+	if (ll == IBV_LINK_LAYER_ETHERNET) {
+		sprintf(str, ", %s", gid_type_str(type));
+		printf("\t\t\tGID[%3d]:\t\t%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x%s\n",
+		       i, gid->raw[0], gid->raw[1], gid->raw[2],
+		       gid->raw[3], gid->raw[4], gid->raw[5], gid->raw[6],
+		       gid->raw[7], gid->raw[8], gid->raw[9], gid->raw[10],
+		       gid->raw[11], gid->raw[12], gid->raw[13], gid->raw[14],
+		       gid->raw[15], str);
+	}
+
+	if (type == IBV_GID_TYPE_ROCE_V2) {
+		inet_ntop(AF_INET6, gid->raw, gid_str, sizeof(gid_str));
+		printf("\t\t\tGID[%3d]:\t\t%s\n", i, gid_str);
+	}
+}
+
+static int print_all_port_gids(struct ibv_context *ctx,
+			       struct ibv_port_attr *port_attr,
+			       uint8_t port_num)
+{
+	enum ibv_gid_type type;
 	union ibv_gid gid;
+	int tbl_len;
 	int rc = 0;
 	int i;
 
+	tbl_len = port_attr->gid_tbl_len;
 	for (i = 0; i < tbl_len; i++) {
 		rc = ibv_query_gid(ctx, port_num, i, &gid);
 		if (rc) {
@@ -175,17 +213,15 @@  static int print_all_port_gids(struct ibv_context *ctx, uint8_t port_num, int tb
 			       port_num, i);
 			return rc;
 		}
+
+		rc = ibv_query_gid_type(ctx, port_num, i, &type);
+		if (rc) {
+			rc = 0;
+			type = DEVINFO_INVALID_GID_TYPE;
+		}
 		if (!null_gid(&gid))
-			printf("\t\t\tGID[%3d]:\t\t%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
-			       i,
-			       gid.raw[ 0], gid.raw[ 1],
-			       gid.raw[ 2], gid.raw[ 3],
-			       gid.raw[ 4], gid.raw[ 5],
-			       gid.raw[ 6], gid.raw[ 7],
-			       gid.raw[ 8], gid.raw[ 9],
-			       gid.raw[10], gid.raw[11],
-			       gid.raw[12], gid.raw[13],
-			       gid.raw[14], gid.raw[15]);
+			print_formated_gid(&gid, i, type,
+					   port_attr->link_layer);
 	}
 	return rc;
 }
@@ -614,7 +650,7 @@  static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port)
 				printf("\t\t\tphys_state:\t\t%s (%d)\n",
 				       port_phy_state_str(port_attr.phys_state), port_attr.phys_state);
 
-			if (print_all_port_gids(ctx, port, port_attr.gid_tbl_len))
+			if (print_all_port_gids(ctx, &port_attr, port))
 				goto cleanup;
 		}
 		printf("\n");