[lldp-devel] [PATCH 2/3] vdptest support for VDP22 filter information data

Thomas Richter tmricht at linux.vnet.ibm.com
Thu Nov 21 09:26:40 UTC 2013


This adds support for netlink message construction for
IEEE 802.1 QBG VDP protocol draft 0.2 and ratified standard
(draft 2.2). The patch builds on
commit 6efa72c67a7005ff28a927c483be2c3f14114d55 and handles
netlink message construction and receptions. This code
has been completely rewritten.

Returned filter information can be checked against expected
values. A mismatch betwen expected and returned filter
information terminates the test program.

The test program does not use the libnl.a on purpose. This
is done to provide a different method of netlink message
construction and parsing.

Signed-off-by: Thomas Richter <tmricht at linux.vnet.ibm.com>
---
 test/vdptest.c | 1585 +++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 1106 insertions(+), 479 deletions(-)

diff --git a/test/vdptest.c b/test/vdptest.c
index e93fed0..4eedf3e 100644
--- a/test/vdptest.c
+++ b/test/vdptest.c
@@ -29,7 +29,27 @@
  * - associate a VSI
  * - disassociate a VSI
  * - receive a netlink message from lldpad when
- *   - the switch de-associates the VSI profile (switch data base cleaned)
+ *    - the switch de-associates the VSI profile (switch data base cleaned)
+ *
+ * Note:
+ * libvirtd is currently the only production code user of lldpad netlink
+ * interface. It uses
+ * - no qos: always set to 0.
+ * - only one mac/macvlan pair.
+ * - netlink message format 1 (no qos/vlanid change on switch side, no group
+ *   id support at all)
+ *
+ * Netlink message format 1 is the default and does not
+ * - expect vlanid etc back from switch
+ * - use the vsi.maclist.qos member at all.
+ *
+ * Netlink message format 2 is selected when
+ * - group id is entered in the map keyword
+ * - 2mgrid is selected as keyword to specified long manager identifier
+ * - replacement vlan identifier is specified in the map keyword
+ * - hints keyword is specified.
+ * This format handles a reply from the switch and compares returned vlan/qos
+ * values.
  */
 
 #include <stdint.h>
@@ -40,7 +60,10 @@
 #include <errno.h>
 #include <ctype.h>
 #include <stdarg.h>
+#include <time.h>
+#include <stdbool.h>
 
+#include <sys/time.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 
@@ -48,13 +71,14 @@
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
+#include <net/if.h>
 #include <netlink/msg.h>
 
 #include "clif.h"
 #include "clif_msgs.h"
+#include "qbg_vdp22def.h"
+#include "qbg_vdpnl.h"
 
-#define	UUIDLEN			16
-#define	DIM(x)			(sizeof(x)/sizeof(x[0]))
 #define	COPY_OP			"new="
 #define	KEYLEN			16
 #define CMD_ASSOC	'a'	/* Association */
@@ -67,23 +91,645 @@
 #define CMD_EXTERN	'E'	/* External command */
 #define CMD_SETDF	'X'	/* Change defaults */
 
-#define	FIF_VID		1	/* Vlan id */
-#define	FIF_VIDMAC	2	/* Vlan+mac id */
-#define	FIF_GRPVID	3	/* Group+Vlan id */
-#define	FIF_GRPVIDMAC	4	/* group+Vlan+mac id */
+#define	BAD_FILTER	250	/* VLAN error in filter data */
 
-#define	MIGTO		16	/* M-bit migrate to indicator */
-#define	MIGFROM		32	/* S-bit migrate from indicator */
+#define	DIM(x)			(sizeof(x)/sizeof(x[0]))
 
 /*
- * Set the define MYDEBUG to any value for detailed debugging
+ * Helper functions to construct a netlink message.
+ * The functions assume the nlmsghdr.nlmsg_len is set correctly.
  */
+static void mynla_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
+{
+	start->nla_type |= NLA_F_NESTED;
+	start->nla_len = (void *)nlh + nlh->nlmsg_len - (void *)start;
+}
 
-enum {				/* Netlink message format for lldpad */
-	nlmsg_v0 = 1,		/* IEEE 802.1 QBG version 0.2 */
-	nlmsg_v2		/* IEEE 802.1 QBG version 2.2 */
-};
+static struct nlattr *mynla_nest_start(struct nlmsghdr *nlh, int type)
+{
+	struct nlattr *ap = (struct nlattr *)((void *)nlh + nlh->nlmsg_len);
+
+	ap->nla_type = type;
+	nlh->nlmsg_len += NLA_HDRLEN;
+	return ap;
+}
+
+static void mynla_put(struct nlmsghdr *nlh, int type, size_t len, void *data)
+{
+	struct nlattr *ap = (struct nlattr *)((void *)nlh + nlh->nlmsg_len);
+
+	ap->nla_type = type;
+	ap->nla_len = NLA_HDRLEN + len;
+	memcpy(ap + 1, data, len);
+	nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(len);
+}
+
+static void mynla_put_u8(struct nlmsghdr *nlh, int type, __u8 data)
+{
+	mynla_put(nlh, type, sizeof data, &data);
+}
+
+static void mynla_put_u32(struct nlmsghdr *nlh, int type, __u32 data)
+{
+	mynla_put(nlh, type, sizeof data, &data);
+}
+
+static void *mynla_data(const struct nlattr *nla)
+{
+	return (char *)nla + NLA_HDRLEN;
+}
+
+static void mynla_get(const struct nlattr *nla, size_t len, void *data)
+{
+	memcpy(data, mynla_data(nla), len);
+}
+
+static __u32 mynla_get_u32(const struct nlattr *nla)
+{
+	return *(__u32 *)mynla_data(nla);
+}
+
+static __u16 mynla_get_u16(const struct nlattr *nla)
+{
+	return *(__u16 *)mynla_data(nla);
+}
+
+static int mynla_payload(const struct nlattr *nla)
+{
+	return nla->nla_len - NLA_HDRLEN;
+}
 
