Blame SOURCES/open-lldp-v1.0.1-5-VDP-Support-for-get-tlv-in-vdptool-and-VDP22.patch

89f6b3
From 0a21b0c0b9674f90cb9185e7fe097ae83657328f Mon Sep 17 00:00:00 2001
89f6b3
From: padkrish <padkrish@cisco.com>
89f6b3
Date: Wed, 21 Jan 2015 03:37:31 +0000
89f6b3
Subject: [PATCH] VDP: Support for get-tlv in vdptool and VDP22
89f6b3
89f6b3
This commit has the following changes:
89f6b3
a. Change in VDP22 and vdptool to support get-tlv. This actually refers to
89f6b3
get-vsi. Support for querying and printing all VSI's, partial VSI's is added.
89f6b3
The vdptool man page document is also modified accordingly.
89f6b3
b. The response from lldpad (VDP22) is modified to support to the
89f6b3
len, key, len, value format. Earlier, only the meessage to VDP22 has the
89f6b3
format. The response from VDP22 followed the comma separated format for VSI
89f6b3
parameters.
89f6b3
c. Fix some formatting issues
89f6b3
89f6b3
Signed-off-by: padkrish <padkrish@cisco.com>
89f6b3
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
89f6b3
---
89f6b3
 docs/vdptool.8         |  47 +++++++-----
89f6b3
 include/lldp_util.h    |   1 +
89f6b3
 include/qbg_vdp22.h    |   5 +-
89f6b3
 include/qbg_vdp22def.h |  11 ++-
89f6b3
 include/qbg_vdpnl.h    |   3 +
89f6b3
 lldp_util.c            |  52 ++++++++++----
89f6b3
 qbg/vdp22.c            |  28 ++++++--
89f6b3
 qbg/vdp22_cmds.c       | 135 +++++++++++++++++++++++++++++++----
89f6b3
 qbg/vdp22sm.c          |   5 +-
89f6b3
 qbg/vdp_ascii.c        | 190 +++++++++++++++++++++++++++++++------------------
89f6b3
 vdptool.c              | 152 +++++++++++----------------------------
89f6b3
 11 files changed, 395 insertions(+), 234 deletions(-)
89f6b3
89f6b3
diff --git a/docs/vdptool.8 b/docs/vdptool.8
89f6b3
index 5110bb9..02b4e8e 100644
89f6b3
--- a/docs/vdptool.8
89f6b3
+++ b/docs/vdptool.8
89f6b3
@@ -70,17 +70,17 @@ bridge.
89f6b3
 Specifies additional parameters for TLV queries and associations commands.
89f6b3
 The argument list varies, depending on the command option
89f6b3
 .B (-T)
89f6b3
-or 
89f6b3
+or
89f6b3
 .BR (-t) .
89f6b3
-To establish a VSI association use the command option 
89f6b3
+To establish a VSI association use the command option
89f6b3
 .B (-T)
89f6b3
 and specify additional information as arguments in the form
89f6b3
-of key=value. See the 
89f6b3
+of key=value. See the
89f6b3
 .I "VSI Parameter"
89f6b3
 subsection and
89f6b3
 .I Example
89f6b3
 section below.
89f6b3
-To query a VSI specific association use the command option 
89f6b3
+To query a VSI specific association use the command option
89f6b3
 .B (-t)
89f6b3
 and specify the value of the
