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

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