+static int mynla_type(const struct nlattr *nla)
+{
+	return nla->nla_type & ~NLA_F_NESTED;
+}
+
+static int mynla_ok(const struct nlattr *nla, int rest)
+{
+	return rest >= (int) sizeof(*nla) &&
+	       nla->nla_len >= sizeof(*nla) && nla->nla_len <= rest;
+}
+
+static struct nlattr *mynla_next(const struct nlattr *nla, int *rest)
+{
+	int len = NLA_ALIGN(nla->nla_len);
+
+	*rest -= len;
+	return (struct nlattr *)((char *)nla + len);
+}
+
+static inline int mynla_attr_size(int payload)
+{
+	return NLA_HDRLEN + payload;
+}
+
+static int mynla_total_size(int payload)
+{
+	return NLA_ALIGN(mynla_attr_size(payload));
+}
+
+/*
+ * Parse a list of netlink attributes.
+ * Return 0 on success and errno when the parsing fails.
+ */
+static int mynla_parse(struct nlattr **tb, size_t tb_len, struct nlattr *pos,
+		       int attrlen)
+{
+	unsigned short nla_type;
+
+	while (mynla_ok(pos, attrlen)) {
+		nla_type = mynla_type(pos);
+		if (nla_type < tb_len)
+			tb[nla_type] = (struct nlattr *)pos;
+		pos = mynla_next(pos, &attrlen);
+	}
+	return (attrlen) ? -EINVAL : 0;
+}
+
+
+/*
+ * Return needed buffer space in bytes to construct netlink message setlink
+ * request. Return the maximum size needed.
+ * In netlink message format 1 only one MAC/VLAN pair is supported.
+ * In netlink message format 2 many MAC/VLAN/group pairs are supported.
+ */
+static size_t nlvsi_getsize(struct vdpnl_vsi *vsip)
+{
+	return NLMSG_SPACE(sizeof(struct ifinfomsg))	/* Header */
+		+ mynla_total_size(IFNAMSIZ + 1)	/* IFLA_IFNAME */
+		+ mynla_total_size(sizeof(struct nlattr)) /* IFLA_VF_PORTS */
+		+ mynla_total_size(4)		/* VF_PORTS */
+		+ mynla_total_size(4)		/* VF_PORT */
+		+ mynla_total_size(1)		/* PORT_VDP_REQUEST */
+		+ mynla_total_size(2)		/* PORT_VDP_RESPONSE */
+		+ mynla_total_size(PORT_UUID_MAX)	/* INSTANCE UUID */
+		+ mynla_total_size(sizeof(struct ifla_port_vsi))
+						/* VSI_TYPE */
+		+ mynla_total_size(sizeof(struct nlattr))
+						/* IFLA_VFINFO_LIST */
+		+ mynla_total_size(sizeof(struct nlattr))
+						/* IFLA_VF_INFO */
+		+ mynla_total_size(sizeof(struct ifla_vf_mac))
+						/* IFLA_VF_MAC */
+		+ mynla_total_size(sizeof(struct ifla_vf_vlan ))
+						/* IFLA_VF_VLAN */
+		+ mynla_total_size(sizeof(struct ifla_port_vsi22))
+		+ mynla_total_size(vsip->macsz
+					* sizeof(struct ifla_port_vsi_filter));
+}
+
+/*
+ * Test input and return false on error.
+ */
+static int nlvsi_isgood(struct vdpnl_vsi *vsip)
+{
+	if (!vsip->macsz)
+		return 0;
+	switch (vsip->filter_fmt) {
+	case VDP22_FFMT_MACVID:
+	case VDP22_FFMT_VID:
+	case VDP22_FFMT_GROUPMACVID:
+	case VDP22_FFMT_GROUPVID:
+		break;
+	default:
+		return 0;
+	}
+
+	/*
+	 * Adjust for different request numbering.
+	 * Draft 0.2 starts from 0 and ratified standard starts from 1.
+	 * Sequence is PREASSOC, PREASSOC_RR, ASSOC, DEASSOC
+	 *
+	 * Expect "offical" draft 0.2 numbering defined in
+	 * /usr/include/linux/if_link.h
+	 */
+	switch (vsip->request + 1) {
+	case VDP22_PREASSOC:
+	case VDP22_PREASSOC_WITH_RR:
+	case VDP22_ASSOC:
+	case VDP22_DEASSOC:
+		break;
+	default:
+		return 0;
+	}
+
+	switch (vsip->vsiid_fmt) {
+	case VDP22_ID_IP4:
+	case VDP22_ID_IP6:
+	case VDP22_ID_MAC:
+	case VDP22_ID_LOCAL:
+	case VDP22_ID_UUID:
+		break;
+	default:
+		return 0;
+	}
+
+	if (vsip->hints && (vsip->hints != VDP22_MIGTO
+	    && vsip->hints != VDP22_MIGFROM))
+		return 0;
+
+	if (vsip->vsi_typeid >= (1 << 24))	/* 3 byte type identifier */
+		return 0;
+	return 1;
+}
+
+/*
+ * Build netlink message 1 format.
+ */
+static void nlf1(struct vdpnl_vsi *vsip, struct nlmsghdr *nlh)
+{
+	struct nlattr *port, *ports;
+	struct ifla_port_vsi myvsi;
+	int i;
+
+	ports = mynla_nest_start(nlh, IFLA_VF_PORTS);
+	port = mynla_nest_start(nlh, IFLA_VF_PORT);
+	mynla_put_u8(nlh, IFLA_PORT_REQUEST, vsip->request);
+	memset(&myvsi, 0, sizeof(myvsi));
+	myvsi.vsi_mgr_id = vsip->vsi_mgrid;
+	myvsi.vsi_type_id[2] = (vsip->vsi_typeid >> 16) & 0xff;
+	myvsi.vsi_type_id[1] = (vsip->vsi_typeid >> 8) & 0xff;
+	myvsi.vsi_type_id[0] = vsip->vsi_typeid & 0xff;
+	myvsi.vsi_type_version = vsip->vsi_typeversion;
+	mynla_put(nlh, IFLA_PORT_VSI_TYPE, sizeof(myvsi), &myvsi);
+	mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsip->vsi_uuid);
+	mynla_nest_end(nlh, port);
+	mynla_nest_end(nlh, ports);
+
+	ports = mynla_nest_start(nlh, IFLA_VFINFO_LIST);
+	for (i = 0; i < vsip->macsz; ++i) {
+		port = mynla_nest_start(nlh, IFLA_VF_INFO);
+		if (vsip->filter_fmt == VDP22_FFMT_MACVID) {
+			struct ifla_vf_mac vf_mac = {
+				.vf = PORT_SELF_VF
+			};
+
+			memcpy(vf_mac.mac, vsip->maclist[i].mac, ETH_ALEN);
+			mynla_put(nlh, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac);
+		}
+		if (vsip->filter_fmt) {
+			struct ifla_vf_vlan vf_vlan = {
+				.vf = PORT_SELF_VF,
+				.vlan = vsip->maclist[i].vlan & 0xfff,
+				.qos = (vsip->maclist[i].vlan >> 12) & 7
+			};
+
+			mynla_put(nlh, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan);
+		}
+		mynla_nest_end(nlh, port);
+	}
+	mynla_nest_end(nlh, ports);
+}
+
+/*
+ * Build netlink message 2 format.
+ */
+static void nlf2(struct vdpnl_vsi *vsip, struct nlmsghdr *nlh)
+{
+	struct ifla_port_vsi22 myvsi;
+	struct ifla_port_vsi_filter fdata[vsip->macsz];
+	struct nlattr *port, *ports;
+	int i;
+
+	memset(&myvsi, 0, sizeof(myvsi));
+	memset(fdata, 0, sizeof(fdata));
+	ports = mynla_nest_start(nlh, IFLA_VF_PORTS);
+	port = mynla_nest_start(nlh, IFLA_VF_PORT);
+	mynla_put_u32(nlh, IFLA_PORT_VF, vsip->vf);
+	mynla_put_u8(nlh, IFLA_PORT_REQUEST, vsip->request);
+	mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsip->vsi_uuid);
+	myvsi.vsi_type_id[2] = (vsip->vsi_typeid >> 16) & 0xff;
+	myvsi.vsi_type_id[1] = (vsip->vsi_typeid >> 8) & 0xff;
+	myvsi.vsi_type_id[0] = vsip->vsi_typeid & 0xff;
+	myvsi.vsi_type_version = vsip->vsi_typeversion;
+	myvsi.vsi_uuidfmt = vsip->vsiid_fmt;
+	memcpy(myvsi.vsi_mgrid, vsip->vsi_mgrid2, sizeof(myvsi.vsi_mgrid));
+	myvsi.vsi_hints = vsip->hints;
+	myvsi.vsi_filter_fmt = vsip->filter_fmt;
+	myvsi.vsi_filter_num = vsip->macsz;
+	mynla_put(nlh, IFLA_PORT_VSI_TYPE22, sizeof(myvsi), &myvsi);
+	for (i = 0; i < vsip->macsz; ++i) {
+		struct ifla_port_vsi_filter *ep = &fdata[i];
+
+		ep->vlanid = vsip->maclist[i].vlan;
+		if (vsip->filter_fmt == VDP22_FFMT_MACVID
+		    || vsip->filter_fmt == VDP22_FFMT_GROUPMACVID)
+			memcpy(ep->mac, vsip->maclist[i].mac, sizeof(ep->mac));
+		if (vsip->filter_fmt == VDP22_FFMT_GROUPVID
+		    || vsip->filter_fmt == VDP22_FFMT_GROUPMACVID)
+			ep->gpid = vsip->maclist[i].gpid;
+	}
+	mynla_put(nlh, IFLA_PORT_VSI_FILTER, sizeof(fdata), fdata);
+	mynla_nest_end(nlh, port);
+	mynla_nest_end(nlh, ports);
+}
+
+/*
+ * Construct the netlink request message for the VSI profile.
+ * Return number of bytes occupied in buffer or errno on error.
+ */
+static int vdpnl_request_build(struct vdpnl_vsi *vsip, unsigned char *buf,
+			       size_t len)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+	struct ifinfomsg ifinfo;
+
+	if (!nlvsi_isgood(vsip))
+		return -EINVAL;
+	if (nlvsi_getsize(vsip) > len)
+		return -ENOMEM;
+	memset(buf, 0, len);
+	memset(&ifinfo, 0, sizeof(ifinfo));
+	nlh->nlmsg_type = RTM_SETLINK;
+	nlh->nlmsg_pid = getpid();
+	nlh->nlmsg_seq = vsip->req_seq;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+	nlh->nlmsg_len = NLMSG_SPACE(sizeof ifinfo);
+	ifinfo.ifi_index = vsip->ifindex;
+	ifinfo.ifi_family = AF_UNSPEC;
+	memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof(ifinfo));
+	mynla_put(nlh, IFLA_IFNAME, 1 + strlen(vsip->ifname), vsip->ifname);
+	if (vsip->nl_version == vdpnl_nlf2)
+		nlf2(vsip, nlh);
+	else
+		nlf1(vsip, nlh);
+	return nlh->nlmsg_len;
+}
+
+/*
+ * Read the contents of the IFLA_PORT_VSI_FILTER netlink attribute.
+ * It is an array of struct ifla_port_vsi_filter entries.
+ * Return 0 on success and errno on failure.
+ *
+ * Code to parse netlink message format 2.
+ */
+static void parse_filter_data(struct vdpnl_vsi *vsip, struct nlattr *tb)
+{
+	int i = 0;
+	struct ifla_port_vsi_filter elem[vsip->macsz];
+
+	mynla_get(tb, sizeof(elem), elem);
+	for (i = 0; i < vsip->macsz; ++i) {
+		struct vdpnl_mac *macp = &vsip->maclist[i];
+		struct ifla_port_vsi_filter *ep = &elem[i];
+
+		macp->vlan = ep->vlanid;
+		macp->gpid = ep->gpid;
+		memcpy(macp->mac, ep->mac, sizeof(macp->mac));
+	}
+}
+
+/*
+ * Read the contents of the IFLA_PORT_VSI_FILTER netlink attribute.
+ * Return 0 on success and errno on failure.
+ *
+ * Code to parse netlink message format 2.
+ */
+static int parse_vsi_type22(struct vdpnl_vsi *vsip, struct nlattr *tb,
+			    struct nlattr *tc)
+{
+	struct ifla_port_vsi22 myvsi;
+
+	mynla_get(tb, sizeof(myvsi), &myvsi);
+	vsip->filter_fmt = myvsi.vsi_filter_fmt;
+	if (vsip->macsz >= myvsi.vsi_filter_num) {
+		vsip->macsz = myvsi.vsi_filter_num;
+		parse_filter_data(vsip, tc);
+		return 0;
+	}
+	return -E2BIG;
+}
+
+/*
+ * Parse the IFLA_VF_PORT block of the netlink message.
+ * Return 1 when uuid found and 0 when not found and errno else.
+ * Set length of filter pair on return.
+ *
+ * Code to parse netlink message format 1.
+ */
+static int scan_vf_port(struct vdpnl_vsi *vsi, struct nlattr *tb)
+{
+	struct nlattr *vf[IFLA_PORT_MAX + 1];
+	int found = 0, rc;
+
+	memset(vf, 0, sizeof(vf));
+	rc = mynla_parse(vf, DIM(vf), mynla_data(tb), mynla_payload(tb));
+	if (rc)
+		return -EINVAL;
+	if (vf[IFLA_PORT_INSTANCE_UUID]) {
+		if (!memcmp(mynla_data(vf[IFLA_PORT_INSTANCE_UUID]),
+			    vsi->vsi_uuid, sizeof(vsi->vsi_uuid))
+		     && vf[IFLA_PORT_RESPONSE]) {
+			found = 1;
+			vsi->response = mynla_get_u16(vf[IFLA_PORT_RESPONSE]);
+		}
+	} else
+		return -EINVAL;
+	if (found && vf[IFLA_PORT_VSI_TYPE22] && vf[IFLA_PORT_VSI_FILTER])
+		rc = parse_vsi_type22(vsi, vf[IFLA_PORT_VSI_TYPE22],
+				      vf[IFLA_PORT_VSI_FILTER]);
+	else
+		vsi->macsz = 0;
+	return found;
+}
+
+/*
+ * Parse the IFLA_VF_PORTS block of the netlink message. Expect many
+ * IFLA_VF_PORT attribute and search the one we are looking for.
+ * Return zero on success and errno else.
+ *
+ * Code to parse netlink message format 1.
+ */
+static int scan_vf_ports(struct vdpnl_vsi *vsi, struct nlattr *tb)
+{
+	struct nlattr *pos;
+	int rest, rc = 0;
+
+	for (rest = mynla_payload(tb), pos = mynla_data(tb);
+		mynla_ok(pos, rest) && rc == 0; pos = mynla_next(pos, &rest)) {
+		if (mynla_type(pos) == IFLA_VF_PORT)
+			rc = scan_vf_port(vsi, pos);
+		else
+			rc = -EINVAL;
+	}
+	return rc;
+}
+
+/*
+ * Scan the GETLINK reply and parse the response for the UUID.
+ *
+ * Return
+ * < 0 on error
+ * 0 wanted UUID not in reply
+ * 1 found
+ */
+static int vdpnl_getreply_parse(struct vdpnl_vsi *p, unsigned char *buf,
+		size_t len)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+	struct nlattr *tb[IFLA_MAX + 1];
+	int rc;
+
+	if (len < nlh->nlmsg_len)
+		return -ENOMEM;
+	memset(tb, 0, sizeof(tb));
+	rc = mynla_parse(tb, DIM(tb),
+			 (struct nlattr *)IFLA_RTA(NLMSG_DATA(nlh)),
+			 IFLA_PAYLOAD(nlh));
+	if (rc || !tb[IFLA_VF_PORTS])
+		return -EINVAL;
+	return scan_vf_ports(p, tb[IFLA_VF_PORTS]);
+}
+
+/*
+ * Parse a received netlink request message and check for errors.
+ * When a netlink error message is received, return it in the 3rd
+ * parameter.
+ *
+ * Return
+ * <0 on parse error.
+ * 1 when a netlink error response is received.
+ * 0 when no netlink error response
+ */
+static int vdpnl_getreply_error(unsigned char *buf, size_t len, int *error)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+
+	if (len < nlh->nlmsg_len)
+		return -ENOMEM;
+	if (nlh->nlmsg_type == NLMSG_ERROR) {
+		struct nlmsgerr *err = NLMSG_DATA(nlh);
+
+		if (error)
+			*error = err->error;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Parse the IFLA_VF_PORT block of an unsolicited netlink message triggered
+ * after a dis-associated from switch.
+ * Set length of filter pair on return.
+ *
+ * Code to parse netlink message format 1.
+ */
+static int trigger_vf_port(struct vdpnl_vsi *vsi, struct nlattr *tb)
+{
+	struct nlattr *vf[IFLA_PORT_MAX + 1];
+	int rc;
+	struct ifla_port_vsi portvsi;
+
+	memset(vf, 0, sizeof(vf));
+	rc = mynla_parse(vf, DIM(vf), mynla_data(tb), mynla_payload(tb));
+	if (rc)
+		return -EINVAL;
+	if (vf[IFLA_PORT_INSTANCE_UUID])
+		mynla_get(vf[IFLA_PORT_INSTANCE_UUID], sizeof(vsi->vsi_uuid),
+			  vsi->vsi_uuid);
+	else
+		return -EINVAL;
+	if (vf[IFLA_PORT_REQUEST])
+		vsi->response = mynla_get_u16(vf[IFLA_PORT_REQUEST]);
+	else
+		return -EINVAL;
+	if (vf[IFLA_PORT_VF])
+		vsi->vf = mynla_get_u32(vf[IFLA_PORT_VF]);
+	else
+		return -EINVAL;
+	if (vf[IFLA_PORT_VSI_TYPE]) {
+		mynla_get(vf[IFLA_PORT_VSI_TYPE], sizeof portvsi, &portvsi);
+		vsi->vsi_mgrid = portvsi.vsi_mgr_id;
+		vsi->vsi_typeversion = portvsi.vsi_type_version;
+		vsi->vsi_typeid = portvsi.vsi_type_id[0] << 16
+				  | portvsi.vsi_type_id[1] << 8
+				  | portvsi.vsi_type_id[2] << 8;
+	} else
+		return -EINVAL;
+	vsi->macsz = 0;		/* No returned filter data */
+	return 0;
+}
+
+/*
+ * Parse the IFLA_VF_PORTS block of the netlink message. Expect many
+ * IFLA_VF_PORT attribute and search the one we are looking for.
+ * Return zero on success and errno else.
+ *
+ * Code to parse netlink message format 1.
+ */
+static int trigger_vf_ports(struct vdpnl_vsi *vsi, struct nlattr *tb)
+{
+	struct nlattr *pos;
+	int rest, rc = 0;
+
+	for (rest = mynla_payload(tb), pos = mynla_data(tb);
+		mynla_ok(pos, rest) && rc == 0; pos = mynla_next(pos, &rest)) {
+		if (mynla_type(pos) == IFLA_VF_PORT)
+			rc = trigger_vf_port(vsi, pos);
+		else
+			rc = -EINVAL;
+	}
+	return rc;
+}
+
+/*
+ * Parse the IFLA_VF_INFO block.
+ */
+static int trigger_vf_info(struct vdpnl_mac *p, struct nlattr *tb)
+{
+	struct nlattr *vf[IFLA_VF_MAX + 1];
+	struct ifla_vf_mac ifla_vf_mac;
+	struct ifla_vf_vlan ifla_vf_vlan;
+	int rc;
+
+	memset(vf, 0, sizeof(vf));
+	memset(&ifla_vf_mac, 0, sizeof(ifla_vf_mac));
+	memset(&ifla_vf_vlan, 0, sizeof(ifla_vf_vlan));
+	rc = mynla_parse(vf, DIM(vf), mynla_data(tb), mynla_payload(tb));
+	if (rc)
+		return -EINVAL;
+	if (vf[IFLA_VF_MAC]) {
+		mynla_get(vf[IFLA_VF_MAC], sizeof ifla_vf_mac, &ifla_vf_mac);
+		memcpy(p->mac, ifla_vf_mac.mac, sizeof(p->mac));
+	} else
+		return -EINVAL;
+	if (vf[IFLA_VF_VLAN]) {
+		mynla_get(vf[IFLA_VF_VLAN], sizeof ifla_vf_vlan, &ifla_vf_vlan);
+		p->vlan = ifla_vf_vlan.vlan & 0xfff;
+		p->qos = ifla_vf_vlan.qos & 0xf;
+	} else
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ * Parse the IFLA_VFINFO_LIST block which contains blocks of VF_INFO blocks.
+ */
+static int trigger_vfinfo_list(struct vdpnl_vsi *p, struct nlattr *tb)
+{
+	struct nlattr *pos;
+	int i = 0, rest, rc = 0;
+
+	if (p->macsz)		/* This must be netlink format 2 */
+		return -EINVAL;
+	for (rest = mynla_payload(tb), pos = mynla_data(tb);
+		mynla_ok(pos, rest); pos = mynla_next(pos, &rest)) {
+		++p->macsz;
+	}
+	if (!p->macsz)		/* No VLAN/MAC pair */
+		return -EINVAL;
+	p->maclist = calloc(p->macsz, sizeof(*p->maclist));
+	if (!p->maclist) {
+		p->macsz = 0;
+		return -ENOMEM;
+	}
+	for (rest = mynla_payload(tb), pos = mynla_data(tb);
+			mynla_ok(pos, rest) && rc == 0;
+					++i, pos = mynla_next(pos, &rest)) {
+		if (mynla_type(pos) == IFLA_VF_INFO)
+			rc = trigger_vf_info(&p->maclist[i], pos);
+		else
+			rc = -EINVAL;
+	}
+	if (rc) {
+		free(p->maclist);
+		p->maclist = NULL;
+		p->macsz = 0;
+	}
+	return rc;
+}
+
+/*
+ * Scan an unsolicited message from lldpad and parse the response for the UUID.
+ *
+ * Return
+ * < 0 on error
+ * 0 success
+ */
+static int vdpnl_trigger_parse(struct vdpnl_vsi *p, unsigned char *buf,
+				size_t len)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+	struct nlattr *tb[IFLA_MAX + 1];
+	int rc;
+
+	if (len < nlh->nlmsg_len)
+		return -ENOMEM;
+	memset(tb, 0, sizeof(tb));
+	rc = mynla_parse(tb, DIM(tb),
+			 (struct nlattr *)IFLA_RTA(NLMSG_DATA(nlh)),
+			 IFLA_PAYLOAD(nlh));
+	if (rc || !tb[IFLA_VF_PORTS] || !tb[IFLA_IFNAME]
+	    || !tb[IFLA_VFINFO_LIST])
+		return -EINVAL;
+	mynla_get(tb[IFLA_IFNAME], sizeof(p->ifname), p->ifname);
+	return trigger_vf_ports(p, tb[IFLA_VF_PORTS])
+		| trigger_vfinfo_list(p, tb[IFLA_VFINFO_LIST]);
+}
+
+/*
+ * Code for construction vdp protocol messages.
+ */
 enum {
 	f_map,
 	f_mgrid,
@@ -94,11 +740,18 @@ enum {
 	f_2mgrid
 };
 
+enum {
+	fid_clr = 0,			/* Returned filter check */
+	fid_ok = 1,			/* Filter changed ok */
+	fid_mod = 2			/* Filter modified unexpectedly */
+};
+
 struct macvlan {
 	unsigned char mac[ETH_ALEN];	/* MAC address */
 	unsigned short vlanid;		/* VLAN Id */
 	unsigned long gpid;		/* Group */
 	unsigned short newvid;		/* New vlan id returned from switch */
+	unsigned char flags;		/* Tested? */
 };
 
 static struct vdpdata {
@@ -108,14 +761,21 @@ static struct vdpdata {
 	unsigned char mgrid;	/* Manager ID */
 	unsigned char typeidver;	/* Type ID version */
 	unsigned int typeid;	/* Type ID */
-	unsigned char uuid[UUIDLEN];	/* Instance ID */
-	unsigned char mgrid2[UUIDLEN];	/* Manager ID VDP22 */
+	unsigned char uuid[PORT_UUID_MAX];	/* Instance ID */
+	unsigned char mgrid2[PORT_UUID_MAX];	/* Manager ID VDP22 */
 	struct macvlan addr[10];	/* Pairs of MAC/VLAN */
 	unsigned char fif;	/* Filter info format */
 	unsigned char hints;	/* Migrate to/from hits */
 	unsigned char nlmsg_v;	/* Version of netlink messaage to use */
 } vsidata[32];
 
+struct vdpback {			/* Reply data from lldpad */
+	unsigned char uuid[PORT_UUID_MAX];	/* Instance ID */
+	unsigned short resp;		/* Response */
+	unsigned char pairs;		/* # of returned VLAN */
+	struct macvlan addr[10];	/* Pairs of MAC/VLAN */
+};
+
 static struct command {		/* Command structure */
 	char key[KEYLEN];	/* Name of profile to use */
 	unsigned int waittime;	/* Time (in secs) to wait after cmd */
@@ -125,6 +785,7 @@ static struct command {		/* Command structure */
 	unsigned char no_err;	/* # of expected errors */
 	int errors[4];		/* Expected errors */
 	int rc;			/* Encountered error */
+	int sys_rc;		/* System error on send/receive of messages */
 	char *text;		/* Text to display */
 } cmds[32], defaults = {	/* Default values in structure */
 	.waittime = 1,
@@ -140,24 +801,6 @@ static int ifindex;		/* Index of ifname */
 static char *ifname;		/* Interface to operate on */
 static pid_t lldpad;		/* LLDPAD process identifier */
 static int my_sock;		/* Netlink socket for lldpad talk */
-static char mybuf[1024];	/* Buffer for netlink message decode */
-
-static struct nla_policy ifla_vf_policy[IFLA_VF_MAX + 1] = {
-	[IFLA_VF_MAC] = {
-		.minlen = sizeof(struct ifla_vf_mac),
-		.maxlen = sizeof(struct ifla_vf_mac)
-	},
-	[IFLA_VF_VLAN] = {
-		.minlen = sizeof(struct ifla_vf_vlan),
-		.maxlen = sizeof(struct ifla_vf_vlan)
-	}
-};
-
-static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = {
-	[IFLA_PORT_RESPONSE] = {
-		.type = NLA_U16
-	}
-};
 
 static void uuid2buf(const unsigned char *p, char *buf)
 {
@@ -167,167 +810,94 @@ static void uuid2buf(const unsigned char *p, char *buf)
 		p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
 }
 
-static int addit(char *format, ...)
+#if 0
+static void showmac(struct vdpnl_vsi *p)
 {
-	size_t left = strlen(mybuf);
-	int c;
-	va_list ap;
+	int i;
+	struct vdpnl_mac *macp = p->maclist;
 
-	va_start(ap, format);
-	c = vsnprintf(mybuf + left, sizeof mybuf - left, format, ap);
-	va_end(ap);
-	return (c < 0 || ((unsigned)c >= sizeof mybuf - left)) ? -1 : 0;
+	for (i = 0; i < p->macsz; ++i, ++macp)
+		printf("\tvlan:%hd qos:%d\n", macp->vlan, macp->qos);
 }
+#endif
 
-static int showerror(struct nlmsghdr *nlh)
+static int test_new(unsigned short new, unsigned short me)
 {
-	struct nlmsgerr *err = NLMSG_DATA(nlh);
+	unsigned short new_vlan = (new & 0xfff);
+	unsigned char new_qos = (new >> 12) & 0xf;
+	unsigned short vlan = (me & 0xfff);
+	unsigned char qos = (me >> 12) & 0xf;
 
-	if (verbose)
-		printf("%s setlink response:%d\n", progname, err->error);
-	return err->error;
+	return (vlan == new_vlan && qos == new_qos);
 }
 
-static void parse_vfinfolist(struct nlattr *vfinfolist)
+static void expect_fid(struct vdpdata *vdp)
 {
-	struct nlattr *le1, *vf[IFLA_VF_MAX + 1];
-	int rem;
-
-	addit("\tfound IFLA_VFINFO_LIST!\n");
-	nla_for_each_nested(le1, vfinfolist, rem) {
-		if (nla_type(le1) != IFLA_VF_INFO) {
-			fprintf(stderr, "%s nested parsing of"
-			    "IFLA_VFINFO_LIST failed\n", progname);
-			return;
-		}
-		if (nla_parse_nested(vf, IFLA_VF_MAX, le1, ifla_vf_policy)) {
-			fprintf(stderr, "%s nested parsing of "
-			    "IFLA_VF_INFO failed\n", progname);
-			return;
-		}
-
-		if (vf[IFLA_VF_MAC]) {
-			struct ifla_vf_mac *mac = RTA_DATA(vf[IFLA_VF_MAC]);
-			unsigned char *m = mac->mac;
+	int i;
+	struct macvlan *mac = vdp->addr;
 
-			addit("\tIFLA_VF_MAC=%02x:%02x:%02x:"
-			    " %02x:%02x:%02x\n",
-			    m[0], m[1], m[2], m[3], m[4], m[5]);
-		}
+	printf(" expected");
+	for (i = 0; i < vdp->pairs; ++i, ++mac)
+		if( mac->flags == fid_clr)
+			printf(" [%hu,%hu]",
+				(mac->newvid ?: mac->vlanid) & 0xfff,
+				(mac->newvid ?: mac->vlanid) >> 12 & 0xf);
+}
 
-		if (vf[IFLA_VF_VLAN]) {
-			struct ifla_vf_vlan *vlan = RTA_DATA(vf[IFLA_VF_VLAN]);
+static int test_fid(struct vdpnl_mac *new, struct vdpdata *vdp)
+{
+	int i;
+	struct macvlan *mac = vdp->addr;
 
-			addit("\tIFLA_VF_VLAN=%d\n", vlan->vlan);
+	for (i = 0; i < vdp->pairs; ++i, ++mac) {
+		if (mac->flags == fid_clr) {
+			if (test_new(new->vlan, mac->newvid ?: mac->vlanid)) {
+				mac->flags = fid_ok;
+				return 0;
+			}
 		}
 	}
+	return BAD_FILTER;
 }
 
-static void show_nlas(struct nlattr **tb, int max)
+static int compare_fid(struct vdpnl_vsi *back, struct vdpdata *vdp)
 {
-	int rem;
+	int rc = 0, i;
 
-	for (rem = 0; rem < max; ++rem) {
-		if (tb[rem])
-			printf("nlattr %02d type:%d len:%d\n", rem,
-			    tb[rem]->nla_type, tb[rem]->nla_len);
+	for (i = 0; i < vdp->pairs; ++i)
+		vdp->addr[i].flags = fid_clr;
+	/*
+	 * Check each returned filter data. Should be in the list of newvid.
+	 */
+	for (i = 0; rc == 0 && i < back->macsz; ++i) {
+		rc |= test_fid(&back->maclist[i], vdp);
+		if (verbose >= 3) {
+			printf("%s fid:%d vlan:%hu qos:%hu",
+				progname, i, back->maclist[i].vlan & 0xfff,
+				(back->maclist[i].vlan >> 12) & 0xf);
+			if (rc)
+				expect_fid(vdp);
+			else
+				printf(" match ok");
+			printf("\n");
+		}
 	}
+	return rc;
 }
 
-static void showmsg(struct nlmsghdr *nlh, int *status)
+static int compare_vsi(struct vdpnl_vsi *p, struct vdpdata *vdp)
 {
-	struct nlattr *tb[IFLA_MAX + 1], *tb3[IFLA_PORT_MAX + 1];
-	struct ifinfomsg ifinfo;
-	char *ifname;
-	int rem;
-
-	if (status)
-		*status = -1;
-	if (nlh->nlmsg_type == NLMSG_ERROR) {
-		if (status)
-			*status = showerror(nlh);
-		return;
-	}
-	memset(mybuf, 0, sizeof mybuf);
-	addit("\tnlh.nl_pid:%d nlh_type:%d nlh_seq:%#x nlh_len:%#x\n",
-	    nlh->nlmsg_pid, nlh->nlmsg_type, nlh->nlmsg_seq, nlh->nlmsg_len);
-	memcpy(&ifinfo, NLMSG_DATA(nlh), sizeof ifinfo);
-	addit("\tifinfo.family:%#x type:%#x index:%d flags:%#x change:%#x\n",
-	    ifinfo.ifi_family, ifinfo.ifi_type, ifinfo.ifi_index,
-	    ifinfo.ifi_flags, ifinfo.ifi_change);
-	if (nlmsg_parse(nlh, sizeof ifinfo,
-		(struct nlattr **)&tb, IFLA_MAX, NULL)) {
-		fprintf(stderr, "%s error parsing request...\n", progname);
-		return;
-	}
-	if (verbose >= 3)
-		show_nlas(tb, IFLA_MAX);
-	if (tb[IFLA_IFNAME]) {
-		ifname = (char *)RTA_DATA(tb[IFLA_IFNAME]);
-		addit("\tIFLA_IFNAME=%s\n", ifname);
-	}
-	if (tb[IFLA_OPERSTATE]) {
-		rem = *(unsigned short *)RTA_DATA(tb[IFLA_OPERSTATE]);
-		addit("\tIFLA_OPERSTATE=%d\n", rem);
-	}
-	if (tb[IFLA_VFINFO_LIST])
-		parse_vfinfolist(tb[IFLA_VFINFO_LIST]);
-	if (tb[IFLA_VF_PORTS]) {
-		struct nlattr *tb_vf_ports;
+	int rc = 0;
 
-		addit("\tfound IFLA_VF_PORTS\n");
-		nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) {
+	if (verbose >= 2) {
+		char uuidbuf[64];
 
-			if (nla_type(tb_vf_ports) != IFLA_VF_PORT) {
-				fprintf(stderr, "%s not a IFLA_VF_PORT, "
-				    " skipping\n", progname);
-				continue;
-			}
-			if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports,
-				ifla_port_policy)) {
-				fprintf(stderr, "%s nested parsing on level 2"
-				    " failed\n", progname);
-			}
-			if (tb3[IFLA_PORT_VF])
-				addit("\tIFLA_PORT_VF=%d\n",
-				    *(uint32_t *) RTA_DATA(tb3[IFLA_PORT_VF]));
-			if (tb3[IFLA_PORT_VSI_TYPE]) {
-				struct ifla_port_vsi *pvsi;
-				int tid = 0;
-
-				pvsi = (struct ifla_port_vsi *)
-				    RTA_DATA(tb3[IFLA_PORT_VSI_TYPE]);
-				tid = pvsi->vsi_type_id[2] << 16 |
-				    pvsi->vsi_type_id[1] << 8 |
-				    pvsi->vsi_type_id[0];
-				addit("\tIFLA_PORT_VSI_TYPE=mgr_id:%d "
-				    " type_id:%d typeid_version:%d\n",
-				    pvsi->vsi_mgr_id, tid,
-				    pvsi->vsi_type_version);
-			}
-			if (tb3[IFLA_PORT_INSTANCE_UUID]) {
-				char uuidbuf[64];
-				unsigned char *uuid;
-
-				uuid = (unsigned char *)
-				    RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]);
-				uuid2buf(uuid, uuidbuf);
-				addit("\tIFLA_PORT_INSTANCE_UUID=%s\n",
-				    uuidbuf);
-			}
-			if (tb3[IFLA_PORT_REQUEST])
-				addit("\tIFLA_PORT_REQUEST=%d\n", *(uint8_t *)
-				    RTA_DATA(tb3[IFLA_PORT_REQUEST]));
-			if (tb3[IFLA_PORT_RESPONSE]) {
-				addit("\tIFLA_PORT_RESPONSE=%d\n", *(uint16_t *)
-				    RTA_DATA(tb3[IFLA_PORT_RESPONSE]));
-				*status = *(int *)
-				    RTA_DATA(tb3[IFLA_PORT_RESPONSE]);
-			}
-		}
+		uuid2buf(p->vsi_uuid, uuidbuf);
+		printf("%s uuid:%s response:%d no_vlanid:%hd\n", progname,
+			uuidbuf, p->response, p->macsz);
 	}
-	if (verbose >= 2)
-		printf("%s", mybuf);
+	rc = compare_fid(p, vdp);
+	return rc;
 }
 
 /*
@@ -335,35 +905,38 @@ static void showmsg(struct nlmsghdr *nlh, int *status)
  *
  * Return number of bytes received. 0 means timeout and -1 on error.
  */
-static int waitmsg(struct command *cp, int *status)
+static int lldp_waitmsg(int waittime, unsigned char *msgbuf, size_t msgbuf_len)
 {
-	struct msghdr msg;
+	struct timeval tv1, tv2, tv_res;
 	struct sockaddr_nl dest_addr;
-	struct iovec iov;
-	unsigned char msgbuf[1024];
-	struct nlmsghdr *nlh = (struct nlmsghdr *)msgbuf;
+	struct iovec iov = {
+		.iov_base = msgbuf,
+		.iov_len = msgbuf_len
+	};
+	struct msghdr msg = {
+		.msg_name = &dest_addr,
+		.msg_namelen = sizeof(dest_addr),
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+		.msg_controllen = 0,
+		.msg_control = 0
+	};
 	int n, result = 0;
 	fd_set readfds;
 
 	struct timeval tv = {
-		.tv_sec = cp->waittime
+		.tv_sec = waittime
 	};
 
-	memset(&msgbuf, 0, sizeof msgbuf);
-	memset(&dest_addr, 0, sizeof dest_addr);
-	iov.iov_base = (void *)nlh;
-	iov.iov_len = sizeof msgbuf;
-	msg.msg_name = (void *)&dest_addr;
-	msg.msg_namelen = sizeof(dest_addr);
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-
 	if (verbose)
 		printf("%s Waiting %d seconds for message...\n", progname,
-		    cp->waittime);
+		    waittime);
 	FD_ZERO(&readfds);
 	FD_SET(my_sock, &readfds);
+	gettimeofday(&tv1, NULL);
 	n = select(my_sock + 1, &readfds, NULL, NULL, &tv);
+	gettimeofday(&tv2, NULL);
+	timersub(&tv2, &tv1, &tv_res);
 	if (n <= 0) {
 		if (n < 0)
 			fprintf(stderr, "%s error netlink socket:%s\n",
@@ -374,88 +947,119 @@ static int waitmsg(struct command *cp, int *status)
 				    progname);
 		return n;
 	}
+	memset(msgbuf, 0, msgbuf_len);
+	memset(&dest_addr, 0, sizeof(dest_addr));
 	result = recvmsg(my_sock, &msg, MSG_DONTWAIT);
 	if (result < 0)
-		fprintf(stderr, "%s receive error:%s\n",
-		    progname, strerror(errno));
-	else {
-		if (verbose)
-			printf("%s received %d bytes from %d\n",
-			    progname, result, dest_addr.nl_pid);
-		showmsg(nlh, status);
-	}
+		fprintf(stderr, "%s receive error:%s wait:%ld:%06ld\n\n",
+			progname, strerror(errno), tv_res.tv_sec,
+			tv_res.tv_usec);
+	else if (verbose)
+		printf("%s received %d bytes from %d wait:%ld:%06ld\n",
+			progname, result, dest_addr.nl_pid, tv_res.tv_sec,
+			tv_res.tv_usec);
 	return result;
 }
 
-static int lldp_wait(struct command *cp)
+/*
+ * Find out which vdp this unsolicited message was sent for.
+ */
+static struct vdpdata *finduuid(unsigned char *uuid)
 {
-	int rc = 0;
-	unsigned int cnt;
+	unsigned int i;
 
-	for (cnt = 0; cnt < cp->repeats && rc >= 0; ++cnt)
-		if ((rc = waitmsg(cp, 0))) {
-			cp->rc = 1;
-			break;
-		}
-	return rc;
+	for (i = 0; i < DIM(vsidata); ++i)
+		if (!memcmp(vsidata[i].uuid, uuid, sizeof(vsidata[i].uuid)))
+			return &vsidata[i];
+	return 0;
 }
 
-/*
- * Construct the GETLINK message to lldpad.
- */
-static int mk_nlas(char *buf)
+static int trigger_test(struct vdpnl_vsi *p)
 {
-	int total;
-	struct nlattr *nlap;
-	char *cp;
-	struct ifinfomsg *to = (struct ifinfomsg *)buf;
+	char uuid[64];
+	int rc = -1;
 
-	to->ifi_index = ifindex;
-	to->ifi_family = AF_UNSPEC;
-	total = NLMSG_ALIGN(sizeof *to);
-	nlap = (struct nlattr *)(buf + NLMSG_ALIGN(sizeof *to));
-	nlap->nla_type = IFLA_IFNAME;
-	nlap->nla_len = NLA_HDRLEN + NLA_ALIGN(1 + strlen(ifname));
-	total += nlap->nla_len;
-	cp = (char *)nlap + NLA_HDRLEN;
-	strcpy(cp, ifname);
-	return total;
+	uuid2buf(p->vsi_uuid, uuid);
+	if (finduuid(p->vsi_uuid)) {
+		if (p->response == PORT_REQUEST_DISASSOCIATE)
+			rc = 1;
+	}
+	if (p->maclist)
+		free(p->maclist);
+	if (verbose >= 2)
+		printf("%s switch dis-assoc %s rc:%d\n", progname, uuid, rc);
+	return rc;
+}
+
+int vdpnl_trigger_parse(struct vdpnl_vsi *, unsigned char *, size_t);
+
+static void lldp_wait(struct command *cp)
+{
+	int rc;
+	unsigned int cnt;
+	unsigned char rcvbuf[2 * 1024];
+	struct vdpnl_vsi p;
+
+	for (cnt = 0; cnt < cp->repeats && rc >= 0; ++cnt) {
+		cp->sys_rc = cp->rc = 0;
+		rc = lldp_waitmsg(cp->waittime, rcvbuf, sizeof(rcvbuf));
+		if (rc < 0) {
+			cp->sys_rc = rc;
+			break;
+		}
+		if (rc > 0) {	/* Check for de-assoc message */
+			memset(&p, 0, sizeof(p));
+			rc = vdpnl_trigger_parse(&p, rcvbuf, sizeof(rcvbuf));
+			if (rc < 0)
+				cp->sys_rc = rc;
+			else
+				cp->rc = trigger_test(&p);
+			break;
+		}
+	}
 }
 
 /*
  * Send a GETLINK message to lldpad to query the status of the operation.
  */
-static int getlink(void)
+static int lldp_getlink(void)
 {
-	struct sockaddr_nl d_nladdr;
-	struct msghdr msg;
-	char buffer[256];
-	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
-	struct iovec iov;
+	char msgbuf[256];
+	struct iovec iov = {
+		.iov_base = msgbuf,
+		.iov_len = sizeof(msgbuf),
+	};
+	struct sockaddr_nl dest_addr;
+	struct msghdr msg = {
+		.msg_name = &dest_addr,
+		.msg_namelen = sizeof(dest_addr),
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+		.msg_controllen = 0,
+		.msg_control = 0
+	};
+	struct nlmsghdr *nlh = (struct nlmsghdr *)msgbuf;
+	struct ifinfomsg ifinfo;
 	int rc;
 
-	memset(buffer, 0, sizeof buffer);
-	/* Destination address */
-	memset(&d_nladdr, 0, sizeof d_nladdr);
-	d_nladdr.nl_family = PF_NETLINK;
-	d_nladdr.nl_pid = lldpad;
+	memset(msgbuf, 0, sizeof(msgbuf));
+	ifinfo.ifi_index = ifindex;
+	ifinfo.ifi_family = AF_UNSPEC;
 
 	/* Fill the netlink message header */
-	nlh->nlmsg_len = NLMSG_HDRLEN + mk_nlas((char *)NLMSG_DATA(nlh));
 	nlh->nlmsg_pid = getpid();
 	nlh->nlmsg_flags = NLM_F_REQUEST;
 	nlh->nlmsg_type = RTM_GETLINK;
+	nlh->nlmsg_len = NLMSG_SPACE(sizeof(ifinfo));
+	memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof(ifinfo));
+	mynla_put(nlh, IFLA_IFNAME, 1 + strlen(ifname), ifname);
+	iov.iov_len =  nlh->nlmsg_len;
 
-	/* Iov structure */
-	iov.iov_base = (void *)nlh;
-	iov.iov_len = nlh->nlmsg_len;
+	/* Destination address */
+	memset(&dest_addr, 0, sizeof(dest_addr));
+	dest_addr.nl_family = PF_NETLINK;
+	dest_addr.nl_pid = lldpad;
 
-	/* Msg */
-	memset(&msg, 0, sizeof msg);
-	msg.msg_name = (void *)&d_nladdr;
-	msg.msg_namelen = sizeof d_nladdr;
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
 	if ((rc = sendmsg(my_sock, &msg, 0)) == -1)
 		perror(progname);
 	if (verbose)
@@ -466,198 +1070,217 @@ static int getlink(void)
 /*
  * Send a RTM_GETLINK message and retrieve the status of the pending
  * command.
+ *
+ * Return
+ * <0 send/receive error
+ * 0  send/receive ok, but returned netlink message contains netlink error
+ * 1  send/receive ok, returned netlink message contains parsed response
+ * 2  send/receive ok, but no message returned at all
  */
-static int lldp_ack(struct command *cp)
-{
-	int bytes;
-	int status;
-
-	bytes = getlink();
-	if (bytes <= 0)
-		return bytes;
-	bytes = waitmsg(cp, &status);
-	if (bytes <= 0)
-		return bytes;
-	cp->rc = status;
-	if (verbose)
-		printf("%s lldp_ack status:%d\n", progname, cp->rc);
-	return bytes;
-}
+int vdpnl_getreply_error(unsigned char *, size_t, int *);
+int vdpnl_getreply_parse(struct vdpnl_vsi *, unsigned char *, size_t);
 
-static int addvfs(struct nl_msg *nl_msg, struct vdpdata *vdp, unsigned char cmd)
+static int lldp_recv(struct command *cp, struct vdpnl_vsi *p)
 {
-	struct nlattr *vfports, *vfport;
-	struct ifla_port_vsi vsi;
-	unsigned char op;
-
-	switch (cmd) {
-	case CMD_ASSOC:
-		op = PORT_REQUEST_ASSOCIATE;
-		break;
-	case CMD_DEASSOC:
-		op = PORT_REQUEST_DISASSOCIATE;
-		break;
-	case CMD_PREASSOC:
-		op = PORT_REQUEST_PREASSOCIATE;
-		break;
-	case CMD_RRPREASSOC:
-		op = PORT_REQUEST_PREASSOCIATE_RR;
-		break;
+	unsigned int cnt;
+	int rc, rc2, bytes;
+	unsigned char rcvbuf[2 * 1024];
+
+	for (bytes = 0, cnt = 0; cnt < cp->repeats && bytes == 0; ++cnt) {
+		usleep(cp->delay * 1000);
+		cp->sys_rc = lldp_getlink();
+		if (cp->sys_rc < 0)
+			return cp->sys_rc;
+		cp->rc = cp->sys_rc = 0;
+		bytes = lldp_waitmsg(cp->waittime, rcvbuf, sizeof(rcvbuf));
+		if (bytes < 0)			/* Error */
+			return cp->sys_rc = bytes;
+		if (bytes > 0) {			/* Got reply */
+			rc2 = vdpnl_getreply_error(rcvbuf, sizeof(rcvbuf), &rc);
+			if (rc2 < 0) {		/* Parsing failed */
+				if (verbose)
+					printf("%s getlink errmsg parse "
+						"error:%d\n", progname, rc2);
+				return cp->sys_rc = cp->rc = rc2;
+			} else if (rc2 == 1) {	/* Error reply */
+				if (verbose)
+					printf("%s getlink error response:%d\n",
+						progname, rc);
+				cp->rc = rc;
+				return 0;
+			}
+			/* Normal reply, parsed ok */
+			rc2 = vdpnl_getreply_parse(p, rcvbuf, sizeof(rcvbuf));
+			if (rc2 < 0) {		/* Parsing failed */
+				if (verbose)
+					printf("%s getlink parse error rc:%d\n",
+						progname, rc2);
+				return cp->sys_rc = cp->rc = rc2;
+			} else if (rc2 == 1) {	/* Found reply */
+				cp->rc = p->response;
+				return 1;
+			} else if (rc2 == 0) {
+				/* Reply without UUID/RESPONSE attribute */
+				if (verbose >= 2)
+					printf("%s getlink parse UUID/RESPONSE"
+						" missing\n", progname);
+				cp->rc = -1;
+			}
+		}
 	}
-	if (vdp->hints)
-		op |= vdp->hints;
+	return 2;
+}
 
-	vsi.vsi_mgr_id = vdp->mgrid;
-	vsi.vsi_type_version = vdp->typeidver;
-	vsi.vsi_type_id[2] = vdp->typeid >> 16;
-	vsi.vsi_type_id[1] = vdp->typeid >> 8;
-	vsi.vsi_type_id[0] = vdp->typeid;
+static int check_sendack(struct nlmsghdr *nlh, int *ack)
+{
+	struct nlmsgerr *err = NLMSG_DATA(nlh);
 
-	if (!(vfports = nla_nest_start(nl_msg, IFLA_VF_PORTS)))
-		return -ENOMEM;
-	if (!(vfport = nla_nest_start(nl_msg, IFLA_VF_PORT)))
-		return -ENOMEM;
-	if (nla_put(nl_msg, IFLA_PORT_VSI_TYPE, sizeof vsi, &vsi) < 0)
-		return -ENOMEM;
-	if (nla_put(nl_msg, IFLA_PORT_INSTANCE_UUID, UUIDLEN, vdp->uuid) < 0)
-		return -ENOMEM;
-	if (nla_put(nl_msg, IFLA_PORT_REQUEST, sizeof op, &op) < 0)
-		return -ENOMEM;
-	nla_nest_end(nl_msg, vfport);
-	nla_nest_end(nl_msg, vfports);
+	if (nlh->nlmsg_type != NLMSG_ERROR)
+		return -1;
+	if (verbose)
+		printf("%s setlink response:%d\n", progname, err->error);
+	*ack = err->error;
 	return 0;
 }
 
 /*
- * Add filter information and use SPOOFCHK to send group information
+ * Send a netlink message to lldpad. Its a SETLINK message to trigger an
+ * action. LLDPAD responds with an error netlink message indicating if the
+ * profile was accepted.
+ * LLDPAD sends negative numbers as error indicators.
  */
-static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp)
+static int lldp_send(struct vdpnl_vsi *vsi, int waittime, int *ack)
 {
-	int i;
-	struct nlattr *vfinfolist, *vfinfo;
+	unsigned char msgbuf[2 * 1024];
+	struct iovec iov = {
+		.iov_base = msgbuf,
+		.iov_len = sizeof(msgbuf),
+	};
+	struct sockaddr_nl dest_addr = {
+		.nl_family = AF_NETLINK,
+		.nl_groups = 0,
+		.nl_pid = lldpad		/* Target PID */
+	};
+	struct msghdr msg = {
+		.msg_name = &dest_addr,
+		.msg_namelen = sizeof(dest_addr),
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+		.msg_controllen = 0,
+		.msg_control = 0
+	};
+	struct nlmsghdr *nlh = (struct nlmsghdr *)msgbuf;
+	int rc;
 
-	if (vdp->pairs == 0)
-		return 0;
-	if (!(vfinfolist = nla_nest_start(nl_msg, IFLA_VFINFO_LIST)))
-		return -ENOMEM;
-	for (i = 0; i < vdp->pairs; ++i) {
-		if (!(vfinfo = nla_nest_start(nl_msg, IFLA_VF_INFO)))
-			return -ENOMEM;
-
-		if (vdp->fif == FIF_VIDMAC || vdp->fif == FIF_GRPVIDMAC) {
-			struct ifla_vf_mac ifla_vf_mac;
-
-			ifla_vf_mac.vf = PORT_SELF_VF;
-			memcpy(ifla_vf_mac.mac, vdp->addr[i].mac, ETH_ALEN);
-			if (nla_put(nl_msg, IFLA_VF_MAC, sizeof ifla_vf_mac,
-				&ifla_vf_mac) < 0)
-				return -ENOMEM;
-		}
+	memset(msgbuf, 0, sizeof msgbuf);
+	rc = vdpnl_request_build(vsi, msgbuf, sizeof(msgbuf));
+	if (rc < 0) {
+		fprintf(stderr, "%s: can not build netlink msg (ver %d): %d\n",
+			progname, vsi->nl_version, rc);
+		return rc;
+	}
 
-		if (vdp->fif) {
-			struct ifla_vf_vlan ifla_vf_vlan = {
-				.vf = PORT_SELF_VF,
-				.vlan = vdp->addr[i].vlanid & 0xfff,
-				.qos = (vdp->addr[i].vlanid >> 12) & 7
-			};
+	iov.iov_len = nlh->nlmsg_len;		/* Set  msg length */
+	rc = sendmsg(my_sock, &msg, 0);
+	if (rc < 0){
+		perror(progname);
+		return rc;
+	}
+	if (verbose)
+		printf("%s send message to %d --> rc:%d\n", progname, lldpad,
+			rc);
+	rc = lldp_waitmsg(waittime, msgbuf, sizeof(msgbuf));
+	if (rc > 0)
+		 rc = check_sendack(nlh, ack);
+	else if (rc == 0)	/* Time out */
+		rc = -1;
+	return rc;
+}
 
-			if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof ifla_vf_vlan,
-				&ifla_vf_vlan) < 0)
-				return -ENOMEM;
-		}
-		nla_nest_end(nl_msg, vfinfo);
+static unsigned char cvt_request(unsigned char cmd)
+{
+	switch (cmd) {
+	case CMD_ASSOC:
+		return PORT_REQUEST_ASSOCIATE;
+	case CMD_DEASSOC:
+		return PORT_REQUEST_DISASSOCIATE;
+	case CMD_PREASSOC:
+		return PORT_REQUEST_PREASSOCIATE;
+	case CMD_RRPREASSOC:
+		return PORT_REQUEST_PREASSOCIATE_RR;
 	}
-	nla_nest_end(nl_msg, vfinfolist);
-	return 0;
+	return PORT_REQUEST_PREASSOCIATE;
 }
 
 /*
- * Build the netlink message, return total length of message
+ * Convert vdp to vsi structure.
  */
-static int buildmsg(unsigned char *buf, size_t len, unsigned char cmd,
-    struct vdpdata *vdp)
+static void vdp2vsi(struct vdpnl_vsi *p, unsigned char cmd, struct vdpdata *vdp)
 {
-	struct nlmsghdr *nlh;
-	struct nl_msg *nl_msg;
-	struct ifinfomsg ifinfo;
-
-	nl_msg = nlmsg_alloc();
-	if (!nl_msg)
-		goto err_exit;
-	ifinfo.ifi_index = ifindex;
-	ifinfo.ifi_family = AF_UNSPEC;
-	if (nlmsg_append(nl_msg, &ifinfo, sizeof ifinfo, NLMSG_ALIGNTO) < 0)
-		goto err_exit;
-	if (addmacs(nl_msg, vdp))
-		goto err_exit;
-	if (addvfs(nl_msg, vdp, cmd))
-		goto err_exit;
-	/*
-	 * Fill the netlink message header
-	 */
-	nlh = nlmsg_hdr(nl_msg);
-	nlh->nlmsg_type = RTM_SETLINK;
-	nlh->nlmsg_pid = getpid();
-	nlh->nlmsg_flags = NLM_F_REQUEST;
-	if (len < nlh->nlmsg_len)
-		goto err_exit;
-	memcpy(buf, nlh, nlh->nlmsg_len);
-	nlmsg_free(nl_msg);
-	return 0;
-
-err_exit:
-	if (nl_msg)
-		nlmsg_free(nl_msg);
-	fprintf(stderr, "%s: can not build netlink message\n", progname);
-	return -ENOMEM;
+	int i;
+	static unsigned long nlseq;
+	struct vdpnl_mac *mac = p->maclist;
+
+	strncpy(p->ifname, ifname, sizeof(p->ifname) - 1);
+	p->ifindex = ifindex;
+	p->vf = PORT_SELF_VF;
+	p->nl_version = vdp->nlmsg_v;
+	p->request = cvt_request(cmd);
+	p->req_seq = ++nlseq;
+	p->vsi_typeversion = vdp->typeidver;
+	p->vsi_typeid = vdp->typeid;
+	p->vsi_mgrid = vdp->mgrid;
+	p->hints = vdp->hints;
+	p->vsiid_fmt = 5;
+	memcpy(p->vsi_uuid, vdp->uuid, sizeof(p->vsi_uuid));
+	memcpy(p->vsi_mgrid2, vdp->mgrid2, sizeof(p->vsi_mgrid2));
+	p->filter_fmt = vdp->fif;
+	for (i = 0; i < p->macsz; ++ i, ++mac) {
+		mac->vlan = vdp->addr[i].vlanid;
+		mac->gpid = vdp->addr[i].gpid;
+		memcpy(mac->mac, vdp->addr[i].mac, sizeof(mac->mac));
+	}
+}
+
+static void clear_vsi(struct vdpnl_vsi *vsi, struct vdpnl_mac *macp, size_t sz)
+{
+	memset(vsi, 0, sizeof(*vsi));
+	memset(macp, 0, sizeof(*macp) * sz);
+	vsi->macsz = sz;
+	vsi->maclist = macp;
 }
 
 /*
- * Send a netlink message to lldpad. Its a SETLINK message to trigger an
- * action. LLDPAD responds with an error netlink message indicating if the
- * profile was accepted.
- * LLDPAD sends negative numbers as error indicators.
+ * Convey a message to lldpad.
+ *
+ * Return
+ * 1 for response from lldpad GETLINK command
+ * 0 for error response as sendack from lldpad (in cp->rc)
+ * -1 for system error (in cp->sys_rc)
  */
-static int lldp_send(struct command *cp, struct vdpdata *vdp)
-{
-	unsigned char sndbuf[1024];
-	struct iovec iov;
-	struct msghdr msg;
-	struct sockaddr_nl d_nladdr;
-	struct nlmsghdr *nlh = (struct nlmsghdr *)sndbuf;
-	int rc, vsiok = 0;
-
-	memset(&d_nladdr, 0, sizeof d_nladdr);
-	d_nladdr.nl_family = AF_NETLINK;
-	d_nladdr.nl_pid = lldpad;	/* Target PID */
-
-	memset(sndbuf, 0, sizeof sndbuf);
-	rc = buildmsg(sndbuf, sizeof sndbuf, cp->cmd, vdp);
-	if (rc)
-		return -ENOMEM;
-	iov.iov_base = (void *)nlh;
-	iov.iov_len = nlh->nlmsg_len;
-
-	/* Msg */
-	memset(&msg, 0, sizeof msg);
-	msg.msg_name = (void *)&d_nladdr;
-	msg.msg_namelen = sizeof d_nladdr;
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-	rc = sendmsg(my_sock, &msg, 0);
-	if (rc < 0)
-		perror(progname);
-	else {
-		if (verbose)
-			printf("%s send message to %d --> rc:%d\n", progname,
-			    lldpad, rc);
-		rc = waitmsg(cp, &vsiok);
-		if (rc > 0)
-			rc = vsiok;
-		else if (rc == 0)	/* Time out */
-			rc = -1;
+static void cmd_lldp(struct command *cp, struct vdpdata *vdp)
+{
+	int lldpad_cmdack;
+	struct vdpnl_mac mac[vdp->pairs];
+	struct vdpnl_vsi vsi;
+
+	/* Send command */
+	clear_vsi(&vsi, mac, vdp->pairs);
+	vdp2vsi(&vsi, cp->cmd, vdp);
+	cp->rc = 0;
+	cp->sys_rc = lldp_send(&vsi, cp->waittime, &lldpad_cmdack);
+	if (cp->sys_rc < 0)
+		return;
+	cp->rc = lldpad_cmdack;
+	if (cp->rc)
+		return;
+	/* Receive reply */
+	clear_vsi(&vsi, mac, vdp->pairs);
+	memcpy(vsi.vsi_uuid, vdp->uuid, sizeof(vsi.vsi_uuid));
+	if (lldp_recv(cp, &vsi) == 1) {
+		if (vsi.macsz)
+			cp->rc = compare_vsi(&vsi, vdp);
 	}
-	return rc;
 }
 
 /*
@@ -805,7 +1428,7 @@ static int check_map(char *value, struct vdpdata *profile)
 	}
 	memset(x, 0, sizeof(x));
 	slash = strchr(value, '/');
-	if (slash) {		/* Expect replacement vid */
+	if (slash) {		/* Expect replacement vid incl. changed QoS */
 		*slash = '\0';
 		newvlan = getnumber("map", slash + 1, '\0', &ec);
 		if (ec) {
@@ -818,7 +1441,7 @@ static int check_map(char *value, struct vdpdata *profile)
 				progname, newvlan);
 			return -1;
 		}
-		profile->nlmsg_v = nlmsg_v2;
+		profile->nlmsg_v = vdpnl_nlf2;
 	}
 	vlan = getnumber("map", value, '\0', &ec);
 	if (ec) {
@@ -829,7 +1452,7 @@ static int check_map(char *value, struct vdpdata *profile)
 		fprintf(stderr, "%s vlanid %ld too high\n", progname, vlan);
 		return -1;
 	}
-	fif = FIF_VID;
+	fif = VDP22_FFMT_VID;
 	if (have_mac) {
 		ec = sscanf(delim + 1, "%02x:%02x:%02x:%02x:%02x:%02x", &x[0],
 				&x[1], &x[2], &x[3], &x[4], &x[5]);
@@ -845,7 +1468,7 @@ static int check_map(char *value, struct vdpdata *profile)
 					progname, delim);
 			return -1;
 		}
-		fif = FIF_VIDMAC;
+		fif = VDP22_FFMT_MACVID;
 	}
 	/* Check for optional group identifier */
 	if (have_gpid && *(delim2 + 1)) {
@@ -856,7 +1479,7 @@ static int check_map(char *value, struct vdpdata *profile)
 			return -1;
 		}
 		fif += 2;
-		profile->nlmsg_v = nlmsg_v2;
+		profile->nlmsg_v = vdpnl_nlf2;
 	}
 #ifdef MYDEBUG
 	for (i = 0; i < ETH_ALEN; ++i)