89f6b3
 VSI Instance Identifier (keywork uuid followed be the VSI
89f6b3
@@ -92,6 +92,9 @@ show raw client interface messages
89f6b3
 .TP
89f6b3
 .B \-R
89f6b3
 show only raw Client interface messages
89f6b3
+.TP
89f6b3
+.B \-W
89f6b3
+Wait for the bridge response message
89f6b3
 .SS VSI Parameter
89f6b3
 Each VDP22 TLVs contains a command mode, manager identifier,
89f6b3
 type identifier, type identifier version, VSI instance identifier,
89f6b3
@@ -99,7 +102,7 @@ migiration hints and filter information.
89f6b3
 The fields are explained next:
89f6b3
 .TP
89f6b3
 .B "mode (Command Mode):"
89f6b3
-The command mode determines the type 
89f6b3
+The command mode determines the type
89f6b3
 of the VSI association to be established.
89f6b3
 It is an ascii string can be one of:
89f6b3
 .RS
89f6b3
@@ -110,7 +113,7 @@ Create an VSI preassociation. The association
89f6b3
 is only announced to the switch.
89f6b3
 .IP preassoc-rr:
89f6b3
 Create an VSI preassociation. The association
89f6b3
-is only announced to the switch and the 
89f6b3
+is only announced to the switch and the
89f6b3
 switch should reserve the resources.
89f6b3
 .IP deassoc:
89f6b3
 Delete an VSI association.
89f6b3
@@ -137,7 +140,7 @@ an UUID according to RFC 4122
89f6b3
 with optional dashes in between.
89f6b3
 .TP
89f6b3
 .B "hints (Migration Hints):"
89f6b3
-The migiration hints is a string aiding in 
89f6b3
+The migiration hints is a string aiding in
89f6b3
 migration of virtual machines:
89f6b3
 .RS
89f6b3
 .IP none:
89f6b3
@@ -168,13 +171,13 @@ The MAC address is specified in the format xx:xx:xx:xx:xx:xx.
89f6b3
 The colons are mandatory.
89f6b3
 For vlan details see (1).
89f6b3
 .IP "vlan-mac-group (4)"
89f6b3
-A vlan number, MAC address and group identifier, 
89f6b3
+A vlan number, MAC address and group identifier,
89f6b3
 each delimited by a slash ('-'),
89f6b3
 also known as filter information format 4.
89f6b3
 The group identifier is a 32 bit number.
89f6b3
 For vlan and MAC address details see (1) and (2).
89f6b3
 .IP "vlan--group (3)"
89f6b3
-A vlan number and group identifier, 
89f6b3
+A vlan number and group identifier,
89f6b3
 delimited by two slashes ('--'),
89f6b3
 also known as filter information format 3.
89f6b3
 For vlan and group details see (1) and (4).
89f6b3
@@ -218,18 +221,30 @@ vdptool -p
89f6b3
 Create a VSI association on interface eth2
89f6b3
 .br
89f6b3
 .nf
89f6b3
-Supported today: One config parameter and comma separated list
89f6b3
-vdptool -i eth2 -T -V assoc -c vsi=assoc,blabla,5, \\
89f6b3
-	1122,4,none,2-52:00:00:11:22:33-200
89f6b3
+vdptool -i eth2 -T -V assoc -c mode=assoc -c mgrid2=blabla \\
89f6b3
+	-c typeid=5 -c uuid=1122 -c typeidver=4 -c hints=none \\
89f6b3
+	-c filter=2-52:00:00:11:22:33-200
89f6b3
+.fi
89f6b3
+.TP
89f6b3
+Create a VSI association on interface eth2 and wait for the response from the bridge
89f6b3
+.br
89f6b3
+.nf
89f6b3
+vdptool -i eth2 -T -W -V assoc -c mode=assoc -c mgrid2=blabla \\
89f6b3
+	-c typeid=5 -c uuid=1122 -c typeidver=4 -c hints=none \\
89f6b3
+	-c filter=0-52:00:00:11:22:33-200
89f6b3
+.fi
89f6b3
 
89f6b3
-Planned for the future:
89f6b3
-vdptool -i eth2 -T -V assoc -c mgrid2=blabla -c typeid=5 \\
89f6b3
-	-c uuid=1122 -c typeidver=4 -c hints=none -c fid=2-52:00:00:11:22:33-200
89f6b3
-.fi
89f6b3
 .TP
89f6b3
 Query all VSI association on interface eth2
89f6b3
 .br
89f6b3
 vdptool -i eth2 -t -V assoc
89f6b3
+
89f6b3
+.TP
89f6b3
+Query  VSI association on interface eth2 that matches specific VSI parameters. Any of the VSI parameters below can be omitted.
89f6b3
+.br
89f6b3
+vdptool -i eth2 -t -V assoc -t -V assoc -c mode=assoc \\
89f6b3
+        -c mgrid2=blabla -c typeid=5 -c uuid=1122 \\
89f6b3
+        -c typeidver=4 -c hints=none
89f6b3
 .SH SEE ALSO
89f6b3
 .BR lldptool-dcbx (8),
89f6b3
 .BR lldptool-ets (8),
89f6b3
diff --git a/include/lldp_util.h b/include/lldp_util.h
89f6b3
index 5767d4e..878426b 100644
89f6b3
--- a/include/lldp_util.h
89f6b3
+++ b/include/lldp_util.h
89f6b3
@@ -170,6 +170,7 @@ int check_link_status(const char *ifname);
89f6b3
 int get_arg_val_list(char *ibuf, int ilen, int *ioff,
89f6b3
 			    char **args, char **argvals);
89f6b3
 int get_arg_list(char *ibuf, int ilen, int *ioff, char **args);
89f6b3
+int get_vsistr_arg_count(int ioff, int ilen);
89f6b3
 
89f6b3
 #define ntohll(x) be64_to_cpu(x)
89f6b3
 #define htonll(x) cpu_to_be64(x)
89f6b3
diff --git a/include/qbg_vdp22.h b/include/qbg_vdp22.h
89f6b3
index 45f44d5..af0aa15 100644
89f6b3
--- a/include/qbg_vdp22.h
89f6b3
+++ b/include/qbg_vdp22.h
89f6b3
@@ -165,7 +165,7 @@ struct vdp22_user_data {		/* Head for all VDP data */
89f6b3
 
89f6b3
 struct vsi_keyword_handler {
89f6b3
 	char *keyword;
89f6b3
-	enum vsi_mand_arg val;
89f6b3
+	enum vsi_key_arg val;
89f6b3
 };
89f6b3
 
89f6b3
 struct lldp_module *vdp22_register(void);
89f6b3
@@ -175,6 +175,7 @@ void vdp22_showvsi(struct vsi22 *p);
89f6b3
 void vdp22_stop(char *);
89f6b3
 int vdp22_from_ecp22(struct vdp22 *);
89f6b3
 int vdp22_query(const char *);
89f6b3
+struct vdp22 *vdp22_getvdp(const char *);
89f6b3
 int vdp22_addreq(struct vsi22 *, struct vdp22 *);
89f6b3
 int vdp22_nlback(struct vsi22 *);
89f6b3
 int vdp22_clntback(struct vsi22 *);
89f6b3
@@ -184,6 +185,8 @@ int vdp22br_resources(struct vsi22 *, int *);
89f6b3
 int vdp22_info(const char *);
89f6b3
 void vdp22_stop_timers(struct vsi22 *);
89f6b3
 int vdp22_start_localchange_timer(struct vsi22 *);
89f6b3
+bool vdp22_cmp_fdata(struct vsi22 *, struct vsi22 *);
89f6b3
+void vdp22_delete_vsi(struct vsi22 *);
89f6b3
 
89f6b3
 /*
89f6b3
  * Functions to get and set vlan identifier and qos.
89f6b3
diff --git a/include/qbg_vdp22def.h b/include/qbg_vdp22def.h
89f6b3
index 21ba15d..ff4270c 100644
89f6b3
--- a/include/qbg_vdp22def.h
89f6b3
+++ b/include/qbg_vdp22def.h
89f6b3
@@ -30,6 +30,15 @@
89f6b3
 #define QBG_VDP22DEF_H
89f6b3
 
89f6b3
 /*
89f6b3
+ * Define for length of vid-mac-gid
89f6b3
+ * VID in string cannot be more than 4B (Max is 4K)
89f6b3
+ * MAC when represented as 11:22:33:44:55:66 has 17B
89f6b3
+ * GID is 4B
89f6b3
+ * The below should be more than sufficient.
89f6b3
+ */
89f6b3
+#define MAX_GID_MAC_VID_STR 50
89f6b3
+
89f6b3
+/*
89f6b3
  * Define VDP22 filter formats.
89f6b3
  */
89f6b3
 enum vdp22_ffmt {			/* Format of filter information */
89f6b3
@@ -72,7 +81,7 @@ enum vdp22_migration_hints {
89f6b3
 	VDP22_MIGFROM = 32		/* S-bit migrate from hint */
89f6b3
 };
89f6b3
 
89f6b3
-enum vsi_mand_arg {
89f6b3
+enum vsi_key_arg {
89f6b3
 	VSI_MODE_ARG = 0,
89f6b3
 	VSI_MGRID2_ARG,
89f6b3
 	VSI_TYPEID_ARG,
89f6b3
diff --git a/include/qbg_vdpnl.h b/include/qbg_vdpnl.h
89f6b3
index 510a20c..c5c93ed 100644
89f6b3
--- a/include/qbg_vdpnl.h
89f6b3
+++ b/include/qbg_vdpnl.h
89f6b3
@@ -79,4 +79,7 @@ int vdp_str2vdpnl(char *, struct vdpnl_vsi *, char *);
89f6b3
 int vdp_vdpnl2str(struct vdpnl_vsi *, char *, size_t);
89f6b3
 int vdp22_sendevent(struct vdpnl_vsi *);
89f6b3
 void vdp22_freemaclist(struct vdpnl_vsi *);
89f6b3
+int vdp22_parse_str_vdpnl(struct vdpnl_vsi *, unsigned short *, char *);
89f6b3
+struct vsi22 *vdp22_alloc_vsi_ext(struct vdpnl_vsi *, int *);
89f6b3
+void copy_vsi_external(struct vdpnl_vsi *, struct vsi22 *, int);
89f6b3
 #endif
89f6b3
diff --git a/lldp_util.c b/lldp_util.c
89f6b3
index 754b0cd..f1fb7b9 100644
89f6b3
--- a/lldp_util.c
89f6b3
+++ b/lldp_util.c
89f6b3
@@ -199,7 +199,7 @@ int is_bond(const char *ifname)
89f6b3
  */
89f6b3
 int is_san_mac(u8 *addr)
89f6b3
 {
89f6b3
-	int i; 
89f6b3
+	int i;
89f6b3
 
89f6b3
 	for ( i = 0; i < ETH_ALEN; i++) {
89f6b3
 		if ( addr[i]!= 0xff )
89f6b3
@@ -215,7 +215,7 @@ int is_san_mac(u8 *addr)
89f6b3
  *	@addr: address of buffer in which to return the selected MAC address
89f6b3
  *
89f6b3
  *	Checks to see if ifname is a slave of the bond port.  If it is,
89f6b3
- *	then a 
89f6b3
+ *	then a
89f6b3
  *	Returns 0 if a source MAC from the bond could not be found. 1 is
89f6b3
  *	returned if the slave was found in the bond.  addr is updated with
89f6b3
  *	the source MAC that should be used.
89f6b3
@@ -287,7 +287,7 @@ int	get_src_mac_from_bond(struct port *bond_port, char *ifname, u8 *addr)
89f6b3
 
89f6b3
 	switch (ifb.bond_mode) {
89f6b3
 	case BOND_MODE_ACTIVEBACKUP:
89f6b3
-		/* If current port is not the active slave, then 
89f6b3
+		/* If current port is not the active slave, then
89f6b3
 		 * if the bond MAC is equal to the port's
89f6b3
 		 * permanent MAC, then find and return
89f6b3
 		 * the permanent MAC of the active
89f6b3
@@ -297,7 +297,7 @@ int	get_src_mac_from_bond(struct port *bond_port, char *ifname, u8 *addr)
89f6b3
 		if (strncmp(ifname, act_ifname, IFNAMSIZ))
89f6b3
 			if (get_perm_hwaddr(ifname, addr, san_mac) == 0)
89f6b3
 				if (!memcmp(bond_mac, addr, ETH_ALEN))
89f6b3
-					get_perm_hwaddr(act_ifname, addr, 
89f6b3
+					get_perm_hwaddr(act_ifname, addr,
89f6b3
 								san_mac);
89f6b3
 		break;
89f6b3
 	default:
89f6b3
@@ -346,7 +346,7 @@ int get_ifflags(const char *ifname)
89f6b3
 	int flags = 0;
89f6b3
 	struct ifreq ifr;
89f6b3
 
89f6b3
-	/* use ioctl */	
89f6b3
+	/* use ioctl */
89f6b3
 	fd = get_ioctl_socket();
89f6b3
 	if (fd >= 0) {
89f6b3
 		memset(&ifr, 0, sizeof(ifr));
89f6b3
@@ -382,7 +382,7 @@ int get_ifpflags(const char *ifname)
89f6b3
 	int flags = 0;
89f6b3
 	struct ifreq ifr;
89f6b3
 
89f6b3
-	/* use ioctl */	
89f6b3
+	/* use ioctl */
89f6b3
 	fd = get_ioctl_socket();
89f6b3
 	if (fd >= 0) {
89f6b3
 		memset(&ifr, 0, sizeof(ifr));
89f6b3
@@ -417,7 +417,7 @@ int get_iflink(const char *ifname)
89f6b3
 	snprintf(path, sizeof(path), "/sys/class/net/%s/iflink", ifname);
89f6b3
 	return read_int(path);
89f6b3
 }
89f6b3
-	
89f6b3
+
89f6b3
 int is_ether(const char *ifname)
89f6b3
 {
89f6b3
 	/* check for bridge in sysfs */
89f6b3
@@ -486,7 +486,7 @@ int is_slave(const char *ifmaster, const char *ifslave)
89f6b3
 			}
89f6b3
 		}
89f6b3
 	}
89f6b3
-	
89f6b3
+
89f6b3
 out_done:
89f6b3
 	return rc;
89f6b3
 }
89f6b3
@@ -562,13 +562,13 @@ int is_bridge(const char *ifname)
89f6b3
 	if (dirp) {
89f6b3
 		closedir(dirp);
89f6b3
 		rc = 1;
89f6b3
-	} else { 
89f6b3
-		/* use ioctl */	
89f6b3
+	} else {
89f6b3
+		/* use ioctl */
89f6b3
 		fd = get_ioctl_socket();
89f6b3
 		if (fd >= 0) {
89f6b3
 			struct ifreq ifr;
89f6b3
 			struct __bridge_info bi;
89f6b3
-			unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO, 
89f6b3
+			unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
89f6b3
 						 (unsigned long) &bi, 0, 0 };
89f6b3
 
89f6b3
 			ifr.ifr_data = (char *)args;
89f6b3
@@ -748,7 +748,7 @@ int is_autoneg_supported(const char *ifname)
89f6b3
 	int fd;
89f6b3
 	struct ifreq ifr;
89f6b3
 	struct ethtool_cmd cmd;
89f6b3
-	
89f6b3
+
89f6b3
 	fd = get_ioctl_socket();
89f6b3
 	if (fd >= 0) {
89f6b3
 		memset(&ifr, 0, sizeof(ifr));
89f6b3
@@ -769,7 +769,7 @@ int is_autoneg_enabled(const char *ifname)
89f6b3
 	int fd;
89f6b3
 	struct ifreq ifr;
89f6b3
 	struct ethtool_cmd cmd;
89f6b3
-	
89f6b3
+
89f6b3
 	fd = get_ioctl_socket();
89f6b3
 	if (fd >= 0) {
89f6b3
 		memset(&ifr, 0, sizeof(ifr));
89f6b3
@@ -806,7 +806,7 @@ int get_maucaps(const char *ifname)
89f6b3
 	u16 caps = MAUCAPADV_bOther;
89f6b3
 	struct ifreq ifr;
89f6b3
 	struct ethtool_cmd cmd;
89f6b3
-	
89f6b3
+
89f6b3
 	fd = get_ioctl_socket();
89f6b3
 	if (fd >= 0) {
89f6b3
 		memset(&ifr, 0, sizeof(ifr));
89f6b3
@@ -940,7 +940,7 @@ u16 get_caps(const char *ifname)
89f6b3
 
89f6b3
 	/* how to find TPID to determine C-VLAN vs. S-VLAN ? */
89f6b3
 	if (is_vlan(ifname))
89f6b3
-		caps |= SYSCAP_CVLAN; 
89f6b3
+		caps |= SYSCAP_CVLAN;
89f6b3
 
89f6b3
 	if (is_bridge(ifname))
89f6b3
 		caps |= SYSCAP_BRIDGE;
89f6b3
@@ -1282,3 +1282,25 @@ int get_arg_list(char *ibuf, int ilen, int *ioff, char **args)
89f6b3
 	free(arglens);
89f6b3
 	return numargs;
89f6b3
 }
89f6b3
+
89f6b3
+/*
89f6b3
+ * This functionality can be seen in many places to convert a LenData to a
89f6b3
+ * argument array.
89f6b3
+ */
89f6b3
+
89f6b3
+int get_vsistr_arg_count(int ioff, int ilen)
89f6b3
+{
89f6b3
+	int offset;
89f6b3
+	int numargs;
89f6b3
+
89f6b3
+	offset = ioff;
89f6b3
+	for (numargs = 0; (ilen - offset) > 2; numargs++) {
89f6b3
+		offset += 2;
89f6b3
+		if (ilen - offset > 0) {
89f6b3
+			offset++;
89f6b3
+			if (ilen - offset > 4)
89f6b3
+				offset += 4;
89f6b3
+		}
89f6b3
+	}
89f6b3
+	return numargs;
89f6b3
+}
89f6b3
diff --git a/qbg/vdp22.c b/qbg/vdp22.c
89f6b3
index a3cb7c9..af11af8 100644
89f6b3
--- a/qbg/vdp22.c
89f6b3
+++ b/qbg/vdp22.c
89f6b3
@@ -219,7 +219,7 @@ void vdp22_showvsi(struct vsi22 *p)
89f6b3
 /*
89f6b3
  * Delete a complete VSI node not on queue.
89f6b3
  */
89f6b3
-static void vdp22_delete_vsi(struct vsi22 *p)
89f6b3
+void vdp22_delete_vsi(struct vsi22 *p)
89f6b3
 {
89f6b3
 	LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p,
89f6b3
 		   p->vsi[0]);
89f6b3
@@ -477,14 +477,15 @@ static bool filter_ok(unsigned char ffmt, struct fid22 *fp,
89f6b3
  * Allocate a VSI node with filter information data.
89f6b3
  * Check if input data is valid.
89f6b3
  */
89f6b3
-static struct vsi22 *vdp22_alloc_vsi(struct vdpnl_vsi *vsi, struct vdp22 *vdp,
89f6b3
-				     int *rc)
89f6b3
+static struct vsi22 *vdp22_alloc_vsi_int(struct vdpnl_vsi *vsi,
89f6b3
+					 struct vdp22 *vdp,
89f6b3
+					 int *rc, bool vsinl_chk)
89f6b3
 {
89f6b3
 	struct vsi22 *p;
89f6b3
 	int i;
89f6b3
 
89f6b3
 	*rc = -EINVAL;
89f6b3
-	if (!check_vsinl(vsi))
89f6b3
+	if (vsinl_chk && (!check_vsinl(vsi)))
89f6b3
 		return NULL;
89f6b3
 	p = calloc(1, sizeof(*p));
89f6b3
 	if (!p) {
89f6b3
@@ -546,6 +547,16 @@ error1:
89f6b3
 	return NULL;
89f6b3
 }
89f6b3
 
89f6b3
+struct vsi22 *vdp22_alloc_vsi_ext(struct vdpnl_vsi *vsinl, int *rc)
89f6b3
+{
89f6b3
+	struct vdp22 *vdp;
89f6b3
+
89f6b3
+	vdp = vdp22_getvdp(vsinl->ifname);
89f6b3
+	if (!vdp)
89f6b3
+		return NULL;
89f6b3
+	return vdp22_alloc_vsi_int(vsinl, vdp, rc, false);
89f6b3
+}
89f6b3
+
89f6b3
 /*
89f6b3
  * Allocate a VSI node with filter information data.
89f6b3
  * Check if input data is valid. Data was received by bridge from unknown
89f6b3
@@ -750,7 +761,7 @@ static struct vdp22 *vdp22_create(const char *ifname,
89f6b3
 /*
89f6b3
  * Query the supported VDP protocol on an interface.
89f6b3
  */
89f6b3
-static struct vdp22 *vdp22_getvdp(const char *ifname)
89f6b3
+struct vdp22 *vdp22_getvdp(const char *ifname)
89f6b3
 {
89f6b3
 	struct vdp22 *vdp;
89f6b3
 
89f6b3
@@ -820,7 +831,7 @@ int vdp22_request(struct vdpnl_vsi *vsi, int clif)
89f6b3
 		/* Adjust numbering for VDP 0.2 protocol from netlink */
89f6b3
 		if (!clif)
89f6b3
 			vsi->request += 1;
89f6b3
-		p = vdp22_alloc_vsi(vsi, vdp, &rc);
89f6b3
+		p = vdp22_alloc_vsi_int(vsi, vdp, &rc, true);
89f6b3
 		if (p) {
89f6b3
 			rc = vdp22_addreq(p, vdp);
89f6b3
 			if (rc)
89f6b3
@@ -1079,3 +1090,8 @@ int vdp22_info(const char *ifname)
89f6b3
 	return rc;
89f6b3
 
89f6b3
 }
89f6b3
+
89f6b3
+void copy_vsi_external(struct vdpnl_vsi *vsi, struct vsi22 *p, int clif)
89f6b3
+{
89f6b3
+	copy_vsi(vsi, p, clif);
89f6b3
+}
89f6b3
diff --git a/qbg/vdp22_cmds.c b/qbg/vdp22_cmds.c
89f6b3
index dde4669..409858d 100644
89f6b3
--- a/qbg/vdp22_cmds.c
89f6b3
+++ b/qbg/vdp22_cmds.c
89f6b3
@@ -237,7 +237,7 @@ int vdp22_clif_cmd(UNUSED void *data, UNUSED struct sockaddr_un *from,
89f6b3
 		return cmd_not_applicable;
89f6b3
 	}
89f6b3
 
89f6b3
-	if (!(cmd.ops & op_config))
89f6b3
+	if (!(cmd.ops & op_config) && (cmd.cmd != cmd_gettlv))
89f6b3
 		return cmd_invalid;
89f6b3
 
89f6b3
 	snprintf(rbuf, rlen, "%c%1x%02x%08x%02x%s",
89f6b3
@@ -254,10 +254,9 @@ int vdp22_clif_cmd(UNUSED void *data, UNUSED struct sockaddr_un *from,
89f6b3
 	snprintf(rbuf + roff, rlen - roff, "%08x", cmd.tlvid);
89f6b3
 	roff += 8;
89f6b3
 	if (cmd.cmd == cmd_gettlv) {
89f6b3
-		rstatus = handle_get_arg(&cmd, ARG_VDP22_VSI,
89f6b3
-						NULL,
89f6b3
-						rbuf + strlen(rbuf),
89f6b3
-						rlen - strlen(rbuf));
89f6b3
+		rstatus = handle_get_arg(&cmd, ARG_VDP22_VSI, ibuf + ioff,
89f6b3
+					 rbuf + strlen(rbuf),
89f6b3
+					 rlen - strlen(rbuf));
89f6b3
 	} else {
89f6b3
 		rstatus = handle_test_arg(&cmd, ARG_VDP22_VSI,
89f6b3
 						ibuf + ioff,
89f6b3
@@ -392,19 +391,25 @@ static int test_arg_vsi(struct cmd *cmd, UNUSED char *arg, char *argvalue,
89f6b3
  */
89f6b3
 static int catvsis(struct vdpnl_vsi *vsi, char *out, size_t out_len)
89f6b3
 {
89f6b3
-	int rc, i;
89f6b3
+	int rc, i, len, c;
89f6b3
 	size_t used = 0;
89f6b3
 	unsigned char wanted_req = vsi->request;
89f6b3
+	char tmp_buf[MAX_CLIF_MSGBUF];
89f6b3
 
89f6b3
+	memset(tmp_buf, 0, sizeof(tmp_buf));
89f6b3
 	for (i = 1; vdp22_status(i, vsi, 1) > 0; ++i) {
89f6b3
 		if (wanted_req != vsi->request) {
89f6b3
 			vdp22_freemaclist(vsi);
89f6b3
 			continue;
89f6b3
 		}
89f6b3
-		rc = vdp_vdpnl2str(vsi, out + used, out_len - used);
89f6b3
+		rc = vdp_vdpnl2str(vsi, tmp_buf, out_len - used);
89f6b3
+		len = strlen(tmp_buf);
89f6b3
+		c = snprintf(out + used, out_len - used, "%04x%s", len,
89f6b3
+			     tmp_buf);
89f6b3
+		if ((c < 0) || ((unsigned)c >= (out_len - used)))
89f6b3
+			return 0;
89f6b3
 		vdp22_freemaclist(vsi);
89f6b3
 		if (rc) {
89f6b3
-			strcat(out, ";");
89f6b3
 			used = strlen(out);
89f6b3
 		} else
89f6b3
 			return 0;
89f6b3
@@ -413,15 +418,113 @@ static int catvsis(struct vdpnl_vsi *vsi, char *out, size_t out_len)
89f6b3
 }
89f6b3
 
89f6b3
 /*
89f6b3
+ * Based on the VSI arguments specified, checks if it matches.
89f6b3
+ * This does't check for all VSI parameters.
89f6b3
+ */
89f6b3
+
89f6b3
+static bool vdp22_partial_vsi_equal(struct vsi22 *p1, struct vsi22 *p2,
89f6b3
+				    enum vsi_key_arg vsi_arg_key_flags)
89f6b3
+{
89f6b3
+	enum vsi_key_arg key_enum;
89f6b3
+
89f6b3
+	for (key_enum = VSI_MODE_ARG; key_enum < VSI_INVALID_ARG; key_enum++) {
89f6b3
+		if (!((1 << key_enum) & vsi_arg_key_flags))
89f6b3
+			continue;
89f6b3
+		switch (key_enum) {
89f6b3
+		case VSI_MODE_ARG:
89f6b3
+			break;
89f6b3
+		case VSI_MGRID2_ARG:
89f6b3
+			if (memcmp(p1->mgrid, p2->mgrid,
89f6b3
+				   sizeof(p2->mgrid)))
89f6b3
+				return false;
89f6b3
+		case VSI_TYPEID_ARG:
89f6b3
+			if (p1->type_id != p2->type_id)
89f6b3
+				return false;
89f6b3
+			break;
89f6b3
+		case VSI_TYPEIDVER_ARG:
89f6b3
+			if (p1->type_ver != p2->type_ver)
89f6b3
+				return false;
89f6b3
+			break;
89f6b3
+#ifdef LATER
89f6b3
+/* Currently not supported */
89f6b3
+		case VSI_VSIIDFRMT_ARG:
89f6b3
+			if (p1->vsi_fmt != p2->vsi_fmt)
89f6b3
+				return false;
89f6b3
+			break;
89f6b3
+#endif
89f6b3
+		case VSI_VSIID_ARG:
89f6b3
+			if (memcmp(p1->vsi, p2->vsi, sizeof(p1->vsi)))
89f6b3
+				return false;
89f6b3
+			break;
89f6b3
+		case VSI_FILTER_ARG:
89f6b3
+			if ((p1->fif != p2->fif) || (!vdp22_cmp_fdata(p1, p2)))
89f6b3
+				return false;
89f6b3
+			break;
89f6b3
+		case VSI_HINTS_ARG:
89f6b3
+			break;
89f6b3
+		default:
89f6b3
+			return false;
89f6b3
+		}
89f6b3
+	}
89f6b3
+	return true;
89f6b3
+}
89f6b3
+
89f6b3
+static int get_vsi_partial_arg(UNUSED char *arg, char *orig_argvalue,
89f6b3
+			       struct vdpnl_vsi *vsinl, char *out,
89f6b3
+			       size_t out_len)
89f6b3
+{
89f6b3
+	char tmp_buf[MAX_CLIF_MSGBUF];
89f6b3
+	struct vsi22 *p, *vsi;
89f6b3
+	struct vdp22 *vdp;
89f6b3
+	size_t used = 0;
89f6b3
+	int rc = -ENOMEM, len, c;
89f6b3
+	u16 vsi_arg_key_flags = 0;
89f6b3
+
89f6b3
+	if (vdp22_parse_str_vdpnl(vsinl, &vsi_arg_key_flags, orig_argvalue))
89f6b3
+		goto out;
89f6b3
+	vdp = vdp22_getvdp(vsinl->ifname);
89f6b3
+	if (!vdp)
89f6b3
+		goto out;
89f6b3
+
89f6b3
+	vsi = vdp22_alloc_vsi_ext(vsinl, &rc);
89f6b3
+	if (!vsi)
89f6b3
+		goto out;
89f6b3
+	LIST_FOREACH(p, &vdp->vsi22_que, node) {
89f6b3
+		if (p->vsi_mode != vsi->vsi_mode)
89f6b3
+			continue;
89f6b3
+		if (vdp22_partial_vsi_equal(p, vsi, vsi_arg_key_flags)) {
89f6b3
+			copy_vsi_external(vsinl, p, 1);
89f6b3
+			rc = vdp_vdpnl2str(vsinl, tmp_buf, out_len - used);
89f6b3
+			len = strlen(tmp_buf);
89f6b3
+			c = snprintf(out + used, out_len - used, "%04x%s",
89f6b3
+				     len, tmp_buf);
89f6b3
+			vdp22_freemaclist(vsinl);
89f6b3
+			if ((c < 0) || ((unsigned)c >= (out_len - used)))
89f6b3
+				goto out_delvsi;
89f6b3
+			if (rc)
89f6b3
+				used = strlen(out);
89f6b3
+			else
89f6b3
+				goto out_delvsi;
89f6b3
+		}
89f6b3
+	}
89f6b3
+out_delvsi:
89f6b3
+	vdp22_delete_vsi(vsi);
89f6b3
+out:
89f6b3
+	return rc;
89f6b3
+}
89f6b3
+
89f6b3
+/*
89f6b3
  * Return all VSIs on a particular interface into one string.
89f6b3
  */
89f6b3
-static int get_arg_vsi(struct cmd *cmd, char *arg, UNUSED char *argvalue,
89f6b3
+static int get_arg_vsi(struct cmd *cmd, char *arg, char *argvalue,
89f6b3
 		       char *obuf, int obuf_len)
89f6b3
 {
89f6b3
 	cmd_status good_cmd = vdp22_cmdok(cmd, cmd_gettlv);
89f6b3
 	struct vdpnl_vsi vsi;
89f6b3
 	char vsi_str[MAX_CLIF_MSGBUF];
89f6b3
 	int rc;
89f6b3
+	int fsize = (cmd->ops >> OP_FID_POS) & 0xff;
89f6b3
+	struct vdpnl_mac mac[fsize];
89f6b3
 
89f6b3
 	if (good_cmd != cmd_success)
89f6b3
 		return good_cmd;
89f6b3
@@ -433,14 +536,20 @@ static int get_arg_vsi(struct cmd *cmd, char *arg, UNUSED char *argvalue,
89f6b3
 
89f6b3
 	memset(obuf, 0, obuf_len);
89f6b3
 	memset(&vsi, 0, sizeof(vsi));
89f6b3
+	memset(vsi_str, 0, sizeof(vsi_str));
89f6b3
 	vsi.request = cmd->tlvid;
89f6b3
 	strncpy(vsi.ifname, cmd->ifname, sizeof(vsi.ifname) - 1);
89f6b3
 	good_cmd = cmd_failed;
89f6b3
-	if (!catvsis(&vsi, vsi_str, sizeof(vsi_str)))
89f6b3
+	if ((cmd->ops & op_config) && (cmd->ops & op_arg)) {
89f6b3
+		memset(&mac, 0, sizeof(mac));
89f6b3
+		vsi.macsz = fsize;
89f6b3
+		vsi.maclist = mac;
89f6b3
+		if (!get_vsi_partial_arg(arg, argvalue, &vsi, vsi_str,
89f6b3
+					 sizeof(vsi_str)))
89f6b3
+			goto out;
89f6b3
+	} else if (!catvsis(&vsi, vsi_str, sizeof(vsi_str)))
89f6b3
 		goto out;
89f6b3
-	rc = snprintf(obuf, obuf_len, "%02x%s%04x%s",
89f6b3
-		 (unsigned int)strlen(arg), arg, (unsigned int)strlen(vsi_str),
89f6b3
-		 vsi_str);
89f6b3
+	rc = snprintf(obuf, obuf_len, "%s", vsi_str);
89f6b3
 	if (rc > 0 || rc < obuf_len)
89f6b3
 		good_cmd = cmd_success;
89f6b3
 out:
89f6b3
diff --git a/qbg/vdp22sm.c b/qbg/vdp22sm.c
89f6b3
index d1f65b4..6264f74 100644
89f6b3
--- a/qbg/vdp22sm.c
89f6b3
+++ b/qbg/vdp22sm.c
89f6b3
@@ -944,7 +944,8 @@ static bool cmp_fdata1(struct fid22 *p1, struct fid22 *p2, unsigned char fif)
89f6b3
 
89f6b3
 	if (fif == VDP22_FFMT_MACVID || fif == VDP22_FFMT_GROUPMACVID)
89f6b3
 		is_good = !memcmp(p1->mac, p2->mac, sizeof(p1->mac));
89f6b3
-	if (fif == VDP22_FFMT_GROUPVID || fif == VDP22_FFMT_GROUPMACVID)
89f6b3
+	if (is_good &&
89f6b3
+		(fif == VDP22_FFMT_GROUPVID || fif == VDP22_FFMT_GROUPMACVID))
89f6b3
 		is_good = (p1->grpid == p2->grpid);
89f6b3
 	if (is_good) {
89f6b3
 		if (vdp22_get_vlanid(p1->vlan))
89f6b3
@@ -956,7 +957,7 @@ static bool cmp_fdata1(struct fid22 *p1, struct fid22 *p2, unsigned char fif)
89f6b3
 	return is_good;
89f6b3
 }
89f6b3
 
89f6b3
-static bool vdp22_cmp_fdata(struct vsi22 *p, struct vsi22 *vsip)
89f6b3
+bool vdp22_cmp_fdata(struct vsi22 *p, struct vsi22 *vsip)
89f6b3
 {
89f6b3
 	int i;
89f6b3
 
89f6b3
diff --git a/qbg/vdp_ascii.c b/qbg/vdp_ascii.c
89f6b3
index 09e53c6..76dde4a 100644
89f6b3
--- a/qbg/vdp_ascii.c
89f6b3
+++ b/qbg/vdp_ascii.c
89f6b3
@@ -110,6 +110,15 @@ static bool getnumber(char *s, unsigned int min, unsigned int max,
89f6b3
 }
89f6b3
 
89f6b3
 /*
89f6b3
+ * Returns the byte length of a given number
89f6b3
+ */
89f6b3
+
89f6b3
+static int get_strlen_num(unsigned long no)
89f6b3
+{
89f6b3
+	return snprintf(NULL, 0, "%lu", no);
89f6b3
+}
89f6b3
+
89f6b3
+/*
89f6b3
  * Read filter information data. The format is an ascii string:
89f6b3
  * filter-data		filter-format
89f6b3
  * vlan			1
89f6b3
@@ -264,7 +273,7 @@ static bool getmode(struct vdpnl_vsi *p, char *s)
89f6b3
 	return true;
89f6b3
 }
89f6b3
 
89f6b3
-enum vsi_mand_arg get_keywork_val(char *keyword)
89f6b3
+enum vsi_key_arg get_keywork_val(char *keyword)
89f6b3
 {
89f6b3
 	int count, key_str_size;
89f6b3
 
89f6b3
@@ -276,65 +285,36 @@ enum vsi_mand_arg get_keywork_val(char *keyword)
89f6b3
 	return VSI_INVALID_ARG;
89f6b3
 }
89f6b3
 
89f6b3
-/*
89f6b3
- * Parse the mode parameter to create/change an VSI assoication.
89f6b3
- * The format is a comma separated list of tokens:
89f6b3
- * cmd,mgrid,typeid,typeidversion,vsiid,hints,fid[,fid,fid,...]
89f6b3
- * with
89f6b3
- * cmd := "assoc" | "deassoc" | "preassoc" | "preassoc-rr"
89f6b3
- * mgrid :=  less or equal to 16 byte alphanumeric characters
89f6b3
- *		| UUID (with dashes in between)
89f6b3
- * typeid := number in range of 1 - 2^24 -1
89f6b3
- * typeidversion:= number in range of 1 - 255
89f6b3
- * vsiid := UUID (with dashes in between)
89f6b3
- * hints := varies between input (command) and output (event message)
89f6b3
- *          on input --> dash (-) | "none" | "from" | "to"
89f6b3
- *          on output --> response (number between 0..255)
89f6b3
- * fid := vlan
89f6b3
- *	| vlan-mac
89f6b3
- *	| vlan--group
89f6b3
- *	| vlan-mac-group
89f6b3
- * vlan := number in range of 1..2^16 -1
89f6b3
- * group := number in range of 1..2^32 - 1
89f6b3
- * mac := xx:xx:xx:xx:xx:xx
89f6b3
- */
89f6b3
-
89f6b3
-static int str2vdpnl(char *orig_argvalue, struct vdpnl_vsi *vsi)
89f6b3
+int vdp22_parse_str_vdpnl(struct vdpnl_vsi *vsi, u16 *key_flags,
89f6b3
+			  char *orig_argvalue)
89f6b3
 {
89f6b3
-	char **args;
89f6b3
 	char **argvals;
89f6b3
+	char **args;
89f6b3
 	char *argvalue;
89f6b3
+	enum vsi_key_arg vsi_key;
89f6b3
 	int rc = -ENOMEM;
89f6b3
+	int i, ioff = 0, numargs;
89f6b3
+	int ilen = strlen(orig_argvalue);
89f6b3
 	unsigned int no;
89f6b3
 	unsigned short idx = 0;
89f6b3
-	int i, ioff = 0, offset;
89f6b3
-	int ilen = strlen(orig_argvalue);
89f6b3
-	int numargs;
89f6b3
-	enum vsi_mand_arg vsi_key;
89f6b3
-	u16 vsi_mand_mask = (1 << VSI_MAND_NUM_ARG) - 1;
89f6b3
 	u16 num_arg_keys = 0;
89f6b3
 
89f6b3
 	argvalue = strdup(orig_argvalue);
89f6b3
 	if (!argvalue)
89f6b3
 		goto out;
89f6b3
 	/* Count args and argvalues */
89f6b3
-	offset = ioff;
89f6b3
-	for (numargs = 0; (ilen - offset) > 2; numargs++) {
89f6b3
-		offset += 2;
89f6b3
-		if (ilen - offset > 0) {
89f6b3
-			offset++;
89f6b3
-			if (ilen - offset > 4)
89f6b3
-				offset += 4;
89f6b3
-		}
89f6b3
-	}
89f6b3
+	numargs = get_vsistr_arg_count(ioff, ilen);
89f6b3
+	if (numargs == 0)
89f6b3
+		goto out_argvalue;
89f6b3
 	args = calloc(numargs, sizeof(char *));
89f6b3
 	if (!args)
89f6b3
 		goto out_argvalue;
89f6b3
-
89f6b3
 	argvals = calloc(numargs, sizeof(char *));
89f6b3
 	if (!argvals)
89f6b3
 		goto out_args;
89f6b3
 	numargs = get_arg_val_list(argvalue, ilen, &ioff, args, argvals);
89f6b3
+	if (numargs == 0)
89f6b3
+		goto out_free;
89f6b3
 	for (i = 0; i < numargs; i++) {
89f6b3
 		vsi_key = get_keywork_val(args[i]);
89f6b3
 		switch (vsi_key) {
89f6b3
@@ -378,9 +358,9 @@ static int str2vdpnl(char *orig_argvalue, struct vdpnl_vsi *vsi)
89f6b3
 		}
89f6b3
 		num_arg_keys |= (1 << vsi_key);
89f6b3
 	}
89f6b3
-	/* Return error if no filter information provided */
89f6b3
-	if ((num_arg_keys & vsi_mand_mask) == vsi_mand_mask)
89f6b3
-		rc = 0;
89f6b3
+	*key_flags = num_arg_keys;
89f6b3
+	rc = 0;
89f6b3
+
89f6b3
 out_free:
89f6b3
 	free(argvals);
89f6b3
 out_args:
89f6b3
@@ -392,6 +372,44 @@ out:
89f6b3
 }
89f6b3
 
89f6b3
 /*
89f6b3
+ * Parse the mode parameter to create/change an VSI assoication.
89f6b3
+ * The format is a comma separated list of tokens:
89f6b3
+ * cmd,mgrid,typeid,typeidversion,vsiid,hints,fid[,fid,fid,...]
89f6b3
+ * with
89f6b3
+ * cmd := "assoc" | "deassoc" | "preassoc" | "preassoc-rr"
89f6b3
+ * mgrid :=  less or equal to 16 byte alphanumeric characters
89f6b3
+ *		| UUID (with dashes in between)
89f6b3
+ * typeid := number in range of 1 - 2^24 -1
89f6b3
+ * typeidversion:= number in range of 1 - 255
89f6b3
+ * vsiid := UUID (with dashes in between)
89f6b3
+ * hints := varies between input (command) and output (event message)
89f6b3
+ *          on input --> dash (-) | "none" | "from" | "to"
89f6b3
+ *          on output --> response (number between 0..255)
89f6b3
+ * fid := vlan
89f6b3
+ *	| vlan-mac
89f6b3
+ *	| vlan--group
89f6b3
+ *	| vlan-mac-group
89f6b3
+ * vlan := number in range of 1..2^16 -1
89f6b3
+ * group := number in range of 1..2^32 - 1
89f6b3
+ * mac := xx:xx:xx:xx:xx:xx
89f6b3
+ */
89f6b3
+
89f6b3
+static int str2vdpnl(char *orig_argvalue, struct vdpnl_vsi *vsi)
89f6b3
+{
89f6b3
+	int rc = -ENOMEM;
89f6b3
+	u16 vsi_mand_mask = (1 << VSI_MAND_NUM_ARG) - 1;
89f6b3
+	u16 num_arg_keys = 0;
89f6b3
+
89f6b3
+	if (vdp22_parse_str_vdpnl(vsi, &num_arg_keys, orig_argvalue))
89f6b3
+		goto out;
89f6b3
+	/* Return error if no filter information provided */
89f6b3
+	if ((num_arg_keys & vsi_mand_mask) == vsi_mand_mask)
89f6b3
+		rc = 0;
89f6b3
+out:
89f6b3
+	return rc;
89f6b3
+}
89f6b3
+
89f6b3
+/*
89f6b3
  * Fill the vdpnl_vsi structure from the string.
89f6b3
  * Allocate the maclist. Must be free'ed by caller.
89f6b3
  */
89f6b3
@@ -426,6 +444,7 @@ static char *check_and_update(size_t *total, size_t *length, char *s, int c)
89f6b3
 /*
89f6b3
  * Convert VSI association to string.
89f6b3
  */
89f6b3
+#ifdef LATER_USE
89f6b3
 static const char *mode2str(unsigned char x)
89f6b3
 {
89f6b3
 	if (x == VDP22_ASSOC)
89f6b3
@@ -438,6 +457,7 @@ static const char *mode2str(unsigned char x)
89f6b3
 		return "deassoc";
89f6b3
 	return "unknown";
89f6b3
 }
89f6b3
+#endif
89f6b3
 
89f6b3
 /*
89f6b3
  * Convert filter information format into vlan[-mac][-group] string.
89f6b3
@@ -448,26 +468,50 @@ static int fid2str(char *s, size_t length, int fif, struct vdpnl_mac *p)
89f6b3
 {
89f6b3
 	int c;
89f6b3
 	size_t total = 0;
89f6b3
+	char tmp_buf[MAX_GID_MAC_VID_STR];
89f6b3
 
89f6b3
-	c = snprintf(s, length, "%d", vdp22_set_qos(p->qos) |
89f6b3
-		     vdp22_set_vlanid(p->vlan));
89f6b3
+	c = snprintf(s, length, "%02x%s",
89f6b3
+		     (unsigned int)strlen(VSI22_ARG_FILTER_STR),
89f6b3
+		     VSI22_ARG_FILTER_STR);
89f6b3
 	s = check_and_update(&total, &length, s, c);
89f6b3
 	if (!s)
89f6b3
 		goto out;
89f6b3
-	if (fif == VDP22_FFMT_MACVID || fif == VDP22_FFMT_GROUPMACVID) {
89f6b3
-		c = snprintf(s, length, "-%02x:%02x:%02x:%02x:%02x:%02x",
89f6b3
-			     p->mac[0], p->mac[1], p->mac[2], p->mac[3],
89f6b3
-			     p->mac[4], p->mac[5]);
89f6b3
-		s = check_and_update(&total, &length, s, c);
89f6b3
-		if (!s)
89f6b3
-			goto out;
89f6b3
-	}
89f6b3
-	if (fif == VDP22_FFMT_GROUPVID || fif == VDP22_FFMT_GROUPMACVID) {
89f6b3
-		c = snprintf(s, length, "-%ld", p->gpid);
89f6b3
-		s = check_and_update(&total, &length, s, c);
89f6b3
-		if (!s)
89f6b3
-			goto out;
89f6b3
+	memset(tmp_buf, 0, sizeof(tmp_buf));
89f6b3
+	switch (fif) {
89f6b3
+	case VDP22_FFMT_VID:
89f6b3
+		snprintf(tmp_buf, MAX_GID_MAC_VID_STR, "%d",
89f6b3
+			 vdp22_set_qos(p->qos) |
89f6b3
+			 vdp22_set_vlanid(p->vlan));
89f6b3
+		break;
89f6b3
+	case VDP22_FFMT_MACVID:
89f6b3
+		snprintf(tmp_buf, MAX_GID_MAC_VID_STR,
89f6b3
+			 "%d-%02x:%02x:%02x:%02x:%02x:%02x",
89f6b3
+			 vdp22_set_qos(p->qos) |
89f6b3
+			 vdp22_set_vlanid(p->vlan),
89f6b3
+			 p->mac[0], p->mac[1], p->mac[2], p->mac[3],
89f6b3
+			 p->mac[4], p->mac[5]);
89f6b3
+		break;
89f6b3
+	case VDP22_FFMT_GROUPVID:
89f6b3
+		snprintf(tmp_buf, MAX_GID_MAC_VID_STR,
89f6b3
+			 "%d-%ld",
89f6b3
+			 vdp22_set_qos(p->qos) | vdp22_set_vlanid(p->vlan),
89f6b3
+			 p->gpid);
89f6b3
+		break;
89f6b3
+	case VDP22_FFMT_GROUPMACVID:
89f6b3
+		snprintf(tmp_buf, MAX_GID_MAC_VID_STR,
89f6b3
+			 "%d-%02x:%02x:%02x:%02x:%02x:%02x-%ld",
89f6b3
+			 vdp22_set_qos(p->qos) | vdp22_set_vlanid(p->vlan),
89f6b3
+			 p->mac[0], p->mac[1], p->mac[2], p->mac[3],
89f6b3
+			 p->mac[4], p->mac[5], p->gpid);
89f6b3
+		break;
89f6b3
+	default:
89f6b3
+		break;
89f6b3
 	}
89f6b3
+	c = snprintf(s, length, "%04x%s", (unsigned int)strlen(tmp_buf),
89f6b3
+		     tmp_buf);
89f6b3
+	s = check_and_update(&total, &length, s, c);
89f6b3
+	if (!s)
89f6b3
+		goto out;
89f6b3
 out:
89f6b3
 	return s ? total : 0;
89f6b3
 }
89f6b3
@@ -500,15 +544,28 @@ int vdp_vdpnl2str(struct vdpnl_vsi *p, char *s, size_t length)
89f6b3
 	char instance[VDP_UUID_STRLEN + 2];
89f6b3
 
89f6b3
 	mgrid2str(instance, p, sizeof(instance));
89f6b3
-	c = snprintf(s, length, "%s,%s,%ld,%d,",
89f6b3
-		     mode2str(p->request), instance, p->vsi_typeid,
89f6b3
-		     p->vsi_typeversion);
89f6b3
+	c = snprintf(s, length, "%02x%s%04x%s%02x%s%04x%lu%02x%s%04x%d",
89f6b3
+		     (unsigned int)strlen(VSI22_ARG_MGRID_STR),
89f6b3
+		     VSI22_ARG_MGRID_STR,
89f6b3
+		     (unsigned int)strlen(instance), instance,
89f6b3
+		     (unsigned int)strlen(VSI22_ARG_TYPEID_STR),
89f6b3
+		     VSI22_ARG_TYPEID_STR, get_strlen_num(p->vsi_typeid),
89f6b3
+		     p->vsi_typeid,
89f6b3
+		     (unsigned int)strlen(VSI22_ARG_TYPEIDVER_STR),
89f6b3
+		     VSI22_ARG_TYPEIDVER_STR,
89f6b3
+		     get_strlen_num(p->vsi_typeversion), p->vsi_typeversion);
89f6b3
 	s = check_and_update(&total, &length, s, c);
89f6b3
 	if (!s)
89f6b3
 		goto out;
89f6b3
 
89f6b3
 	vdp_uuid2str(p->vsi_uuid, instance, sizeof(instance));
89f6b3
-	c = snprintf(s, length, "%s,%d,", instance, p->response);
89f6b3
+	c = snprintf(s, length, "%02x%s%04x%s%02x%s%04x%d",
89f6b3
+		     (unsigned int)strlen(VSI22_ARG_VSIID_STR),
89f6b3
+		     VSI22_ARG_VSIID_STR, (unsigned int)strlen(instance),
89f6b3
+		     instance,
89f6b3
+		     (unsigned int)strlen(VSI22_ARG_HINTS_STR),
89f6b3
+		     VSI22_ARG_HINTS_STR,
89f6b3
+		     get_strlen_num(p->response), p->response);
89f6b3
 	s = check_and_update(&total, &length, s, c);
89f6b3
 	if (!s)
89f6b3
 		goto out;
89f6b3
@@ -519,13 +576,8 @@ int vdp_vdpnl2str(struct vdpnl_vsi *p, char *s, size_t length)
89f6b3
 		s = check_and_update(&total, &length, s, c);
89f6b3
 		if (!c)
89f6b3
 			goto out;
89f6b3
-		if (p->macsz > 1 && i < p->macsz - 1) {
89f6b3
-			c = snprintf(s, length, ",");
89f6b3
-			s = check_and_update(&total, &length, s, c);
89f6b3
-			if (!s)
89f6b3
-				goto out;
89f6b3
-		}
89f6b3
 	}
89f6b3
+
89f6b3
 out:
89f6b3
 	return s ? total : 0;
89f6b3
 }
89f6b3
diff --git a/vdptool.c b/vdptool.c
89f6b3
index f506020..551e829 100644
89f6b3
--- a/vdptool.c
89f6b3
+++ b/vdptool.c
89f6b3
@@ -53,6 +53,7 @@
89f6b3
 
89f6b3
 #include "qbg22.h"
89f6b3
 #include "qbg_vdp22_clif.h"
89f6b3
+#include "lldp_util.h"
89f6b3
 
89f6b3
 static char *print_status(cmd_status status)
89f6b3
 {
89f6b3
@@ -129,7 +130,7 @@ static int render_cmd(struct cmd *cmd, int argc, char **args, char **argvals)
89f6b3
 
89f6b3
 	len = sizeof(cmd->obuf);
89f6b3
 
89f6b3
-	if (cmd->cmd == cmd_settlv) {
89f6b3
+	if ((cmd->cmd == cmd_settlv) || (cmd->cmd == cmd_gettlv)) {
89f6b3
 		for (i = 0; i < argc; i++) {
89f6b3
 			if (args[i]) {
89f6b3
 				if (!strncasecmp(args[i], "filter",
89f6b3
@@ -208,13 +209,6 @@ static int vdp_cmd_gettlv(struct clif *clif, int argc, char *argv[],
89f6b3
 		cmd->ops |= op_arg;
89f6b3
 	}
89f6b3
 
89f6b3
-	for (i = 0; i < numargs; i++) {
89f6b3
-		if (argvals[i]) {
89f6b3
-			printf("%s\n", print_status(cmd_invalid));
89f6b3
-			goto out;
89f6b3
-		}
89f6b3
-	}
89f6b3
-
89f6b3
 	render_cmd(cmd, argc, args, argvals);
89f6b3
 	free(args);
89f6b3
 	free(argvals);
89f6b3
@@ -305,125 +299,61 @@ static int vdp_parse_response(char *buf)
89f6b3
 	return hex2u8(buf + CLIF_STAT_OFF);
89f6b3
 }
89f6b3
 
89f6b3
-static void print_pair(char *arg, size_t arglen, char *value, size_t valuelen)
89f6b3
+int get_vsi_args(char *ibuf)
89f6b3
 {
89f6b3
-	while (arglen--)
89f6b3
-		putchar(*arg++);
89f6b3
-	putchar('=');
89f6b3
-	while (valuelen--)
89f6b3
-		putchar(*value++);
89f6b3
-	putchar('\n');
89f6b3
-}
89f6b3
+	int ioff = 0;
89f6b3
+	char **args;
89f6b3
+	char **argvals;
89f6b3
+	int numargs, i;
89f6b3
+	int ilen = strlen(ibuf);
89f6b3
 
89f6b3
-static int print_arg_value(char *ibuf)
89f6b3
-{
89f6b3
-	int arglen, valuelen, offset = 0, ilen = strlen(ibuf);
89f6b3
-	char *arg, *value;
89f6b3
+	/* count args and argvalus */
89f6b3
+	numargs = get_vsistr_arg_count(ioff, ilen);
89f6b3
 
89f6b3
-	while (offset < ilen) {
89f6b3
-		/* Length of argument */
89f6b3
-		arglen = hex2u8(ibuf + offset);
89f6b3
-		if (arglen < 0)
89f6b3
-			break;
89f6b3
-		offset += 2;
89f6b3
-		arg = ibuf + offset;
89f6b3
-		offset += arglen;
89f6b3
+	args = calloc(numargs, sizeof(char *));
89f6b3
+	if (!args)
89f6b3
+		return cmd_failed;
89f6b3
 
89f6b3
-		/* Length of argument value */
89f6b3
-		valuelen = hex2u16(ibuf + offset);
89f6b3
-		if (valuelen < 0)
89f6b3
-			break;
89f6b3
-		offset += 4;
89f6b3
-		value = ibuf + offset;
89f6b3
-		offset += valuelen;
89f6b3
+	argvals = calloc(numargs, sizeof(char *));
89f6b3
+	if (!argvals) {
89f6b3
+		free(args);
89f6b3
+		return cmd_failed;
89f6b3
+	}
89f6b3
 
89f6b3
-		print_pair(arg, arglen, value, valuelen);
89f6b3
+	numargs = get_arg_val_list(ibuf, ilen, &ioff, args, argvals);
89f6b3
+	for (i = 0; i < numargs; i++) {
89f6b3
+		printf("\t%s", args[i]);
89f6b3
+		printf(" = %s\n", argvals[i]);
89f6b3
 	}
89f6b3
-	return offset;
89f6b3
-}
89f6b3
 
89f6b3
-static int get_tlvid(char *ibuf)
89f6b3
-{
89f6b3
-	return hex2u32(ibuf);
89f6b3
+	free(args);
89f6b3
+	free(argvals);
89f6b3
+	return ioff;
89f6b3
 }
89f6b3
 
89f6b3
-/*
89f6b3
- * Print a TLV.
89f6b3
- */
89f6b3
-static void print_tlv2(char *ibuf)
89f6b3
+static void print_all_vsis(char *ibuf)
89f6b3
 {
89f6b3
 	size_t ilen = strlen(ibuf);
89f6b3
-	u16 tlv_type;
89f6b3
-	u16 tlv_len;
89f6b3
-	u32 tlvid;
89f6b3
-	int offset = 0;
89f6b3
-	int printed;
89f6b3
-	struct lldp_module *np;
89f6b3
+	u16 vsi_len;
89f6b3
+	int offset = 0, vsi_cnt = 0;
89f6b3
+	char tmp_ibuf[strlen(ibuf)];
89f6b3
 
89f6b3
 	while (ilen > 0) {
89f6b3
-		tlv_len = 2 * sizeof(u16);
89f6b3
-		if (ilen < 2 * sizeof(u16)) {
89f6b3
-			printf("corrupted TLV ilen:%zd, tlv_len:%d\n",
89f6b3
-				ilen, tlv_len);
89f6b3
-			break;
89f6b3
-		}
89f6b3
-		tlv_type = hex2u16(ibuf + offset);
89f6b3
-		tlv_len = tlv_type;
89f6b3
-		tlv_type >>= 9;
89f6b3
-		tlv_len &= 0x01ff;
89f6b3
+		vsi_len = hex2u16(ibuf + offset);
89f6b3
+		if (vsi_len > ilen)
89f6b3
+			return;
89f6b3
 		offset += 2 * sizeof(u16);
89f6b3
 		ilen -= 2 * sizeof(u16);
89f6b3
-
89f6b3
-		if (ilen < (unsigned) 2 * tlv_len) {
89f6b3
-			printf("corrupted TLV ilen:%zd, tlv_len:%d\n",
89f6b3
-				ilen, tlv_len);
89f6b3
-			break;
89f6b3
-		}
89f6b3
-		tlvid = tlv_type;
89f6b3
-		if (tlvid == INVALID_TLVID) {
89f6b3
-			tlvid = get_tlvid(ibuf + offset);
89f6b3
-			offset += 8;
89f6b3
-		}
89f6b3
-		printed = 0;
89f6b3
-		LIST_FOREACH(np, &lldp_head, lldp) {
89f6b3
-			if (np->ops->print_tlv(tlvid, tlv_len, ibuf + offset)) {
89f6b3
-				printed = 1;
89f6b3
-				break;
89f6b3
-			}
89f6b3
-		}
89f6b3
-
89f6b3
-		if (!printed) {
89f6b3
-			if (tlvid < INVALID_TLVID)
89f6b3
-				printf("Unidentified TLV\n\ttype:%d %*.*s\n",
89f6b3
-					tlv_type, tlv_len*2, tlv_len*2,
89f6b3
-					ibuf+offset);
89f6b3
-			else
89f6b3
-				printf("Unidentified Org Specific TLV\n\t"
89f6b3
-				      "OUI: 0x%06x, Subtype: %d, Info: %*.*s\n",
89f6b3
-					tlvid >> 8, tlvid & 0x0ff,
89f6b3
-					tlv_len*2-8, tlv_len*2-8,
89f6b3
-					ibuf+offset);
89f6b3
-		}
89f6b3
-		if (tlvid > INVALID_TLVID)
89f6b3
-			offset += (2 * tlv_len - 8);
89f6b3
-		else
89f6b3
-			offset += 2 * tlv_len;
89f6b3
-		ilen -= 2 * tlv_len;
89f6b3
-		if (tlvid == END_OF_LLDPDU_TLV)
89f6b3
-			break;
89f6b3
+		strncpy(tmp_ibuf, ibuf + offset, vsi_len);
89f6b3
+		tmp_ibuf[vsi_len] = '\0';
89f6b3
+		printf("%s %d:\n", "VSI ", vsi_cnt);
89f6b3
+		get_vsi_args(tmp_ibuf);
89f6b3
+		offset += vsi_len;
89f6b3
+		ilen -= vsi_len;
89f6b3
+		vsi_cnt++;
89f6b3
 	}
89f6b3
 }
89f6b3
 
89f6b3
-/* Print reply from get command */
89f6b3
-static void print_tlvs(struct cmd *cmd, char *ibuf)
89f6b3
-{
89f6b3
-	if (cmd->ops & op_config) {
89f6b3
-		print_arg_value(ibuf);
89f6b3
-		return;
89f6b3
-	}
89f6b3
-	print_tlv2(ibuf);
89f6b3
-}
89f6b3
-
89f6b3
 static void print_cmd_response(char *ibuf, int status)
89f6b3
 {
89f6b3
 	struct cmd cmd;
89f6b3
@@ -455,7 +385,7 @@ static void print_cmd_response(char *ibuf, int status)
89f6b3
 
89f6b3
 	switch (cmd.cmd) {
89f6b3
 	case cmd_gettlv:
89f6b3
-		print_tlvs(&cmd, ibuf + ioff);
89f6b3
+		print_all_vsis(ibuf + ioff);
89f6b3
 		break;
89f6b3
 	case cmd_settlv:
89f6b3
 		printf("%s", ibuf + ioff);
89f6b3
@@ -708,7 +638,7 @@ static int _clif_command(struct clif *clif, char *cmd, int print)
89f6b3
 	size_t len;
89f6b3
 	int ret;
89f6b3
 	int rc;
89f6b3
-	char reply[100];
89f6b3
+	char reply[200];
89f6b3
 	size_t reply_len2 = sizeof(reply);
89f6b3
 
89f6b3
 	print_raw_message(cmd, print);
89f6b3
-- 
89f6b3
2.1.0
89f6b3