@@ -866,23 +1489,26 @@ static int check_map(char *value, struct vdpdata *profile)
 #endif
 	if (profile->fif && profile->fif != fif) {
 		fprintf(stderr, "%s invalid filter info format %d use %d\n",
-		    progname, FIF_VIDMAC, profile->fif);
+		    progname, fif, profile->fif);
 		return -1;
 	}
 	profile->fif = fif;
 	for (ec = 0; ec < profile->pairs; ++ec) {
 		if (DIM(profile->addr) == i) {
-			fprintf(stderr, "%s too many mac addresses\n",
+			fprintf(stderr, "%s too many filter addresses\n",
 			    progname);
 			return -1;
 		}
-		for (i = 0; i < ETH_ALEN; ++i)
-			if (profile->addr[ec].mac[i] != x[i])
-				break;
-		if (i == ETH_ALEN) {
-			fprintf(stderr, "%s duplicate mac address %s\n",
-			    progname, value);
+		if (profile->fif == VDP22_FFMT_MACVID
+		    || profile->fif == VDP22_FFMT_GROUPMACVID)  {
+			for (i = 0; i < ETH_ALEN; ++i)
+				if (profile->addr[ec].mac[i] != x[i])
+					break;
+			if (i == ETH_ALEN) {
+				fprintf(stderr, "%s duplicate mac address %s\n",
+				    progname, value);
 			return -1;
+			}
 		}
 	}
 	ec = profile->pairs++;
@@ -898,7 +1524,7 @@ static int check_map(char *value, struct vdpdata *profile)
 static int check_uuid(char *value, struct vdpdata *profile)
 {
 	unsigned int rc;
-	unsigned int p[UUIDLEN];
+	unsigned int p[PORT_UUID_MAX];
 
 	rc = sscanf(value, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
 		"%02x%02x-%02x%02x%02x%02x%02x%02x",
@@ -908,11 +1534,11 @@ static int check_uuid(char *value, struct vdpdata *profile)
 	int i;
 
 	printf("cc=%d\n", rc);
-	for (i = 0; i < UUIDLEN; ++i)
+	for (i = 0; i < PORT_UUID_MAX; ++i)
 		printf("p[%d]=%#x ", i, p[i]);
 	puts("");
 #endif
-	if (rc != UUIDLEN) {
+	if (rc != PORT_UUID_MAX) {
 		fprintf(stderr, "%s invalid uuid %s\n", progname, value);
 		return -1;
 	}
@@ -972,17 +1598,17 @@ static int check_mgrid(char *value, struct vdpdata *profile)
 	unsigned long no;
 	int ec;
 
-	if (profile->nlmsg_v == nlmsg_v2) {
+	if (profile->nlmsg_v == vdpnl_nlf2) {
 		fprintf(stderr, "%s: mgrid and 2mgrid specified\n", progname);
 		return -1;
 	}
 	no = getnumber("mgrid", value, '\0', &ec);
 	if (!ec) {
 		if (no <= 255 && no > 0) {
-			profile->nlmsg_v = nlmsg_v0;
+			profile->nlmsg_v = vdpnl_nlf1;
 			profile->mgrid = no;
 			profile->modified |= 1 << f_mgrid;
-			memset(profile->mgrid2, 0, UUIDLEN);
+			memset(profile->mgrid2, 0, sizeof(profile->mgrid2));
 		} else {
 			ec = -1;
 			fprintf(stderr, "%s: invalid mgrid %ld\n", progname,
@@ -997,15 +1623,15 @@ static int check_mgrid(char *value, struct vdpdata *profile)
 
 static int check_2mgrid(char *value, struct vdpdata *profile)
 {
-	if (profile->nlmsg_v == nlmsg_v0) {
+	if (profile->nlmsg_v == vdpnl_nlf1) {
 		fprintf(stderr, "%s: mgrid and 2mgrid specified\n", progname);
 		return -1;
 	}
-	strncpy((char *)profile->mgrid2, value, UUIDLEN - 1);
-	profile->mgrid2[UUIDLEN - 1] = '\0';
+	memcpy(profile->mgrid2, value, sizeof(profile->mgrid2) - 1);
+	profile->mgrid2[sizeof(profile->mgrid2) - 1] = '\0';
 	profile->mgrid = 0;
 	profile->modified |= 1 << f_mgrid;
-	profile->nlmsg_v = nlmsg_v2;
+	profile->nlmsg_v = vdpnl_nlf2;
 	return 0;
 }
 
@@ -1013,18 +1639,18 @@ static int check_hints(char *value, struct vdpdata *profile)
 {
 	int rc = 0;
 
-	if (!strcmp(value, "to")) {
-		profile->hints = MIGTO;
+	if(!strcmp(value, "to")) {
+		profile->hints = VDP22_MIGTO;
 		profile->modified |= 1 << f_hints;
-		profile->nlmsg_v = nlmsg_v2;
-	} else if (!strcmp(value, "from")) {
-		profile->hints = MIGFROM;
+		profile->nlmsg_v = vdpnl_nlf2;
+	} else if(!strcmp(value, "from")) {
+		profile->hints = VDP22_MIGFROM;
 		profile->modified |= 1 << f_hints;
-		profile->nlmsg_v = nlmsg_v2;
-	} else if (!strcmp(value, "none")) {
+		profile->nlmsg_v = vdpnl_nlf2;
+	} else if(!strcmp(value, "none")) {
 		profile->hints = 0;
 		profile->modified |= 1 << f_hints;
-		profile->nlmsg_v = nlmsg_v2;
+		profile->nlmsg_v = vdpnl_nlf2;
 	} else {
 		fprintf(stderr, "%s: invalid hints %s\n", progname, value);
 		rc = -1;
@@ -1172,13 +1798,15 @@ static void print_pairs(struct vdpdata *found)
 		printf("\t%hd", found->addr[i].vlanid);
 		if (found->addr[i].newvid)
 			printf("/%hd", found->addr[i].newvid);
-		if (found->fif == FIF_VIDMAC || found->fif == FIF_GRPVIDMAC) {
+		if (found->fif == VDP22_FFMT_MACVID ||
+		    found->fif == VDP22_FFMT_GROUPMACVID) {
 			unsigned char *xp = found->addr[i].mac;
 
 			printf(" %02x:%02x:%02x:%02x:%02x:%02x",
 				xp[0], xp[1], xp[2], xp[3], xp[4], xp[5]);
 		}
-		if (found->fif == FIF_GRPVID || found->fif == FIF_GRPVIDMAC)
+		if (found->fif == VDP22_FFMT_GROUPVID ||
+		    found->fif == VDP22_FFMT_GROUPMACVID)
 			printf(" %ld", found->addr[i].gpid);
 		printf("\n");
 	}
@@ -1196,7 +1824,7 @@ static void print_profile(struct vdpdata *found)
 	       found->key, found->nlmsg_v, found->fif, uuid, found->typeid,
 	       found->typeidver);
 	if (found->hints)
-		printf(" hints:%s", found->hints == MIGTO ? "to" : "from");
+		printf(" hints:%s", found->hints == VDP22_MIGTO ? "to" : "from");
 	printf("\n");
 	uuid2buf(found->uuid, uuid);
 	printf("\tuuid:%s\n", uuid);
@@ -1216,7 +1844,7 @@ static int change_profile(struct vdpdata *change, struct vdpdata *alter)
 	}
 	if ((alter->modified & (1 << f_mgrid))) {
 		change->mgrid = alter->mgrid;
-		memcpy(change->mgrid2, alter->mgrid2, UUIDLEN);
+		memcpy(change->mgrid2, alter->mgrid2, sizeof(change->mgrid2));
 	}
 	if ((alter->modified & (1 << f_typeid)))
 		change->typeid = alter->typeid;
@@ -1318,7 +1946,7 @@ static void find_field(unsigned char mode, char *buf)
 	}
 }
 
-static void isvalid_profile(struct vdpdata *vdp)
+static int isvalid_profile(struct vdpdata *vdp)
 {
 	char buf[64];
 	unsigned char mode = 1 << f_map | 1 << f_mgrid |
@@ -1330,7 +1958,15 @@ static void isvalid_profile(struct vdpdata *vdp)
 		fprintf(stderr, "%s key %s misses profile fields %s\n",
 		    progname, vdp->key, buf);
 		memset(vdp->key, 0, sizeof vdp->key);
+		return -1;
+	}
+	if (vdp->nlmsg_v != vdpnl_nlf2 && vdp->nlmsg_v != vdpnl_nlf1) {
+		fprintf(stderr, "%s key %s has wrong netlink msg format\n",
+		    progname, vdp->key);
+		memset(vdp->key, 0, sizeof vdp->key);
+		return -1;
 	}
+	return 0;
 }
 
 static int make_profiles(char *profile, char *newkey)
@@ -1358,8 +1994,8 @@ static int make_profiles(char *profile, char *newkey)
 			    progname, nextone.key);
 			return -1;
 		}
-		if (!strcmp(newkey, found->key)) {
-			fprintf(stderr, "%s profile key %s already exits\n",
+		if (!strcmp(newkey, found->key) || findkey(newkey)) {
+			fprintf(stderr, "%s target key %s already exits\n",
 				progname, newkey);
 			return -1;
 		}
@@ -1369,10 +2005,11 @@ static int make_profiles(char *profile, char *newkey)
 		}
 		*vdp = *found;
 		strncpy(vdp->key, newkey, sizeof vdp->key);
+		if (!nextone.nlmsg_v)		/* Test for netlink format */
+			nextone.nlmsg_v = vdp->nlmsg_v;
 		change_profile(vdp, &nextone);
 	}
-	isvalid_profile(vdp);
-	return 0;
+	return isvalid_profile(vdp);
 }
 
 static int del_profiles(char *name)
@@ -1397,7 +2034,7 @@ static int copy_profiles(char *profile)
 		fprintf(stderr, "%s missing key new=name\n", progname);
 		return -1;
 	}
-	newkey = profile + 4;
+	newkey = profile + strlen(COPY_OP);
 	newprofile = strchr(newkey, ',');
 	if (!newprofile) {
 		fprintf(stderr, "%s invalid copy command\n", progname);
@@ -1664,6 +2301,11 @@ static int cmd_checkrc(struct command *cmdp)
 {
 	int i;
 
+	if (cmdp->sys_rc) {
+		printf("FAILURE sys_rc:%d ", cmdp->sys_rc);
+		show_command(cmdp, 1);
+		return -1;
+	}
 	for (i = 0; i < cmdp->no_err; ++i)
 		if (cmdp->rc == cmdp->errors[i]) {
 			if (verbose)
@@ -1706,40 +2348,19 @@ static void cmd_sleep(struct command *cmdp)
 			cmdp->rc |= sleep(cmdp->waittime);
 }
 
-static int rc_ok(struct command *cmdp)
-{
-	int i;
-
-	for (i = 0; i < cmdp->no_err; ++i)
-		if (cmdp->rc == cmdp->errors[i])
-			return 1;
-	return 0;
-}
-
+/*
+ * Return 0 with command executed as expected.
+ * Maybe with expected error.
+ */
 static void cmd_profile(struct command *cmdp)
 {
 	struct vdpdata *vdp = findkey(cmdp->key);
-	int got_ack = 0;
-	unsigned int i;
 
 	if (!vdp) {
 		cmdp->rc = ENFILE;
 		return;
 	}
-	if ((cmdp->rc = lldp_send(cmdp, vdp)) >= 0)
-		for (i = 0; got_ack == 0 && i < cmdp->repeats; ++i) {
-			usleep(cmdp->delay * 1000);
-			got_ack = lldp_ack(cmdp);
-			if (got_ack < 0) {	/* Error */
-				cmdp->rc = -1;
-				break;
-			} else if (got_ack > 0) {	/* Got ack */
-				if (rc_ok(cmdp))
-					break;
-				else
-					got_ack = 0;
-			}
-		}
+	cmd_lldp(cmdp, vdp);
 }
 
 static int runcmds()
@@ -1827,8 +2448,8 @@ int main(int argc, char **argv)
 			break;
 		case CMD_SLEEP:
 			if (!optarg) {
-				optarg = mybuf,
-				    strncpy(mybuf, "w=1", sizeof mybuf);
+				optarg = mybuf;
+				strncpy(mybuf, "w=1", sizeof mybuf);
 			}
 			parse_cmd(ch, optarg);
 			break;
@@ -1857,11 +2478,17 @@ int main(int argc, char **argv)
 	lldpad_pid();
 	if ((my_sock = open_socket(NETLINK_ROUTE)) < 0)
 		exit(4);
-	if (verbose >= 2)
+	if (verbose >= 2) {
+		printf("\nTests to run:\n");
 		show_commands(0);
+	}
+	if (verbose >= 2)
+		printf("\nExecution:\n");
 	rc = runcmds();
 	close(my_sock);
-	if (verbose >= 2)
+	if (verbose >= 2) {
+		printf("\nSummary:\n");
 		show_commands(1);
+	}
 	return rc;
 }
-- 
1.8.3.1



More information about the lldp-devel mailing list