diff --git a/SOURCES/lldpad-0.9.46-123-g48a5f38.patch b/SOURCES/lldpad-0.9.46-123-g48a5f38.patch new file mode 100644 index 0000000..c2d8fdd --- /dev/null +++ b/SOURCES/lldpad-0.9.46-123-g48a5f38.patch @@ -0,0 +1,45882 @@ +v0.9.46-123-g48a5f38 +--- +48a5f38 Move to libnl3 +fa42d01 lldpad: print verbose error messages +cb1ae28 lldpad: do not use absolute pathname for sys/queue.h +d3706f0 Interop issues with Juniper QFX3500 switch & firmware managed dcbx +8f78907 clif.c use correct include file +d36de79 vdp22_cmds scan vdp22 module for configuration +4ace840 liblldp_clif docuementation update clif_vsi and clif_vsiwait +844ddd9 clif and vdp22_clif_cmd send correct tlvid +1c52e87 vdp22 client command interface definition +990044c vdp22 add missing information for client +9064813 vdp22 bridge mode simulation fix for commit 61b69da +272c4f4 veth-setup.sh create veth0 with fixed mac address +c5cf1d3 crtl_iface remove trailing blanks and newlines +3b8cb17 gitignore add new files +ce66e20 Disambiguate TX/RX sum error messages +b8f7583 Add missing newlines in dcb_protocol.c log messages +4f6e8cb Add missing newlines in dcb_rule_chk.c log messages +61b69da ecp22 : Do not send end tlv. +3ef96bc lldp: Fix some spelling errors +8f877b3 Fixed automake error +da964f8 vdp22 test remove obsolete file +522ae1b evb/evb22 test cases +abe2bc7 evb/evb22 make sure one protocol only +ed02ef9 vdp22: Restore vsi profile after link down/up event +5cf5850 Fix the build with recent autotools +9b71e95 vdp22 add test suite +745b8f2 vdp22 bridge mode error simulation fix +9cfda55 vdp handle dis-assoc comand without profile +3bc8b0d evb22 test case 26 +66f229b lldpad: Fixes for the flag values in VDP responses +c8f94ee vdp22 check for evb22.enabletx value +22af9bc trivial: upper-case some enum values +04c7179 vethsetup shell script for qbg22 testing +cc573cf evb22 add test case 25 +ca36254 qbg22sim fix typo in comment +808a677 ecp22 protocol test suite +f997f75 evb22 protocol test suite +95b45b2 qbg22sim fix ecp22 ethertype value +3fc974d liblldp_clif add documentation for new functions +6ea9f8a vdp22 reduce delay before executing vdp22 +727eafa lldpad: fix ECP 2.2 ethertype and allow VDP to support VEB mode +9294969 lldptool update for EVB22 +bc3ebd8 vdptest use liblldp_clif library for vdp22 test cases +f676ad2 clif support for sending vdp22 commands to lldpad +9ae3138 clif add clif_pending_wait function +e7e80bc vdp22 call back to client support +2827f1a vdp22 support for command messages from attached client +f32d041 vdp22 add support for command line interface +155576c vdp22 add vdp22_info function +87cd148 vdp22 set vlanid to include qos +81b43e5 vdp22 define protocol subtype +87cfde3 evb22 fix define values +f5cd6eb crtl_iface minor fixes +bf92b65 lldp_rtnl remove mynla_xxx functions +ee8b4d2 vdpnl remove mynla_xxx functions +796ec98 vdpnl rename vsiid_fmt to vsi_idfmt +4d44957 lldpad: stop dcbx from overwriting adminstatus +354fd12 vdp22 support variable number of VLAN/QoS returns +a3e642c vdp22 make function vdp22_local2str static +5d6b8f3 COPYING: Update FSF address +82bc127 dcbnl.h: Update FSF address +027931b Do not install systemd files as executable +cd7f197 lldpad: do not set rx state from TX initialization +09f7b9f vdptest: add additional notes to man page +106f9c0 vdpnl: initialize vdpnl_mac to prevent segfault +bbd83e0 vdp22-bridge support for error generation +2bddc48 vdpnl add support for new netlink message format +2534205 vdp22 add support for KEEP bit and KEEP state transition +346a427 vdp22 remove default error status on VSI end +c070198 vdp22 returned changed filter information from switch +326fcd2 vdp22 remove pcp and ps from structure definition +1c96e28 vdp22 support tracing for manager id +3c9f390 vdp set size of filter data list to zero +e9d8430 rtnl netlink message construction support +e026e9f liblldp_clif function clif_getpid fix wrong buffer length +c901b23 vdpnl regression support of multiple VSIs broken +6efa72c vdptest add support for IEEE 802.1 Qbg ratified standard +4794c01 vdp22 introduce new header files for common defines +345492b lldp: lldptool evb example man page typo fix +b79bf42 vdp22 protocol support for bridge state machine +3c9f82a vdp22 include bridge resource allocation code +915a2f8 vdp22 add bridge resource allocation code +49a522f Fixup definition of dcbx_get_arg_handlers +180f5df lldpad: Option '-t' to omit timestamps in messages +c321645 lldp: Do not print 'l2_packet_receive - recvfrom' when network is down +bc0c53f lldpad: Fixup pid file handling +90c8224 lldpad: remove check_cfg_file() +d8a997f lldpad: systemd integration +88f02e8 nltest: use correct format for pfc messages +eeff6d4 vdp22 protocol support for station state machine +0f5f66f EVB and VDP are only supported on the nearest customer bridge agent. This patch adds code to fail set commands from lldptool gracefully with a string that users might understand. +1a3cb98 lldpad: refactor VDP cmd interpretor with vdp_cmdok +42f731c vdptest print wrong values in trace +091c203 qbg_utils increase buffer to store uuid +d1b9702 vdpnl add trace statement on filter information +c4da57d vdpnl pretty indentation +edbfec0 vdpnl determine filter information format from netlink msg +bc1a19c vdpnl remove blank after colon in trace +0762554 vdptest man page minor fixes +3c93fd7 lldpad: check for existence of device before allowing set +11cea1c lldptool: update bridge scope long form options +e4d564d lldptool: man page fixes for MED and DCBX TLVs +1beda0b ecp22 ecp22_data_from_evb function rename +7060df3 vdp22 get role from evb22 protocol +b4a1407 vdp22 add VSI format identifier +0313734 lldpad: correct IEEE DCBX capabilities check +8a44162 lldpad: do not require active TLVs to configure attributes +cc83dce vdptest fix and clearify documentation +66ebbb5 lldp: Simplify set_lldp_agent_admin() to fix RHEL 6.4 compiler error +76e794c lldpad: Avoid accessing removed port structure +67ca45d qbg22 rename header files lldp_qbg22 to qbg22 +5fcf657 qbg22 rename header files lldp_vdp22 +d544f05 qbg22 rename source files lldp_vdp22 +1017dbd qbg rename source and header files lldp_qbg_utils +7d4c77c qbg rename source and header files lldp_vdp +99ded5b lldp move files lldp_evb22*.c to parent directory +92bdc90 qbg rename source and header file lldp_ecp +859fab6 qbg22 rename source and header file lldp_ecp22 +5994fa7 vdp22 add timeout calcuation +60c35b7 vdp22 add more support for vdp22 protocol +201e6fe vdp22 add netlink support for filter format field +3375ff9 vdp22 add vsi22 profile data structure +c0fe8bc lldpad: Primarily identify netdevs by ifindex + +diff --git a/.gitignore b/.gitignore +index 9289e11..c2ac5d7 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,5 @@ ++*/.dirstamp ++compile + parse_cli.c + *.o + *.lo +diff --git a/COPYING b/COPYING +index 5f297e5..87eef25 100644 +--- a/COPYING ++++ b/COPYING +@@ -8,7 +8,7 @@ GNU General Public License + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. +-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ++51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Everyone is permitted to copy and distribute verbatim copies of this license + document, but changing it is not allowed. +diff --git a/Makefile.am b/Makefile.am +index 893fa45..4889d32 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -16,8 +16,8 @@ ACLOCAL_AMFLAGS = -I m4 + parse_cli.o: CFLAGS+=-U_FORTIFY_SOURCE -Wno-error + + ## system requires a shared libconfig +-AM_CFLAGS = -Wall -Werror -Wextra -Wformat=2 $(LIBCONFIG_CFLAGS) +-AM_LDFLAGS = $(LIBCONFIG_LIBS) ++AM_CFLAGS = -Wall -Werror -Wextra -Wformat=2 $(LIBCONFIG_CFLAGS) $(LIBNL_CFLAGS) ++AM_LDFLAGS = $(LIBCONFIG_LIBS) $(LIBNL_LIBS) + + ## header files to be installed, for programs using the client interface to lldpad + lldpad_includedir= ${includedir}/lldpad +@@ -27,7 +27,7 @@ include/clif.h include/lldp_dcbx_cmds.h \ + include/lldpad.h include/lldp_mand_cmds.h \ + include/clif_msgs.h include/lldp_basman_cmds.h include/lldp_8023_cmds.h \ + include/lldp_med_cmds.h include/lldp_util.h \ +-include/lldp_evb_cmds.h include/lldp_vdp_cmds.h include/lldp_8021qaz_cmds.h \ ++include/lldp_evb_cmds.h include/qbg_vdp_cmds.h include/lldp_8021qaz_cmds.h \ + include/clif_sock.h include/linux/dcbnl.h \ + include/linux/netlink.h include/linux/rtnetlink.h \ + include/lldpad_status.h +@@ -40,7 +40,7 @@ include/lldpad_shm.h include/event_iface.h include/messages.h \ + include/parse_cli.h include/version.h include/lldptool_cli.h include/list.h \ + include/lldp_mand_clif.h include/lldp_basman_clif.h include/lldp_med_clif.h \ + include/lldp_8023_clif.h include/lldp_dcbx_clif.h include/lldp_evb_clif.h \ +-include/lldp_evb22_clif.h include/lldp_vdp_clif.h include/lldp_vdpnl.h \ ++include/lldp_evb22_clif.h include/qbg_vdp_clif.h include/qbg_vdpnl.h \ + include/lldp_8021qaz_clif.h \ + include/lldp_orgspec_clif.h include/lldp_cisco_clif.h \ + include/lldptool.h include/lldp_rtnl.h include/dcbtool.h include/lldp_dcbx_cfg.h +@@ -56,19 +56,20 @@ lldp_dcbx.c include/lldp_dcbx.h tlv_dcbx.c include/tlv_dcbx.h \ + lldp_dcbx_cfg.c include/lldp_dcbx_cfg.h lldp_util.c \ + lldp_mand.c include/lldp_mand.h \ + lldp_mand_cmds.c lldp_basman_cmds.c lldp_8023_cmds.c lldp_med_cmds.c \ +-lldp_evb_cmds.c lldp_evb.c include/lldp_evb.h lldp_vdp_cmds.c \ +-include/lldp_vdp_cmds.h \ +-include/lldp_ecp.h include/lldp_qbg_utils.h lldp_ecp.c lldp_qbg_utils.c \ +-lldp_vdp.c include/lldp_vdp.h \ ++lldp_evb_cmds.c lldp_evb.c include/lldp_evb.h qbg/vdp_cmds.c \ ++include/qbg_vdp_cmds.h \ ++include/qbg_ecp.h include/qbg_utils.h qbg/ecp.c qbg_utils.c \ ++qbg/vdp.c include/qbg_vdp.h \ + lldp_tlv.c include/lldp_tlv.h \ + lldp_basman.c include/lldp_basman.h \ + lldp_med.c include/lldp_med.h \ + lldp_8023.c include/lldp_8023.h \ + lldp_8021qaz.c include/lldp_8021qaz.h \ + lldp_8021qaz_cmds.c include/lldp_8021qaz_cmds.h \ +-include/lldp_evb22.h qbg/lldp_evb22.c qbg/lldp_evb22_cmds.c \ +-include/lldp_qbg22.h include/lldp_ecp22.h qbg/lldp_ecp22.c \ +-include/lldp_vdp22.h qbg/lldp_vdp22.c qbg/lldp_vdpnl.c ++include/lldp_evb22.h lldp_evb22.c lldp_evb22_cmds.c \ ++include/qbg22.h include/qbg_ecp22.h qbg/ecp22.c \ ++include/qbg_vdp22.h qbg/vdp22.c qbg/vdpnl.c qbg/vdp22sm.c qbg/vdp22br.c \ ++include/qbg_vdp22def.h qbg/vdp22_cmds.c qbg/vdp_ascii.c + + lib_LTLIBRARIES = liblldp_clif.la + liblldp_clif_la_LDFLAGS = -version-info 1:0:0 +@@ -83,11 +84,11 @@ dcbtool_LDFLAGS = -ldl -llldp_clif + lldptool_SOURCES = lldptool.c lldptool_cmds.c lldp_rtnl.c \ + lldp_mand_clif.c lldp_basman_clif.c lldp_med_clif.c \ + lldp_8023_clif.c lldp_dcbx_clif.c lldp_util.c \ +- lldp_8021qaz_clif.c lldp_evb_clif.c lldp_vdp_clif.c \ +- lldp_orgspec_clif.c lldp_cisco_clif.c qbg/lldp_evb22_clif.c \ ++ lldp_8021qaz_clif.c lldp_evb_clif.c qbg/vdp_clif.c \ ++ lldp_orgspec_clif.c lldp_cisco_clif.c lldp_evb22_clif.c \ + weak_readline.c $(lldpad_include_HEADERS) $(noinst_HEADERS) + lldptool_LDADD = ${srcdir}/liblldp_clif.la +-lldptool_LDFLAGS = -ldl -llldp_clif ++lldptool_LDFLAGS = -ldl -llldp_clif $(LIBNL_LIBS) + + if BUILD_DEBUG + nltest_SOURCES = test/nltest.c test/nltest.h +@@ -120,25 +121,21 @@ pkgconfig_DATA = lldpad.pc liblldp_clif.pc + ## put a spec file and documentation in the distribution archive + dist_noinst_DATA = lldpad.spec README COPYING ChangeLog + +-## lldpad.init is listed here because it gets installed from install-data-local +-dist_noinst_SCRIPTS = lldpad.init +- + ## special hooks to handle the init script +-install-data-local: lldpad.init +- $(MKDIR_P) $(DESTDIR)/etc/init.d +- $(INSTALL_SCRIPT) lldpad.init $(DESTDIR)/etc/init.d/lldpad ++install-data-local: lldpad.service lldpad.socket ++ $(MKDIR_P) $(DESTDIR)/usr/lib/systemd/system ++ $(INSTALL_DATA) lldpad.service $(DESTDIR)/usr/lib/systemd/system/lldpad.service ++ $(INSTALL_DATA) lldpad.socket $(DESTDIR)/usr/lib/systemd/system/lldpad.socket + + BASH_COMPLETION_DIR=/etc/bash_completion.d/ + + install-data-hook: +- /sbin/chkconfig --add lldpad || true + ## provide support for bash completion + $(MKDIR_P) $(DESTDIR)/$(BASH_COMPLETION_DIR) +- $(INSTALL_SCRIPT) ${srcdir}/contrib/bash_completion/* $(DESTDIR)/$(BASH_COMPLETION_DIR) ++ $(INSTALL_DATA) ${srcdir}/contrib/bash_completion/* $(DESTDIR)/$(BASH_COMPLETION_DIR) + + uninstall-local: +- /sbin/chkconfig --del lldpad || true +- rm -f '$(DESTDIR)/etc/init.d/lldpad' ++ rm -f '$(DESTDIR)/usr/lib/systemd/system/lldpad.*' + rm -f '$(includedir)/dcbd/clif_cmds.h' + rm -f '$(includedir)/dcbd' + +diff --git a/clif.c b/clif.c +index 2984e8e..cad6f75 100644 +--- a/clif.c ++++ b/clif.c +@@ -1,6 +1,6 @@ + /******************************************************************************* + +- LLDP Agent Daemon (LLDPAD) Software ++ LLDP Agent Daemon (LLDPAD) Software + Copyright(c) 2007-2010 Intel Corporation. + + Substantially modified from: +@@ -179,7 +179,7 @@ static int clif_attach_helper(struct clif *clif, char *tlvs_hex, int attach) + return -1; + sprintf(buf, "D"); + } +- ++ + ret = clif_request(clif, buf, strlen(buf), rbuf, &len, NULL); + free(buf); + if (ret < 0) +@@ -215,11 +215,11 @@ int clif_recv(struct clif *clif, char *reply, size_t *reply_len) + } + + +-int clif_pending(struct clif *clif) ++int clif_pending_wait(struct clif *clif, int waittime) + { + struct timeval tv; + fd_set rfds; +- tv.tv_sec = 0; ++ tv.tv_sec = waittime; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(clif->s, &rfds); +@@ -227,6 +227,10 @@ int clif_pending(struct clif *clif) + return FD_ISSET(clif->s, &rfds); + } + ++int clif_pending(struct clif *clif) ++{ ++ return clif_pending_wait(clif, 0); ++} + + int clif_get_fd(struct clif *clif) + { +@@ -240,7 +244,7 @@ pid_t clif_getpid(void) + { + struct clif *clif_conn; + char buf[MAX_CLIF_MSGBUF]; +- size_t len; ++ size_t len = sizeof(buf); + char *ppong; + int ret; + pid_t lldpad = 0; /* LLDPAD process identifier */ +@@ -275,3 +279,155 @@ out: + clif_close(clif_conn); + return lldpad; + } ++ ++/* ++ * Command line interface for vdp22 module. ++ * Includes for lldptool like access to lldpad ++ */ ++#include ++#include ++#include ++#include "include/qbg22.h" ++#include "include/qbg_vdp22_clif.h" /* Defines op_XXXX */ ++#include /* Needed by agent.h */ ++#include "lldp/agent.h" /* Nearest customer bridge define */ ++ ++/* ++ * Send a command via clif_xxx to lldpad. ++ * Return negavite numbers when a send/reply error occurs. ++ * Lldpad returns cmd_success for success and cmd_xxx for failure. ++ */ ++static int tool_send(struct clif *connp, char *cmd, size_t cmd_len, ++ char *reply, size_t *reply_len, int *lldpad_rc) ++{ ++ int rc; ++ ++ *lldpad_rc = 0; ++ rc = clif_request(connp, cmd, cmd_len, reply, reply_len, NULL); ++ if (!rc) { ++ if (1 != sscanf(reply, "R%02x", lldpad_rc)) ++ rc = -3; ++ } ++ return rc; ++} ++ ++/* ++ * Prepend the lldpad fan out information in front of the command. ++ * We use the vsi parameter. ++ */ ++static int hdr_set(char *ifname, char *s, size_t sz, unsigned int tlvid, ++ char *cmd, size_t cmd_len) ++{ ++ int rc; ++ ++ /* All command messages begin this way */ ++ rc = snprintf(s, sz, "%c%08x%c%1x%02x%08x%02zx%s%02x%08x03vsi%04zx%s", ++ MOD_CMD, LLDP_MOD_VDP22, CMD_REQUEST, CLIF_MSG_VERSION, ++ cmd_settlv, op_arg | op_argval | op_config, ++ strlen(ifname), ifname, NEAREST_CUSTOMER_BRIDGE, tlvid, ++ cmd_len, cmd); ++ return (rc < 0 || rc > (int)sz) ? -EFBIG : 0; ++} ++ ++/* ++ * Remove all whitespace and nonprintable characters from string. ++ */ ++static void kill_white(char *s) ++{ ++ char *cp = s; ++ ++ for (; *s != '\0'; ++s) { ++ if (isspace(*s)) ++ continue; ++ if (isprint(*s)) ++ *cp++ = *s; ++ } ++ *cp = '\0'; ++} ++ ++/* ++ * Send a VSI command to the vdp22 module and expect a reply. The reply can be ++ * an aknowledgement (error code 0) or an error code != 0 which means the ++ * command contained an error and was not accepted. ++ */ ++int clif_vsi(struct clif *connp, char *ifname, unsigned int tlvid, ++ char *cmd, char *reply, size_t *reply_len) ++{ ++ int rc, resp; ++ char cmd2[MAX_CLIF_MSGBUF]; ++ ++ kill_white(cmd); ++ rc = hdr_set(ifname, cmd2, sizeof(cmd2), tlvid, cmd, strlen(cmd)); ++ if (rc) ++ return rc; ++ rc = tool_send(connp, cmd2, strlen(cmd2), reply, reply_len, &resp); ++ if (!rc) ++ rc = resp; ++ return rc; ++} ++ ++/* ++ * Test if this is an event message from vdp22 module. ++ */ ++static bool test_evt(char *msg, size_t *msg_len) ++{ ++ bool is_evt = true; ++ unsigned int module; ++ ++ if (*msg_len < 12 || msg[MSG_TYPE] != MOD_CMD ++ || msg[MOD_MSG_TYPE] != EVENT_MSG ++ || sscanf(&msg[MSG_TYPE + 1], "%08x", &module) != 1 ++ || module != LLDP_MOD_VDP22) ++ is_evt = false; ++ return is_evt; ++} ++ ++/* ++ * Wait for an event message from lldpad module. After checking for the correct ++ * event message, the header of the event message is removed. ++ * ++ * Returns ++ * <0 on error or time out. ++ * =0 number of bytes on successful message reception (in reply_len parameter). ++ */ ++#define EVTHEADER 12 /* # of bytes in event message as hdr */ ++int clif_vsievt(struct clif *clif, char *reply, size_t *reply_len, int wait) ++{ ++ if (clif == NULL || wait < 0) ++ return -EINVAL; ++ if (clif_pending_wait(clif, wait)) { ++ if (clif_recv(clif, reply, reply_len) == 0) { ++ if (test_evt(reply, reply_len)) { ++ *reply_len -= EVTHEADER; ++ memmove(reply, reply + EVTHEADER, *reply_len); ++ reply[*reply_len] = '\0'; ++ return 0; ++ } else ++ return -EBADF; ++ } else ++ return -EIO; ++ } ++ return -EAGAIN; ++} ++/* ++ * Send a VSI command to the vdp22 mode and expect a reply. The reply can ++ * an aknowledgement (error code 0) or an error code != 0 which means the ++ * command contained an error and was not accepted. ++ * ++ * Wait for the event message from lldpad to return the VSI association data ++ * from the switch ++ */ ++int clif_vsiwait(struct clif *connp, char *ifname, unsigned int tlvid, ++ char *cmd, char *reply, size_t *reply_len, int wait) ++{ ++ int rc; ++ size_t reply_len2 = *reply_len; ++ ++ rc = clif_vsi(connp, ifname, tlvid, cmd, reply, reply_len); ++ if (!rc) { ++ rc = clif_vsievt(connp, reply, &reply_len2, wait); ++ if (!rc) ++ *reply_len = reply_len2; ++ } ++ return rc; ++} +diff --git a/config.c b/config.c +index 7229b91..5fc6f58 100644 +--- a/config.c ++++ b/config.c +@@ -102,6 +102,7 @@ void destroy_cfg(void) + void scan_port(UNUSED void *eloop_data, UNUSED void *user_ctx) + { + struct port *port; ++ struct port *next; + struct if_nameindex *nameidx, *p; + + LLDPAD_INFO("%s: NLMSG dropped, scan ports.\n", __func__); +@@ -121,24 +122,20 @@ void scan_port(UNUSED void *eloop_data, UNUSED void *user_ctx) + * comes back online we should receive a RTM_NEWLINK event and can + * readd it there. + */ +- port = porthead; +- while (port != NULL) { ++ for (port = porthead; port; port = next) { + int found = 0; +- struct port *del; +- p = nameidx; +- while (p->if_index != 0) { +- if (!strncmp(p->if_name, port->ifname, +- MAX_DEVICE_NAME_LEN)) { ++ ++ for (p = nameidx; p->if_index; ++p) { ++ if ((int)p->if_index == port->ifindex) { + /* Good device exists continue port walk */ + found = 1; ++ memcpy(port->ifname, p->if_name, IFNAMSIZ); + break; + } +- p++; + } +- del = port; +- port = port->next; ++ next = port->next; + if (!found) +- remove_port(del->ifname); ++ remove_port(port->ifname); + } + + /* Walk port list looking for devices that should have been added +@@ -149,43 +146,42 @@ void scan_port(UNUSED void *eloop_data, UNUSED void *user_ctx) + * This is required because we currently do not know if we missed + * IF_OPER_UP, IF_OPER_DOWN or IF_OPER_DORMANT. + */ +- p = nameidx; +- while (p->if_index != 0) { ++ for (p = nameidx; p->if_index; ++p) { + struct lldp_module *np; + const struct lldp_mod_ops *ops; + char *ifname = p->if_name; + struct lldp_agent *agent; + +- if (!is_valid_lldp_device(ifname)) { +- p++; ++ if (!is_valid_lldp_device(ifname)) ++ continue; ++ ++ port = port_find_by_ifindex(p->if_index); ++ if (!port) { ++ port = add_port(p->if_index, p->if_name); + continue; + } + +- port = port_find_by_name(p->if_name); +- if (!port) +- port = add_port(p->if_name); +- +- if (port && check_link_status(ifname)) { ++ memcpy(port->ifname, ifname, IFNAMSIZ); ++ if (check_link_status(ifname)) { + set_port_oper_delay(ifname); + oper_add_device(ifname); +- } else if (port) { +- LIST_FOREACH(agent, &port->agent_head, entry) { +- LLDPAD_DBG("%s: calling ifdown for agent %p.\n", +- __func__, agent); +- LIST_FOREACH(np, &lldp_head, lldp) { +- ops = np->ops; +- if (ops->lldp_mod_ifdown) +- ops->lldp_mod_ifdown(ifname, +- agent); +- } ++ continue; ++ } ++ LIST_FOREACH(agent, &port->agent_head, entry) { ++ LLDPAD_DBG("%s: calling ifdown for agent %p.\n", ++ __func__, agent); ++ LIST_FOREACH(np, &lldp_head, lldp) { ++ ops = np->ops; ++ if (ops->lldp_mod_ifdown) ++ ops->lldp_mod_ifdown(ifname, agent); + } +- set_lldp_port_enable(ifname, 0); + } +- p++; ++ set_lldp_port_enable(ifname, 0); + } + + if_freenameindex(nameidx); + return; ++ + error_out: + eloop_register_timeout(INI_TIMER, 0, scan_port, NULL, NULL); + return; +@@ -265,7 +261,7 @@ static bool check_int(int int_setting) + + static bool check_priority(int priority_setting) + { +- if (priority_setting < dcb_none || priority_setting >= dcb_invalid) ++ if (priority_setting < DCB_NONE || priority_setting >= DCB_INVALID) + return false; + else + return true; +@@ -361,36 +357,34 @@ void init_ports(void) + return; + } + +- p = nameidx; +- while (p->if_index != 0) { ++ for (p = nameidx; p->if_index; ++p) { + int valid = is_valid_lldp_device(p->if_name); + +- if (!valid) { +- p++; ++ if (!valid) + continue; +- } + +- port = add_port(p->if_name); +- +- if (port == NULL) { ++ port = add_port(p->if_index, p->if_name); ++ if (!port) { + LLDPAD_ERR("%s: Error adding device %s\n", + __func__, p->if_name); +- } else if (check_link_status(p->if_name)) { +- lldp_add_agent(p->if_name, NEAREST_BRIDGE); +- lldp_add_agent(p->if_name, NEAREST_NONTPMR_BRIDGE); +- lldp_add_agent(p->if_name, NEAREST_CUSTOMER_BRIDGE); ++ continue; ++ } ++ if (!check_link_status(p->if_name)) ++ continue; + +- LIST_FOREACH(agent, &port->agent_head, entry) { +- LLDPAD_DBG("%s: calling ifup for agent %p.\n", +- __func__, agent); +- LIST_FOREACH(np, &lldp_head, lldp) { +- if (np->ops->lldp_mod_ifup) +- np->ops->lldp_mod_ifup(p->if_name, agent); +- } ++ lldp_add_agent(p->if_name, NEAREST_BRIDGE); ++ lldp_add_agent(p->if_name, NEAREST_NONTPMR_BRIDGE); ++ lldp_add_agent(p->if_name, NEAREST_CUSTOMER_BRIDGE); ++ ++ LIST_FOREACH(agent, &port->agent_head, entry) { ++ LLDPAD_DBG("%s: calling ifup for agent %p.\n", ++ __func__, agent); ++ LIST_FOREACH(np, &lldp_head, lldp) { ++ if (np->ops->lldp_mod_ifup) ++ np->ops->lldp_mod_ifup(p->if_name, agent); + } +- set_lldp_port_enable(p->if_name, 1); + } +- p++; ++ set_lldp_port_enable(p->if_name, 1); + } + + if_freenameindex(nameidx); +diff --git a/configure.ac b/configure.ac +index 119ab58..8d65d26 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1,5 +1,5 @@ + AC_INIT([lldpad], [0.9.46], [lldp-devel@open-lldp.org]) +-AM_INIT_AUTOMAKE([-Wall -Werror foreign]) ++AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) + + m4_pattern_allow([AM_PROG_AR]) + AM_PROG_AR +@@ -13,6 +13,7 @@ fi + AM_CONDITIONAL([BUILD_DEBUG], [test "$enable_debug" = "yes"]) + + AC_PROG_CC ++AM_PROG_CC_C_O + AC_PROG_CXX + AC_PROG_LEX + AC_PROG_LIBTOOL +@@ -25,12 +26,12 @@ then + fi + + PKG_CHECK_MODULES([LIBCONFIG], [libconfig >= 1.3.2]) +-PKG_CHECK_MODULES([LIBNL], [libnl-1 >= 1.1]) ++PKG_CHECK_MODULES([LIBNL], [libnl-3.0 >= 3.2]) + + AC_SUBST(LIBNL_CFLAGS) + AC_SUBST(LIBNL_LIBS) + +-AC_CHECK_LIB(nl, rtnl_link_get_by_name) ++AC_CHECK_LIB(nl3, rtnl_link_get_by_name) + + AC_CHECK_FUNCS([alarm]) + AC_CHECK_FUNCS([gettimeofday]) +diff --git a/ctrl_iface.c b/ctrl_iface.c +index e02f036..e4fd0b7 100644 +--- a/ctrl_iface.c ++++ b/ctrl_iface.c +@@ -1,6 +1,6 @@ + /******************************************************************************* + +- LLDP Agent Daemon (LLDPAD) Software ++ LLDP Agent Daemon (LLDPAD) Software + Copyright(c) 2007-2010 Intel Corporation. + + Substantially modified from: +@@ -73,7 +73,7 @@ struct clif_cmds { + socklen_t fromlen, + char *ibuf, int ilen, + char *rbuf, int rlen); +-}; ++}; + + static const struct clif_cmds cmd_tbl[] = { + { DCB_CMD, clif_iface_module }, +@@ -117,7 +117,6 @@ int clif_iface_module(struct clif_data *clifd, + } + + mod = find_module_by_id(&lldp_head, module_id); +- + if (mod && mod->ops && mod->ops->client_cmd) + return (mod->ops->client_cmd)(clifd, from, fromlen, + cmd_start, cmd_len, rbuf+strlen(rbuf), rlen); +@@ -156,17 +155,14 @@ int clif_iface_attach(struct clif_data *clifd, + char *tlv, *str, *tokenize; + const char *delim = ","; + int i, tlv_count = 0; +- u8 *ptr; + + dst = malloc(sizeof(*dst)); + if (dst == NULL) +- return 1; ++ return cmd_failed; + memset(dst, 0, sizeof(*dst)); + memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); + dst->addrlen = fromlen; + dst->debug_level = MSG_INFO; +- dst->next = clifd->ctrl_dst; +- clifd->ctrl_dst = dst; + + /* + * There are two cases here one, the user provided +@@ -175,7 +171,6 @@ int clif_iface_attach(struct clif_data *clifd, + * user sent a comma seperated string of tlv module + * ids it expects events from + */ +- + /* set default string to DCBX Events */ + if (ibuf[1] == '\0') { + u32 hex = LLDP_MOD_DCBX; +@@ -197,7 +192,7 @@ int clif_iface_attach(struct clif_data *clifd, + tokenize = strtok(NULL, delim); + tlv_count++; + } while (tokenize); +- ++ + dst->tlv_types = malloc(sizeof(u32) * tlv_count); + if (!dst->tlv_types) + goto err_types; +@@ -206,8 +201,11 @@ int clif_iface_attach(struct clif_data *clifd, + /* Populate tlv_types from comma separated string */ + tokenize = strtok(str, delim); + for (i=0; tokenize; i++) { +- ptr = (u8*)&dst->tlv_types[i]; +- hexstr2bin(tokenize, ptr, 4); ++ char *myend; ++ ++ dst->tlv_types[i] = strtol(tokenize, &myend, 16); ++ if (*myend) /* No hexnumber for module id */ ++ goto err_types; + tokenize = strtok(NULL, delim); + } + +@@ -215,13 +213,17 @@ int clif_iface_attach(struct clif_data *clifd, + dst->tlv_types[i] = ~0; + free(tlv); + ++ /* Insert new node at beginning */ ++ dst->next = clifd->ctrl_dst; ++ clifd->ctrl_dst = dst; + LLDPAD_DBG("CTRL_IFACE monitor attached\n"); + snprintf(rbuf, rlen, "%c", ATTACH_CMD); + +- return 0; ++ return cmd_success; + err_types: + free(tlv); + err_tlv: ++ free(dst); + LLDPAD_DBG("CTRL_IFACE monitor attach error\n"); + snprintf(rbuf, rlen, "%c", ATTACH_CMD); + +@@ -278,7 +280,7 @@ int clif_iface_level(struct clif_data *clifd, + level = ibuf+1; + snprintf(rbuf, rlen, "%c", LEVEL_CMD); + +- LLDPAD_DBG("CTRL_IFACE LEVEL %s", level); ++ LLDPAD_DBG("CTRL_IFACE LEVEL %s\n", level); + + dst = clifd->ctrl_dst; + while (dst) { +@@ -326,7 +328,7 @@ static void process_clif_cmd( struct clif_data *cd, + rsize - strlen(rbuf) - 1); + + /* update status and compute final length */ +- rbuf[CLIF_STAT_OFF] = hexlist[(status & 0x0f1) >> 4]; ++ rbuf[CLIF_STAT_OFF] = hexlist[(status & 0xf0) >> 4]; + rbuf[CLIF_STAT_OFF+1] = hexlist[status & 0x0f]; + *rlen = strlen(rbuf); + } +@@ -371,14 +373,14 @@ static void ctrl_iface_receive(int sock, void *eloop_ctx, + cred = (struct ucred *)CMSG_DATA(cmsg); + + if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { +- LLDPAD_INFO("%s: No sender credentials, ignoring", ++ LLDPAD_INFO("%s: No sender credentials, ignoring\n", + __FUNCTION__); + sprintf(buf,"R%02x", cmd_bad_params); + sendto(sock, buf, 3, 0, (struct sockaddr *) &from, fromlen); + return; + } + if (cred->uid != 0) { +- LLDPAD_INFO("%s: sender uid=%i, ignoring", ++ LLDPAD_INFO("%s: sender uid=%i, ignoring\n", + __FUNCTION__, cred->uid); + sprintf(buf,"R%02x", cmd_no_access); + sendto(sock, buf, 3, 0, (struct sockaddr *) &from, +@@ -411,6 +413,42 @@ int ctrl_iface_register(struct clif_data *clifd) + clifd, NULL); + } + ++int ctrl_iface_systemd_socket() ++{ ++ char *env, *ptr; ++ unsigned int p, l; ++ ++ env = getenv("LISTEN_PID"); ++ if (!env) ++ return -1; ++ ++ p = strtoul(env, &ptr, 10); ++ if (ptr && ptr == env) { ++ LLDPAD_DBG("Invalid value '%s' for LISTEN_PID\n", env); ++ return -1; ++ } ++ if ((pid_t)p != getpid()) { ++ LLDPAD_DBG("Invalid PID '%d' from LISTEN_PID\n", p); ++ return -1; ++ } ++ env = getenv("LISTEN_FDS"); ++ if (!env) { ++ LLDPAD_DBG("LISTEN_FDS is not set\n"); ++ return -1; ++ } ++ l = strtoul(env, &ptr, 10); ++ if (ptr && ptr == env) { ++ LLDPAD_INFO("Invalid value '%s' for LISTEN_FDS\n", env); ++ return -1; ++ } ++ if (l != 1) { ++ LLDPAD_INFO("LISTEN_FDS specified %d fds\n", l); ++ return -1; ++ } ++ /* systemd returns fds with an offset of '3' */ ++ return 3; ++} ++ + int ctrl_iface_init(struct clif_data *clifd) + { + struct sockaddr_un addr; +@@ -421,9 +459,14 @@ int ctrl_iface_init(struct clif_data *clifd) + clifd->ctrl_sock = -1; + clifd->ctrl_dst = NULL; + ++ s = ctrl_iface_systemd_socket(); ++ if (s != -1) { ++ LLDPAD_INFO("using fd %d from systemd\n", s); ++ goto out; ++ } + s = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (s < 0) { +- perror("socket(AF_LOCAL)"); ++ LLDPAD_WARN("failed to create CLI socket: %m\n"); + goto fail; + } + /* enable receiving of the sender credentials */ +@@ -436,7 +479,10 @@ int ctrl_iface_init(struct clif_data *clifd) + "%s", LLDP_CLIF_SOCK); + addrlen = sizeof(sa_family_t) + strlen(addr.sun_path + 1) + 1; + if (bind(s, (struct sockaddr *) &addr, addrlen) < 0) { +- perror("bind(AF_LOCAL)"); ++ if (errno == EADDRINUSE) ++ LLDPAD_WARN("another lldpad instance is running\n"); ++ else ++ LLDPAD_WARN("failed to bind CLI socket address: %m"); + goto fail; + } + /* enable receiving of the sender credentials */ +@@ -444,6 +490,7 @@ int ctrl_iface_init(struct clif_data *clifd) + &feature_on, sizeof(feature_on)); + + LLDPAD_INFO("bound ctrl iface to %s\n", &addr.sun_path[1]); ++out: + clifd->ctrl_sock = s; + + return 0; +@@ -481,7 +528,7 @@ int is_ctrl_listening(struct ctrl_dst *dst, u32 type) + u32 term = ~0; + u32 all = 0; + u32 dcbx = LLDP_MOD_DCBX; +- ++ + if (!dst) + return 0; + +@@ -530,8 +577,7 @@ void ctrl_iface_send(struct clif_data *clifd, int level, u32 moduleid, + next = dst->next; + send = 0; + /* Does dst receive these event messages? */ +- send = is_ctrl_listening(dst, moduleid); +- ++ send = is_ctrl_listening(dst, moduleid); + /* Yes */ + if (send && level >= dst->debug_level) { + msg.msg_name = &dst->addr; +diff --git a/dcb_protocol.c b/dcb_protocol.c +index 1e110a6..61b504d 100644 +--- a/dcb_protocol.c ++++ b/dcb_protocol.c +@@ -45,7 +45,7 @@ + #include "linux/dcbnl.h" + + static void handle_opermode_true(char *device_name); +-u8 gdcbx_subtype = dcbx_subtype2; ++u8 gdcbx_subtype = DCBX_SUBTYPE2; + + int set_configuration(char *device_name, u32 EventFlag); + +@@ -1213,7 +1213,7 @@ int dcbx_remove_adapter(char *device_name) + LLDPAD_DBG("remove_adapter: oper llink not found\n"); + } + +- lldpad_shm_set_dcbx(device_name, dcbx_subtype0); ++ lldpad_shm_set_dcbx(device_name, DCBX_SUBTYPE0); + return true; + } + +@@ -1343,7 +1343,7 @@ bool add_pg_defaults() + pg_data.tx.up[index].pgid = (u8)(index); + pg_data.tx.up[index].bwgid = (u8)index; + pg_data.tx.up[index].percent_of_pg_cap = BW_PERCENT; +- pg_data.tx.up[index].strict_priority = dcb_none; ++ pg_data.tx.up[index].strict_priority = DCB_NONE; + } + temp = rmndr; + for (index=0; index < MAX_BANDWIDTH_GROUPS; index++) { +@@ -1357,7 +1357,7 @@ bool add_pg_defaults() + pg_data.rx.up[index].pgid = (u8)(index); + pg_data.rx.up[index].bwgid = (u8)index; + pg_data.rx.up[index].percent_of_pg_cap = BW_PERCENT; +- pg_data.rx.up[index].strict_priority = dcb_none; ++ pg_data.rx.up[index].strict_priority = DCB_NONE; + } + + snprintf(sTmp, MAX_DESCRIPTION_LEN, DEF_CFG_STORE); +@@ -1391,7 +1391,7 @@ bool add_pfc_defaults() + pfc_data.protocol.Advertise = 1; + + for (index=0; index < MAX_TRAFFIC_CLASSES; index++) +- pfc_data.admin[index] = pfc_disabled; ++ pfc_data.admin[index] = PFC_DISABLED; + + snprintf(sTmp, MAX_DESCRIPTION_LEN, DEF_CFG_STORE); + /* Create pfc default data store for the device. */ +@@ -1599,9 +1599,9 @@ cmd_status put_pg(char *device_name, pg_attribs *pg_data, pfc_attribs *pfc_data) + feature_protocol_attribs *dStore = &(it->second->protocol); + + if (dStore->Enable && !(pg_data->protocol.Enable)) +- LLDPAD_INFO("%s PG disabled", device_name); ++ LLDPAD_INFO("%s PG disabled\n", device_name); + else if (!(dStore->Enable) && pg_data->protocol.Enable) +- LLDPAD_INFO("%s PG enabled", device_name); ++ LLDPAD_INFO("%s PG enabled\n", device_name); + + dStore->Advertise_prev = dStore->Advertise; + dStore->Advertise = pg_data->protocol.Advertise; +@@ -1611,7 +1611,7 @@ cmd_status put_pg(char *device_name, pg_attribs *pg_data, pfc_attribs *pfc_data) + + memcpy(&(it->second->rx), &(pg_data->rx), sizeof(pg_data->rx)); + memcpy(&(it->second->tx), &(pg_data->tx), sizeof(pg_data->tx)); +- if (it->second->protocol.dcbx_st == dcbx_subtype2) ++ if (it->second->protocol.dcbx_st == DCBX_SUBTYPE2) + it->second->num_tcs = pg_data->num_tcs; + + DCB_SET_FLAGS(EventFlag, DCB_LOCAL_CHANGE_PG); +@@ -1653,7 +1653,7 @@ cmd_status put_peer_pg(char *device_name, pg_attribs *peer_pg_data) + goto Exit; + } + +- if (peer_pg_data->protocol.dcbx_st == dcbx_subtype2) ++ if (peer_pg_data->protocol.dcbx_st == DCBX_SUBTYPE2) + rebalance_uppcts(peer_pg_data); + + /* detect config change */ +@@ -1677,7 +1677,7 @@ cmd_status put_peer_pg(char *device_name, pg_attribs *peer_pg_data) + sizeof(peer_pg_data->rx)); + memcpy(&(peer_it->second->tx), &(peer_pg_data->tx), + sizeof(peer_pg_data->tx)); +- if (peer_it->second->protocol.dcbx_st == dcbx_subtype2) ++ if (peer_it->second->protocol.dcbx_st == DCBX_SUBTYPE2) + peer_it->second->num_tcs = peer_pg_data->num_tcs; + Exit: + return result; +@@ -1765,9 +1765,9 @@ cmd_status put_pfc(char *device_name, pfc_attribs *pfc_data) + feature_protocol_attribs *dStore = &(it->second->protocol); + + if (dStore->Enable && !(pfc_data->protocol.Enable)) +- LLDPAD_INFO("%s PFC disabled", device_name); ++ LLDPAD_INFO("%s PFC disabled\n", device_name); + else if (!(dStore->Enable) && pfc_data->protocol.Enable) +- LLDPAD_INFO("%s PFC enabled", device_name); ++ LLDPAD_INFO("%s PFC enabled\n", device_name); + + dStore->Advertise_prev = dStore->Advertise; + dStore->Advertise = pfc_data->protocol.Advertise; +@@ -1777,7 +1777,7 @@ cmd_status put_pfc(char *device_name, pfc_attribs *pfc_data) + + memcpy(it->second->admin, pfc_data->admin, + sizeof(pfc_data->admin)); +- if (it->second->protocol.dcbx_st == dcbx_subtype2) ++ if (it->second->protocol.dcbx_st == DCBX_SUBTYPE2) + it->second->num_tcs = pfc_data->num_tcs; + + /* Run the protocol */ +@@ -1835,7 +1835,7 @@ cmd_status put_peer_pfc(char *device_name, pfc_attribs *peer_pfc_data) + + memcpy(peer_it->second->admin, &peer_pfc_data->admin, + sizeof(peer_pfc_data->admin)); +- if (peer_it->second->protocol.dcbx_st == dcbx_subtype2) ++ if (peer_it->second->protocol.dcbx_st == DCBX_SUBTYPE2) + peer_it->second->num_tcs = peer_pfc_data->num_tcs; + Exit: + return result; +@@ -1934,9 +1934,9 @@ cmd_status put_app(char *device_name, u32 subtype, app_attribs *app_data) + + feature_protocol_attribs *dStore = &(it->second->protocol); + if (dStore->Enable && !(app_data->protocol.Enable)) +- LLDPAD_INFO("%s APP disabled", device_name); ++ LLDPAD_INFO("%s APP disabled\n", device_name); + else if (!(dStore->Enable) && app_data->protocol.Enable) +- LLDPAD_INFO("%s APP enabled", device_name); ++ LLDPAD_INFO("%s APP enabled\n", device_name); + dStore->Advertise_prev = dStore->Advertise; + dStore->Advertise = app_data->protocol.Advertise; + dStore->Enable = app_data->protocol.Enable; +@@ -2040,9 +2040,9 @@ cmd_status put_llink(char *device_name, u32 subtype, llink_attribs *llink_data) + } + feature_protocol_attribs *dStore = &(it->second->protocol); + if (dStore->Enable && !(llink_data->protocol.Enable)) +- LLDPAD_INFO("%s LLINK disabled", device_name); ++ LLDPAD_INFO("%s LLINK disabled\n", device_name); + else if (!(dStore->Enable) && llink_data->protocol.Enable) +- LLDPAD_INFO("%s LLINK enabled", device_name); ++ LLDPAD_INFO("%s LLINK enabled\n", device_name); + dStore->Advertise_prev = dStore->Advertise; + dStore->Advertise = llink_data->protocol.Advertise; + dStore->Enable = llink_data->protocol.Enable; +@@ -2575,7 +2575,7 @@ bool LocalPeerCompatible(char *device_name, u32 EventFlag, u32 Subtype) + ppg = Peer->second; + + match = true; +- if (ppg->protocol.dcbx_st == dcbx_subtype1) { ++ if (ppg->protocol.dcbx_st == DCBX_SUBTYPE1) { + for (i = 0; i < MAX_USER_PRIORITIES; i++) { + if (lpg->tx.up[i].bwgid != + ppg->tx.up[i].bwgid) +@@ -3180,7 +3180,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype) + goto ErrBadVersion; + } + +- if (feat_prot->dcbx_st == dcbx_subtype2) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE2) { + /* Handle Peer expiration */ + if (peer_ctrl_prot->second->RxDCBTLVState == + DCB_PEER_EXPIRED) { +@@ -3210,7 +3210,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype) + feat_prot->Syncd, __LINE__); + feat_prot->Oper_version = + feat_prot->Max_version; +- if (feat_prot->dcbx_st == dcbx_subtype2) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE2) { + feat_prot->Error = true; + } else { + feat_prot->Error = false; +@@ -3295,7 +3295,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype) + feat_prot->Error_Flag = FEAT_ERR_NONE; + Err = feat_prot->Error; + /* Set_configuration to driver. */ +- if (feat_prot->dcbx_st == dcbx_subtype2) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE2) { + feat_prot->Syncd = !(feat_prot->Error); + feat_prot->Error = false; + if (set_configuration(device_name, +@@ -3323,7 +3323,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype) + feat_prot->Error_Flag = FEAT_ERR_NONE; + Err = feat_prot->Error; + +- if (feat_prot->dcbx_st == dcbx_subtype2) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE2) { + feat_prot->OperMode = + !(peer_feat_prot->Error); + if (feat_prot->OperMode) { +@@ -3375,7 +3375,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype) + Err = feat_prot->Error; + + /* Set_configuration to driver. */ +- if (feat_prot->dcbx_st == dcbx_subtype2) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE2) { + feat_prot->OperMode = + !peer_feat_prot->Error; + feat_prot->Syncd = !(feat_prot->Error); +@@ -3412,7 +3412,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype) + Err = feat_prot->Error; + /* Set_configuration to driver. */ + +- if (feat_prot->dcbx_st == dcbx_subtype2) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE2) { + feat_prot->OperMode = + !peer_feat_prot->Error; + feat_prot->Syncd = !(feat_prot->Error); +@@ -3442,7 +3442,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype) + Err = feat_prot->Error; + + /* Set default configuration */ +- if (feat_prot->dcbx_st == dcbx_subtype2) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE2) { + feat_prot->Syncd = feat_prot->Error; + feat_prot->Error = true; + if (set_configuration(device_name, +@@ -3464,7 +3464,7 @@ ErrProt: + if (peer_feat_prot->Error) + feat_prot->Error_Flag |= FEAT_ERR_PEER; + +- if (feat_prot->dcbx_st == dcbx_subtype1) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE1) { + if (feat_prot->Error || peer_feat_prot->Error){ + LLDPAD_DBG(" ## FEATURE ERROR: " + "%d, %d (Error_Flag 0x%x" +@@ -3483,7 +3483,7 @@ ErrProt: + } + if (ErrorChanged) { + LLDPAD_DBG(" ErrorChanged \n"); +- if (feat_prot->dcbx_st == dcbx_subtype1) { ++ if (feat_prot->dcbx_st == DCBX_SUBTYPE1) { + feat_prot->Syncd = false; + LLDPAD_DBG(" Set Syncd to %u [%u]\n", + feat_prot->Syncd, __LINE__); +@@ -3509,10 +3509,10 @@ OperChange: + if (feat_prot->OperMode != old_pg_opmode) { + pg_events = pg_events | EVENT_OPERMODE; + if (feat_prot->OperMode) { +- LLDPAD_INFO("%s PG oper mode true", ++ LLDPAD_INFO("%s PG oper mode true\n", + device_name); + } else { +- LLDPAD_INFO("%s PG oper mode false", ++ LLDPAD_INFO("%s PG oper mode false\n", + device_name); + } + } +@@ -3534,10 +3534,10 @@ OperChange: + if (feat_prot->OperMode != old_pfc_opmode) { + pfc_events = pfc_events | EVENT_OPERMODE; + if (feat_prot->OperMode) { +- LLDPAD_INFO("%s PFC oper mode true", ++ LLDPAD_INFO("%s PFC oper mode true\n", + device_name); + } else { +- LLDPAD_INFO("%s PFC oper mode false", ++ LLDPAD_INFO("%s PFC oper mode false\n", + device_name); + } + } +@@ -3563,10 +3563,10 @@ OperChange: + if (feat_prot->OperMode != old_app_opmode) { + app_events = app_events | EVENT_OPERMODE; + if (feat_prot->OperMode) { +- LLDPAD_INFO("%s APP oper mode true", ++ LLDPAD_INFO("%s APP oper mode true\n", + device_name); + } else { +- LLDPAD_INFO("%s APP oper mode false", ++ LLDPAD_INFO("%s APP oper mode false\n", + device_name); + } + } +@@ -3836,7 +3836,7 @@ cmd_status run_control_protocol(char *device_name, u32 EventFlag) + return cmd_device_not_found; + } + if (pg_dstore.protocol.dcbx_st == +- dcbx_subtype2) { ++ DCBX_SUBTYPE2) { + return cmd_success; + } else { + /* Send the updated DCB TLV */ +diff --git a/dcb_rule_chk.c b/dcb_rule_chk.c +index ee644f6..bd6d2f2 100644 +--- a/dcb_rule_chk.c ++++ b/dcb_rule_chk.c +@@ -144,9 +144,9 @@ static int dcb_fixup_pg(struct pg_attribs *fixpg, struct pfc_attribs *fixpfc) + if (!entry) + continue; + +- if (entry->strict_priority == dcb_link) ++ if (entry->strict_priority == DCB_LINK) + strict++; +- else if (fixpfc && fixpfc->admin[j] == pfc_enabled) ++ else if (fixpfc && fixpfc->admin[j] == PFC_ENABLED) + pfc++; + else + be++; +@@ -188,11 +188,11 @@ static int dcb_fixup_pg(struct pg_attribs *fixpg, struct pfc_attribs *fixpfc) + continue; + + if (pgid < 0) { +- if (entry->strict_priority == dcb_link) { ++ if (entry->strict_priority == DCB_LINK) { + pgid = cbe + cpfc + strict; + strict++; + } else if (fixpfc && +- fixpfc->admin[j] == pfc_enabled) { ++ fixpfc->admin[j] == PFC_ENABLED) { + pgid = cbe + pfc; + pfc++; + } else { +@@ -252,7 +252,7 @@ static int dcb_fixup_pg(struct pg_attribs *fixpg, struct pfc_attribs *fixpfc) + for (i = 0; i < MAX_USER_PRIORITIES; i++) { + fixpg->tx.up[i].bwgid = i; + +- if (fixpg->tx.up[i].strict_priority == dcb_link) { ++ if (fixpg->tx.up[i].strict_priority == DCB_LINK) { + fixpg->tx.up[i].percent_of_pg_cap = 0; + fixpg->rx.up[i].percent_of_pg_cap = 0; + } else { +@@ -314,7 +314,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + + /* Internally in the pg_attribs structure, a link strict PGID is + * maintained as a PGID value (0-7) with a corresponding +- * strict_priority field value of 'dcb_link'. Only one link strict ++ * strict_priority field value of 'DCB_LINK'. Only one link strict + * PGID is allowed. + */ + link_strict_pgid = LINK_STRICT_PGID; +@@ -323,7 +323,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + tx_bw = tx_bw + pg->tx.pg_percent[i]; + + /* check for >1 link strict PGID */ +- if (pg->tx.up[i].strict_priority == dcb_link) { ++ if (pg->tx.up[i].strict_priority == DCB_LINK) { + if (link_strict_pgid == LINK_STRICT_PGID) { + link_strict_pgid = pg->tx.up[i].pgid; + } else if (pg->tx.up[i].pgid != link_strict_pgid) { +@@ -343,7 +343,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + */ + for (i = 0; i < MAX_BW_GROUP; i++) { + if ((tx_bw != 0) || (pg->tx.up[i].strict_priority != +- dcb_link)) { ++ DCB_LINK)) { + LLDPAD_INFO("Invalid tx total BWG %d\n", + (int)tx_bw); + return cmd_bad_params; +@@ -356,7 +356,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + rx_bw = rx_bw + pg->rx.pg_percent[i]; + + /* check for >1 link strict PGID */ +- if (pg->rx.up[i].strict_priority == dcb_link) { ++ if (pg->rx.up[i].strict_priority == DCB_LINK) { + if (link_strict_pgid == LINK_STRICT_PGID) { + link_strict_pgid = pg->rx.up[i].pgid; + } else if (pg->rx.up[i].pgid != link_strict_pgid) { +@@ -376,7 +376,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + */ + for (i = 0; i < MAX_BW_GROUP; i++) { + if ((rx_bw != 0) || (pg->rx.up[i].strict_priority != +- dcb_link)) { ++ DCB_LINK)) { + LLDPAD_INFO("Invalid RX total BWG %d\n", + (int)rx_bw); + return cmd_bad_params; +@@ -403,7 +403,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + (int)tx_bw_id); + return cmd_bad_params; + } +- if (pg->tx.up[i].strict_priority == dcb_link) { ++ if (pg->tx.up[i].strict_priority == DCB_LINK) { + tx_link_strict[tx_bw_id] = true; + /* Link strict should have zero bandwidth */ + if (tx_bw){ +@@ -412,7 +412,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + return cmd_bad_params; + } + } else if (!tx_bw) { +- LLDPAD_INFO("Zero BW on non LSP tc %i", i); ++ LLDPAD_INFO("Zero BW on non LSP tc %i\n", i); + /* Non link strict should have non zero bandwidth*/ + return cmd_bad_params; + } +@@ -422,10 +422,10 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + rx_bw_id = (u8)(pg->rx.up[i].bwgid); + + if (rx_bw_id >= MAX_BW_GROUP) { +- LLDPAD_INFO("Invalid RX BW %i", rx_bw_id); ++ LLDPAD_INFO("Invalid RX BW %i\n", rx_bw_id); + return cmd_bad_params; + } +- if (pg->rx.up[i].strict_priority == dcb_link) { ++ if (pg->rx.up[i].strict_priority == DCB_LINK) { + rx_link_strict[rx_bw_id] = true; + /* Link strict class should have zero bandwidth */ + if (rx_bw){ +@@ -434,7 +434,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + return cmd_bad_params; + } + } else if (!rx_bw) { +- LLDPAD_INFO("Zero BW on no LSP tc %i", i); ++ LLDPAD_INFO("Zero BW on no LSP tc %i\n", i); + /* Non link strict class should have non-zero bw */ + return cmd_bad_params; /* DCB_RX_ERR_TC_BW_ZERO; */ + } +@@ -451,13 +451,13 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + */ + if (tx_link_strict[i]) { + if (tx_bw_sum[i] && pg->tx.pg_percent[i]) { +- LLDPAD_INFO("Non-zero LSP BW %d %d\n", ++ LLDPAD_INFO("Non-zero TX LSP BW %d %d\n", + i, (int)tx_bw_sum[i]); + /* Link strict group should have zero bw */ + return cmd_bad_params; + } + } else if (tx_bw_sum[i] != BW_PERCENT && tx_bw_sum[i] != 0) { +- LLDPAD_INFO("Invalid BW sum on BWG %i %i", ++ LLDPAD_INFO("Invalid TX BW sum on BWG %i %i\n", + i, (int)tx_bw_sum[i]); + return cmd_bad_params; + } +@@ -470,13 +470,13 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs) + */ + if (rx_link_strict[i]) { + if (rx_bw_sum[i] && pg->rx.pg_percent[i]) { +- LLDPAD_INFO("Non-zero BW on LSP tc " +- "%u %u\n", i, rx_bw_sum[i]); ++ LLDPAD_INFO("Non-zero RX LSP BW %d %d\n", ++ i, (int)rx_bw_sum[i]); + /* Link strict group should have zero bw */ + return cmd_bad_params; + } + } else if (rx_bw_sum[i] != BW_PERCENT && rx_bw_sum[i] != 0) { +- LLDPAD_INFO("Invalid BW sum on BWG %i %i", ++ LLDPAD_INFO("Invalid RX BW sum on BWG %i %i\n", + i, (int)rx_bw_sum[i]); + return cmd_bad_params; + } +@@ -517,7 +517,7 @@ void rebalance_uppcts(pg_attribs *pg) + for (i = 0; i < MAX_USER_PRIORITIES; i++) { + if (pg->tx.up[i].bwgid == bwgid) { + uplist[num_found++] = (u8)i; +- if (pg->tx.up[i].strict_priority == dcb_link) { ++ if (pg->tx.up[i].strict_priority == DCB_LINK) { + link_strict = true; + pg->tx.up[i].percent_of_pg_cap = 0; + pg->rx.up[i].percent_of_pg_cap = 0; +@@ -535,8 +535,8 @@ void rebalance_uppcts(pg_attribs *pg) + } + pg->tx.up[uplist[i]].percent_of_pg_cap = (u8)value; + pg->rx.up[uplist[i]].percent_of_pg_cap = (u8)value; +- pg->tx.up[uplist[i]].strict_priority = dcb_none; +- pg->rx.up[uplist[i]].strict_priority = dcb_none; ++ pg->tx.up[uplist[i]].strict_priority = DCB_NONE; ++ pg->rx.up[uplist[i]].strict_priority = DCB_NONE; + } + } + } +diff --git a/dcbtool_cmds.c b/dcbtool_cmds.c +index b36c522..a5cd0fe 100644 +--- a/dcbtool_cmds.c ++++ b/dcbtool_cmds.c +@@ -465,7 +465,7 @@ void print_dcb_cmd_response(char *buf, int status) + int version; + int dcb_cmd; + int feature; +- int dcbx_st = dcbx_subtype1; ++ int dcbx_st = DCBX_SUBTYPE1; + int subtype = 0; + int plen = 0; + int doff; +@@ -634,16 +634,16 @@ void print_dcb_cmd_response(char *buf, int status) + case FEATURE_DCBX: + printf("DCBX Version:\t"); + switch (*(buf+doff+DCBX_VERSION) ^ '0') { +- case dcbx_subtype1: ++ case DCBX_SUBTYPE1: + printf("CIN\n"); + break; +- case dcbx_subtype2: ++ case DCBX_SUBTYPE2: + printf("CEE\n"); + break; +- case dcbx_force_subtype1: ++ case DCBX_FORCE_SUBTYPE1: + printf("FORCED CIN\n"); + break; +- case dcbx_force_subtype2: ++ case DCBX_FORCE_SUBTYPE2: + printf("FORCED CEE\n"); + break; + default: +@@ -680,7 +680,7 @@ void print_dcb_cmd_response(char *buf, int status) + printf("\n"); + + if ((dcb_cmd != CMD_GET_PEER) || +- (dcb_cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1)) { ++ (dcb_cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1)) { + printf("uppct: \t"); + for (i=0; iifname, MAX_DEVICE_NAME_LEN)) ++ ifindex = get_ifidx(device_name); ++ for (port = porthead; port; port = port->next) ++ if (ifindex == port->ifindex) + break; +- port = port->next; +- } + + if (!port) { +- newport = add_port(device_name); +- +- if (newport == NULL) { ++ newport = add_port(ifindex, device_name); ++ if (!newport) { + LLDPAD_INFO("%s: Error adding device %s\n", +- __func__, device_name); ++ __func__, device_name); + return -EINVAL; + } + +@@ -232,6 +230,7 @@ static void event_if_decode_nlmsg(int route_type, void *data, int len) + struct rtattr *rta; + char device_name[IFNAMSIZ]; + struct lldp_agent *agent; ++ int ifindex; + int attrlen; + int valid; + int link_status = IF_OPER_UNKNOWN; +@@ -241,13 +240,13 @@ static void event_if_decode_nlmsg(int route_type, void *data, int len) + case RTM_DELLINK: + case RTM_SETLINK: + case RTM_GETLINK: ++ ifindex = ((struct ifinfomsg *)data)->ifi_index; + LLDPAD_DBG(" IFINFOMSG\n"); + LLDPAD_DBG(" ifi_family = 0x%02x\n", + ((struct ifinfomsg *)data)->ifi_family); + LLDPAD_DBG(" ifi_type = 0x%x\n", + ((struct ifinfomsg *)data)->ifi_type); +- LLDPAD_DBG(" ifi_index = %i\n", +- ((struct ifinfomsg *)data)->ifi_index); ++ LLDPAD_DBG(" ifi_index = %i\n", ifindex); + LLDPAD_DBG(" ifi_flags = 0x%04x\n", + ((struct ifinfomsg *)data)->ifi_flags); + LLDPAD_DBG(" ifi_change = 0x%04x\n", +@@ -274,7 +273,7 @@ static void event_if_decode_nlmsg(int route_type, void *data, int len) + if (!valid) + break; + +- struct port *port = port_find_by_name(device_name); ++ struct port *port = port_find_by_ifindex(ifindex); + if (!port) + break; + +diff --git a/include/clif.h b/include/clif.h +index fa19149..648eedf 100644 +--- a/include/clif.h ++++ b/include/clif.h +@@ -152,8 +152,12 @@ int clif_recv(struct clif *clif, char *reply, size_t *reply_len); + * message available to be received with clif_recv(). clif_pending() is + * only used for event messages, i.e., clif_attach() must have been used to + * register the client interface as an event monitor. ++ * ++ * clif_pending_wait - Same as clif_pending, but allows the specification ++ * of maximum wait time in seconds. + */ + int clif_pending(struct clif *clif); ++int clif_pending_wait(struct clif *clif, int waittime); + + + /** +@@ -180,4 +184,70 @@ int clif_get_fd(struct clif *clif); + * its PID. Extract the PID and return it to the caller. + */ + pid_t clif_getpid(void); ++ ++/** ++ * clif_vsi - Send a VDP22 association command to the running lldpad process ++ * @clif: Control interface data from clif_open() ++ * @ifname: Name of the interface to apply the VSI command ++ * @tlvid: Number of tlv identifier ++ * @cmd: Buffer containing the VSI command ++ * @reply: Buffer for the reply data ++ * @reply_len: Length of the reply buffer ++ * Returns: cmd_success when VSI command was accepted and cmd_failure if not. ++ * ++ * This commands sends an VSI association command encoded as ascii string ++ * to the lldpad VPD22 module. The module decodes the ascii string and checks ++ * for consistency. Any white space in the ascii string is removed. The ++ * format of the ascii string is explained in the man page. ++ * ++ * If the command is invalid cmd_failure is returned. ++ * Other cmd_success is returned. In this case the command was accepted and ++ * sent to the switch. The switch may still deny the request. The switch ++ * response is sent via an event message. ++ * ++ * Note: This command can only be sent when the clif_attach() functions has ++ * been called with successful return code. ++ */ ++int clif_vsi(struct clif *clif, char *ifname, unsigned int tlvid, char *cmd, ++ char *reply, size_t *reply_len); ++ ++/** ++ * clif_vsievt - Wait for event message from lldpad after clif_vsi() ++ * @clif: Control interface data from clif_open() ++ * @reply: Buffer for the reply data ++ * @reply_len: Length of the reply buffer ++ * @waittime: Maximum number of seconds to wait for event message ++ * Returns: ++ * 0: on success (a message was received and reply_len contains the number ++ * of bytes of the message) ++ * -EINVAL: Invalid parameters, for example negative wait time. ++ * -EAGAIN: No message received. ++ * -EIO: Message pending but receive function failed. ++ * -EBADF: Message received but was no event message. ++ * ++ * This function waits up to waittime seconds for an event message from ++ * lldpad. An event message is expected when the clif_vsi() successfully ++ * submitted an VSI command. The event message contains the reply from the ++ * switch. The event message is in acsii and the format is explained in the ++ * man page. ++ */ ++int clif_vsievt(struct clif *clif, char *reply, size_t *reply_len, int waitime); ++ ++/** ++ * clif_vsiwait - Send VSI command and wait for event message. ++ * @clif: Control interface data from clif_open() ++ * @ifname: Name of the interface to apply the VSI command ++ * @tlvid: Number of tlv identifier ++ * @cmd: Buffer containing the VSI command ++ * @reply: Buffer for the reply data ++ * @reply_len: Length of the reply buffer ++ * @waittime: Maximum number of seconds to wait for event message ++ * Returns: see clif_vsi() and clif_vsievt(). ++ * ++ * This function is a combination of clif_vsi() and clif_vsievt(). It sends ++ * the vsi command and on successful reception of the VSI command calls ++ * clif_vsievt() to receive the response. ++ */ ++int clif_vsiwait(struct clif *clif, char *ifname, unsigned int tlvid, ++ char *cmd, char *reply, size_t *reply_len, int waittime); + #endif /* CLIF_H */ +diff --git a/include/dcb_types.h b/include/dcb_types.h +index 34d88d6..23cf264 100644 +--- a/include/dcb_types.h ++++ b/include/dcb_types.h +@@ -41,11 +41,11 @@ + + /* DCBX subtypes */ + typedef enum { +- dcbx_subtype0 = 0, /* auto IEEE */ +- dcbx_subtype1 = 1, /* CIN */ +- dcbx_subtype2 = 2, /* CEE */ +- dcbx_force_subtype1 = 5,/* FORCE CIN */ +- dcbx_force_subtype2 = 6,/* FORCE CEE */ ++ DCBX_SUBTYPE0 = 0, /* auto IEEE */ ++ DCBX_SUBTYPE1 = 1, /* CIN */ ++ DCBX_SUBTYPE2 = 2, /* CEE */ ++ DCBX_FORCE_SUBTYPE1 = 5,/* FORCE CIN */ ++ DCBX_FORCE_SUBTYPE2 = 6,/* FORCE CEE */ + } dcbx_subtype; + + +@@ -54,9 +54,9 @@ typedef enum { + + /* PFC configuration */ + typedef enum { +- pfc_disabled = 0x000, +- pfc_enabled, +- pfc_invalid, ++ PFC_DISABLED = 0x000, ++ PFC_ENABLED, ++ PFC_INVALID, + } pfc_type; + + /* Peer DCB TLV States */ +@@ -70,10 +70,10 @@ typedef enum { + typedef pfc_type dcb_pfc_type; + + typedef enum { +- dcb_none = 0x0000, +- dcb_group, +- dcb_link, +- dcb_invalid, ++ DCB_NONE = 0x0000, ++ DCB_GROUP, ++ DCB_LINK, ++ DCB_INVALID, + } dcb_strict_priority_type; + + typedef pfc_type dcb_pfc_list_type[MAX_USER_PRIORITIES]; +diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h +index 66a6723..503bad3 100644 +--- a/include/linux/dcbnl.h ++++ b/include/linux/dcbnl.h +@@ -11,8 +11,8 @@ + * more details. + * + * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple +- * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Author: Lucy Liu + */ +diff --git a/include/lldp_8021qaz.h b/include/lldp_8021qaz.h +index 461cca2..55353b8 100644 +--- a/include/lldp_8021qaz.h ++++ b/include/lldp_8021qaz.h +@@ -238,5 +238,6 @@ inline int ieee8021qaz_clif_cmd(void *data, struct sockaddr_un *from, + socklen_t fromlen, char *ibuf, int ilen, + char *rbuf); + int ieee8021qaz_check_operstate(void); ++int get_dcbx_hw(const char *ifname, __u8 *dcbx); + + #endif /* _LLDP_8021QAZ_H */ +diff --git a/include/lldp_dcbx_cmds.h b/include/lldp_dcbx_cmds.h +index 9e9603d..39661e7 100644 +--- a/include/lldp_dcbx_cmds.h ++++ b/include/lldp_dcbx_cmds.h +@@ -31,7 +31,7 @@ + #include + #include "clif_msgs.h" + +-struct arg_handlers *dcbx_get_arg_handlers(); ++struct arg_handlers *dcbx_get_arg_handlers(void); + void dont_advertise_dcbx_all(char *ifname, bool ad); + + #define CLIF_RSP_MSG_OFF 0 +diff --git a/include/lldp_ecp.h b/include/lldp_ecp.h +deleted file mode 100644 +index aa388c6..0000000 +--- a/include/lldp_ecp.h ++++ /dev/null +@@ -1,106 +0,0 @@ +-/******************************************************************************* +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Jens Osterkamp +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-#ifndef LLDP_ECP_H +-#define LLDP_ECP_H +- +-#include +- +-#include "lldp_mod.h" +-#include "lldp_vdp.h" +- +-#define ECP_SUBTYPE 0x0 +- +-#define ECP_MAX_RETRIES 3 +-#define ECP_SEQUENCE_NR_START 0x0 +- +-#define MSECS 1000 +-#define SECS (1000 * MSECS) +- +-#define ECP_ACK_TIMER_DEFAULT (500 * MSECS) /* 500 ms */ +-#define ECP_LOCALCHANGE_TIMEOUT (1 * MSECS) /* 1 ms */ +- +-#define ECP_ACK_TIMER_STOPPED (-1) +- +-typedef enum { +- ECP_REQUEST = 0, +- ECP_ACK +-} ecp_mode; +- +-struct ecp_buffer { /* ECP payload buffer */ +- u8 frame[ETH_FRAME_LEN]; /* Payload buffer */ +- u16 frame_len; /* # of bytes of valid data */ +- u8 state; /* Buffer state */ +- u8 localChange; /* Status changed */ +- u8 rcvFrame; /* True if new frame received */ +-}; +- +-struct ecp { +- struct l2_packet_data *l2; +- int sequence; +- int retries; +- int ackReceived; +- int ackTimer; +- u16 lastSequence; +- u16 seqECPDU; +- struct ecp_buffer rx; /* Receive buffer */ +- struct ecp_buffer tx; /* Transmit buffer */ +- struct agentstats stats; +- char ifname[IFNAMSIZ]; /* Interface name */ +-}; +- +-struct ecp_hdr { +- u8 oui[3]; +- u8 pad1; +- u16 subtype; +- u8 mode; +- u16 seqnr; +-} __attribute__ ((__packed__)); +- +-enum { +- ECP_TX_INIT_TRANSMIT, +- ECP_TX_TRANSMIT_ECPDU, +- ECP_TX_WAIT_FOR_ACK, +- ECP_TX_REQUEST_PDU +-}; +- +-enum { +- ECP_RX_IDLE, +- ECP_RX_INIT_RECEIVE, +- ECP_RX_RECEIVE_WAIT, +- ECP_RX_RECEIVE_ECPDU, +- ECP_RX_SEND_ACK, +- ECP_RX_RESEND_ACK, +-}; +- +-struct vdp_data; +- +-void ecp_somethingChangedLocal(struct vdp_data *, bool); +-void ecp_rx_send_ack_frame(struct vdp_data *); +- +-int ecp_init(char *); +-int ecp_deinit(char *); +-#endif /* _ECP_H */ +diff --git a/include/lldp_ecp22.h b/include/lldp_ecp22.h +deleted file mode 100644 +index 50a1b44..0000000 +--- a/include/lldp_ecp22.h ++++ /dev/null +@@ -1,172 +0,0 @@ +-/******************************************************************************* +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2013 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-#ifndef LLDP_ECP22_H +-#define LLDP_ECP22_H +- +-#include +- +-#include "lldp_mod.h" +-#include "lldp_qbg22.h" +- +-enum { /* ECP Receive states */ +- ECP22_RX_BEGIN, +- ECP22_RX_WAIT, +- ECP22_RX_WAIT2, +- ECP22_RX_FIRST, +- ECP22_RX_REC_ECPDU, +- ECP22_RX_NEW_ECPDU, +- ECP22_RX_SEND_ACK +-}; +-enum { /* ECP Transmit states */ +- ECP22_TX_BEGIN, +- ECP22_TX_INIT, +- ECP22_TX_TXMIT_ECPDU, +- ECP22_TX_WAIT_FORREQ, +- ECP22_TX_WAIT_ONDATA, +- ECP22_TX_ERROR +-}; +- +-enum { +- ECP22_REQUEST = 0, +- ECP22_ACK +-} ecp22_mode; +- +-struct ecp22_hdr { /* ECP22 header */ +- u16 ver_op_sub; /* ECP22 version, operation, subtype */ +- u16 seqno; /* ECP22 sequence number */ +-} __attribute__ ((__packed__)); +- +-/* +- * Define maximum ECP protocol payload length. Leave room for END TLV. +- */ +-#define ECP22_MAXPAYLOAD_LEN (ETH_DATA_LEN - sizeof(struct ecp22_hdr) - 2) +- +-struct ecp22_buffer { /* ECP payload buffer */ +- unsigned char frame[ETH_FRAME_LEN]; /* Payload buffer */ +- unsigned short frame_len; /* # of bytes of valid data */ +- unsigned char state; /* Buffer state machine */ +- unsigned char ecpdu_received; /* True when packet received */ +- unsigned char ack_received; /* True when packet acknowledged */ +- unsigned char retries; /* # of retries */ +- unsigned short last_seqno; /* Seqno last acknowledged packet */ +- unsigned short seqno; /* Seqno this packet */ +- unsigned long errors; /* # of transmit errors */ +-}; +- +-struct ecp22_payload_node { /* ECP Payload node */ +- struct packed_tlv *ptlv; /* Pointer to packed TLV to send */ +- unsigned short subtype; /* ECP subtype*/ +- unsigned char mac[ETH_ALEN]; /* Destination MAC address */ +- LIST_ENTRY(ecp22_payload_node) node; +-}; +- +-/* +- * ECP22 payload data +- */ +-typedef LIST_HEAD(ecp22_list, ecp22_payload_node) ecp22_list; +- +-struct ecp22_usedlist { /* List of valid ecp_payload_nodes */ +- ecp22_list head; /* ECP payload data free list */ +- struct ecp22_payload_node *last; /* Ptr to last entry in list */ +-}; +- +-struct ecp22_freelist { /* List of free ecp_payload_nodes */ +- ecp22_list head; /* ECP payload data free list */ +- u16 freecnt; /* # of nodes on freelist */ +-}; +- +-enum { +- ecp22_maxpayload = 64 +-}; +- +-struct ecp22 { /* ECP protocol data per interface */ +- struct l2_packet_data *l2; +- char ifname[IFNAMSIZ]; /* Interface name */ +- LIST_ENTRY(ecp22) node; /* Successor */ +- struct ecp22_buffer rx; /* Receive buffer */ +- struct ecp22_buffer tx; /* Transmit buffer */ +- struct agentstats stats; +- struct ecp22_usedlist inuse; /* List of payload data */ +- struct ecp22_freelist isfree; /* List of free payload nodes */ +- unsigned char max_retries; /* Max # of retries (via EVB) */ +- unsigned char max_rte; /* Wait time for ack (via EVB) */ +-}; +- +-struct ecp22_user_data { /* ECP module data per interface */ +- LIST_HEAD(ecp_head, ecp22) head; +-}; +- +-/* +- * Function prototypes +- */ +-struct lldp_module *ecp22_register(void); +-void ecp22_unregister(struct lldp_module *); +-void ecp22_stop(char *); +-void ecp22_start(char *); +- +-/* +- * Functions to set and read ecp header operations field. +- */ +-static inline void ecp22_hdr_set_op(struct ecp22_hdr *p, unsigned int op) +-{ +- p->ver_op_sub &= 0xf3ff; +- p->ver_op_sub |= (op & 0x3) << 10; +-} +- +-static inline unsigned int ecp22_hdr_read_op(struct ecp22_hdr *p) +-{ +- return (p->ver_op_sub >> 10) & 3; +-} +- +-/* +- * Functions to set and read ecp header subtype field. +- */ +-static inline void ecp22_hdr_set_subtype(struct ecp22_hdr *p, unsigned int sub) +-{ +- p->ver_op_sub &= 0xfc00; +- p->ver_op_sub |= sub & 0x3ff; +-} +- +-static inline unsigned int ecp22_hdr_read_subtype(struct ecp22_hdr *p) +-{ +- return p->ver_op_sub & 0x3ff; +-} +- +-/* +- * Functions to set and read ecp header version field. +- */ +-static inline void ecp22_hdr_set_version(struct ecp22_hdr *p, unsigned int ver) +-{ +- p->ver_op_sub &= 0xfff; +- p->ver_op_sub |= (ver & 0xf) << 12; +-} +- +-static inline unsigned int ecp22_hdr_read_version(struct ecp22_hdr *p) +-{ +- return (p->ver_op_sub >> 12) & 0xf; +-} +- +-#endif +diff --git a/include/lldp_evb22.h b/include/lldp_evb22.h +index c5255dc..36fcc13 100644 +--- a/include/lldp_evb22.h ++++ b/include/lldp_evb22.h +@@ -27,7 +27,7 @@ + #define _LLDP_EVB22_H + + #include "lldp_mod.h" +-#include "lldp_qbg22.h" ++#include "qbg22.h" + + #define LLDP_MOD_EVB22_SUBTYPE 0xd + #define LLDP_MOD_EVB22_OUI { 0x00, 0x80, 0xc2, LLDP_MOD_EVB22_SUBTYPE } +@@ -38,9 +38,9 @@ enum { /* EVB bit definitions defines */ + EVB_RRCTR = 0x1, /* Bridge reflective relay control */ + EVB_SGID = 0x8, /* Station group ID */ + EVB_RRREQ = 0x4, /* Station reflective relay request */ +- EVB_RRSTAT_YES = 0x2, /* Station reflective relay status TRUE */ ++ EVB_RRSTAT_YES = 0x1, /* Station reflective relay status TRUE */ + EVB_RRSTAT_NO = 0x0, /* Station reflective relay status NO */ +- EVB_RRSTAT_DONT = 0x1, /* Station reflective relay status unknown */ ++ EVB_RRSTAT_DONT = 0x3, /* Station reflective relay status unknown */ + EVB_ROL = 0x20, /* Remote or local indicator */ + EVB_BRIDGE = 0x1, /* EVB Bridge */ + EVB_STATION = 0x2 /* EVB Station */ +diff --git a/include/lldp_qbg22.h b/include/lldp_qbg22.h +deleted file mode 100644 +index 1007bd9..0000000 +--- a/include/lldp_qbg22.h ++++ /dev/null +@@ -1,87 +0,0 @@ +-/******************************************************************************* +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2013 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-/* +- * Define IEEE 802.1Qbg module identification numbers and module interface +- * structures which are exchanged between all the qbg modules. +- * +- * Messages are sent from: +- * EVB --> ECP: Max number of retries (R) and retransmit timeout (RTE). +- * +- * EVB --> VDP: Max number of Reinit-keep-Alive (RKA) Resource wait delay (RWD) +- * and groupid support. +- * +- * VDP --> ECP: VSI Information as payload +- * ECP --> VDP: VSI Information as payload +- * +- * This is used in the module notify call back function. +- */ +- +-#ifndef LLDP_QBG22_H +-#define LLDP_QBG22_H +- +-/* +- * Modules Identifications +- */ +-#define LLDP_MOD_EVB22 0x80c2 +-#define LLDP_MOD_ECP22 0x80c3 +-#define LLDP_MOD_VDP22 0x80c4 +- +- +-enum { /* Identify data type in union below */ +- EVB22_TO_ECP22 = 1, /* Data from EVB to ECP */ +- EVB22_TO_VDP22 = 2, /* Data from EVB to VDP */ +- ECP22_TO_ULP = 3, /* Data from ECP to VDP, etc */ +- VDP22_TO_ECP22 = 4, /* Data from VDP to ECP */ +- /* ECP22 subtypes */ +- ECP22_VDP = 1, /* VDP protocol */ +- ECP22_PECSP = 2 /* Port extender control and status protocol */ +-}; +- +-struct evb22_to_ecp22 { /* Notification from EVB to ECP */ +- unsigned char max_retry;/* Max number of retries */ +- unsigned char max_rte; /* Max number of acknowledgement wait */ +-}; +- +-struct evb22_to_vdp22 { /* Notification from EVB to VDP */ +- unsigned char max_rwd; /* Max number of resource wait delay */ +- unsigned char max_rka; /* Max number of reinit keep alive */ +- unsigned char gpid; /* Support group ids in VDP */ +-}; +- +-struct ecp22_to_ulp { /* Notification from ECP to VDP, etc */ +- unsigned short len; /* Size of bytestream */ +- void *data; /* Pointer to data */ +-}; +- +-struct qbg22_imm { /* Intermodule message data structure */ +- int data_type; /* Identifies union data */ +- union { /* Overlay possible data */ +- struct evb22_to_ecp22 a; +- struct evb22_to_vdp22 b; +- struct ecp22_to_ulp c; +- } u; +-}; +-#endif +diff --git a/include/lldp_qbg_utils.h b/include/lldp_qbg_utils.h +deleted file mode 100644 +index 9f465c4..0000000 +--- a/include/lldp_qbg_utils.h ++++ /dev/null +@@ -1,43 +0,0 @@ +-/******************************************************************************* +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2010, 2013 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-/* +- * Header file for small utility functions called throught qbg modules. +- */ +- +-#ifndef LLDP_QBG_UTILS_H +-#define LLDP_QBG_UTILS_H +- +-void hexdump_frame(const char *, char *, const unsigned char *, size_t); +-int modules_notify(int, int, char *, void *); +- +-/* +- * Required buffer space to display a UUID. +- * VDP_UUID_STRLEN = strlen("fa9b7fff-b0a0-4893-abcd-beef4ff18f8f") +- */ +-#define VDP_UUID_STRLEN 36 +- +-int vdp_uuid2str(const u8 *, char *, size_t); +-#endif +diff --git a/include/lldp_rtnl.h b/include/lldp_rtnl.h +index 76425e6..c21236d 100644 +--- a/include/lldp_rtnl.h ++++ b/include/lldp_rtnl.h +@@ -31,19 +31,8 @@ + #define IFNAMSIZ 16 + #endif + +-#include "include/linux/netlink.h" +- +-/* +- * Helper functions to construct a netlink message. +- */ +-void mynla_nest_end(struct nlmsghdr *, struct nlattr *); +-struct nlattr *mynla_nest_start(struct nlmsghdr *, int); +-void mynla_put(struct nlmsghdr *, int, size_t, void *); +-void mynla_put_u16(struct nlmsghdr *, int, __u16); +-void mynla_put_u32(struct nlmsghdr *, int, __u32); +- + int get_operstate(char *ifname); + int set_operstate(char *ifname, __u8 operstate); +-int set_linkmode(const char *ifname, __u8 linkmode); ++int set_linkmode(int ifindex, const char *ifname, __u8 linkmode); + + #endif +diff --git a/include/lldp_util.h b/include/lldp_util.h +index ee9e6e6..5767d4e 100644 +--- a/include/lldp_util.h ++++ b/include/lldp_util.h +@@ -142,6 +142,7 @@ int is_autoneg_supported(const char *ifname); + int get_mtu(const char *); + int get_mfs(const char *); + int get_ifflags(const char *); ++int get_ifname(int ifindex, char *ifname); + int get_maucaps(const char *); + int get_mautype(const char *); + int get_ifpflags(const char *); +diff --git a/include/lldp_vdp.h b/include/lldp_vdp.h +deleted file mode 100644 +index 1e2908b..0000000 +--- a/include/lldp_vdp.h ++++ /dev/null +@@ -1,170 +0,0 @@ +-/******************************************************************************* +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Jens Osterkamp +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-#ifndef _LLDP_VDP_H +-#define _LLDP_VDP_H +- +-#include "lldp_mod.h" +-#include "lldp_ecp.h" +- +-#define LLDP_MOD_VDP (OUI_IEEE_8021Qbg + 1) +- +-#define VDP_MODE_PREASSOCIATE 0x0 +-#define VDP_MODE_PREASSOCIATE_WITH_RR 0x1 +-#define VDP_MODE_ASSOCIATE 0x2 +-#define VDP_MODE_DEASSOCIATE 0x3 +- +-#define VDP_RESPONSE_SUCCESS 0x0 +-#define VDP_RESPONSE_INVALID_FORMAT 0x1 +-#define VDP_RESPONSE_INSUFF_RESOURCES 0x2 +-#define VDP_RESPONSE_UNUSED_VTID 0x3 +-#define VDP_RESPONSE_VTID_VIOLATION 0x4 +-#define VDP_RESPONSE_VTID_VER_VIOLATION 0x5 +-#define VDP_RESPONSE_OUT_OF_SYNC 0x6 +-#define VDP_RESPONSE_UNKNOWN 0xfe +-#define VDP_RESPONSE_NO_RESPONSE 0xff +- +-extern const char * const vsi_states[]; +- +-#define VDP_FILTER_INFO_FORMAT_VID 0x1 +-#define VDP_FILTER_INFO_FORMAT_MACVID 0x2 +-#define VDP_FILTER_INFO_FORMAT_GROUPVID 0x3 +-#define VDP_FILTER_INFO_FORMAT_GROUPMACVID 0x4 +- +-#define VDP_TIMER_GRANULARITY (100 * MSECS) /* 100 ms */ +-#define VDP_KEEPALIVE_TIMER_DEFAULT (10 * SECS) /* 10s */ +-#define VDP_ACK_TIMER_DEFAULT (2 * ECP_ACK_TIMER_DEFAULT * ECP_MAX_RETRIES) +-#define VDP_KEEPALIVE_TIMER_STOPPED (-1) +-#define VDP_ACK_TIMER_STOPPED (-1) +-#define VDP_LOCALCHANGE_TIMEOUT (1 * MSECS) /* 1 ms */ +- +-#define VDP_ROLE_STATION 0 +-#define VDP_ROLE_BRIDGE 1 +- +-enum { +- VSI_UNASSOCIATED = 0, +- VSI_ASSOC_PROCESSING, +- VSI_ASSOCIATED, +- VSI_PREASSOC_PROCESSING, +- VSI_PREASSOCIATED, +- VSI_DEASSOC_PROCESSING, +- VSI_EXIT, +-}; +- +-struct mac_vlan_p { +- u8 mac[6]; +- u16 vlan; +-} __attribute__ ((__packed__)); +- +-struct mac_vlan { /* MAC,VLAN entry anchored by profiles */ +- u8 mac[6]; +- u16 vlan; +- u8 qos; /* QOS field */ +- pid_t req_pid; /* PID of requester for this profile */ +- u32 req_seq; /* Seq # of requester for this profile */ +- LIST_ENTRY(mac_vlan) entry; +-}; +- +-struct tlv_info_vdp { /* VSI information in packet format */ +- u8 oui[3]; +- u8 sub; +- u8 mode; +- u8 response; +- u8 mgrid; +- u8 id[3]; +- u8 version; +- u8 instance[16]; +- u8 format; +- u16 entries; +-} __attribute__ ((__packed__)); +- +-struct vsi_profile { +- int mode; /* VSI profile association command */ +- int response; /* Response from switch */ +- u8 no_nlmsg; /* Don't send netlink msg on VSI_EXIT */ +- u8 mgrid; /* Profile mgr id */ +- int id; /* Profile id */ +- u8 version; /* Profile id version number */ +- u8 instance[16]; /* Profile UUID */ +- u8 format; /* Format of MAC,VLAN list */ +- u16 entries; /* Number of MAC,VLAN entries in macvid_head */ +- LIST_HEAD(macvid_head, mac_vlan) macvid_head; +- struct port *port; +- int ackTimer; /* VDP ACK timer interval */ +- int ackReceived; /* VDP ACK received for this profile */ +- int keepaliveTimer; /* VDP keepalive timer interval */ +- int state; /* State of VDP state machine for profile */ +- int seqnr; /* Seqnr of ECP packet this profile was sent */ +- bool localChange; /* True when state needs change */ +- bool remoteChange; /* True when switch caused profile change */ +- bool txmit; /* Profile transmitted */ +- LIST_ENTRY(vsi_profile) profile; +-}; +- +-struct vdp_data { +- char ifname[IFNAMSIZ]; +- u8 enabletx; +- u8 vdpbit_on; /* Enable VDP Protocol */ +- struct ecp ecp; +- struct unpacked_tlv *vdp; +- int role; +- int keepaliveTimer; +- int ackTimer; +- int nroftimers; +- LIST_HEAD(profile_head, vsi_profile) profile_head; +- LIST_ENTRY(vdp_data) entry; +-}; +- +-struct vdp_user_data { +- LIST_HEAD(vdp_head, vdp_data) head; +-}; +- +-struct lldp_module *vdp_register(void); +-void vdp_unregister(struct lldp_module *); +-struct vdp_data *vdp_data(char *); +-struct packed_tlv *vdp_gettlv(struct vdp_data *, struct vsi_profile *); +-void vdp_vsi_sm_station(struct vsi_profile *); +-struct vsi_profile *vdp_add_profile(struct vdp_data *, struct vsi_profile *); +-int vdp_remove_profile(struct vsi_profile *); +-void vdp_somethingChangedLocal(struct vsi_profile *, bool); +-void vdp_update(char *, u8); +-void vdp_ifup(char *, struct lldp_agent *); +-void vdp_ifdown(char *, struct lldp_agent *); +- +-void vdp_ack_profiles(struct vdp_data *, int); +-void vdp_advance_sm(struct vdp_data *); +-int vdp_indicate(struct vdp_data *, struct unpacked_tlv *); +-int vdp_vsis_pending(struct vdp_data *); +-int vdp_vsis(char *); +-const char *vdp_response2str(int); +-void vdp_trace_profile(struct vsi_profile *); +-struct vsi_profile *vdp_alloc_profile(void); +-void vdp_delete_profile(struct vsi_profile *); +-struct vsi_profile *vdp_find_profile(struct vdp_data *, struct vsi_profile *); +- +-#define MAC_ADDR_STRLEN 18 +- +-#endif /* _LLDP_VDP_H */ +diff --git a/include/lldp_vdp22.h b/include/lldp_vdp22.h +deleted file mode 100644 +index c29b7fe..0000000 +--- a/include/lldp_vdp22.h ++++ /dev/null +@@ -1,62 +0,0 @@ +-/******************************************************************************* +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2013 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-/* +- * External interface definition for the ratified standard VDP protocol. +- */ +-#ifndef LLDP_VDP22_H +-#define LLDP_VDP22_H +- +-#include +-#include +- +-#include "lldp_mod.h" +- +-struct vsi22_profile { +- LIST_ENTRY(vsi22_profile) prof22_entry; +-}; +- +-struct vdp22 { /* Per interface VSI/VDP data */ +- char ifname[IFNAMSIZ]; /* Interface name */ +- unsigned char max_rwd; /* Max number of resource wait delay */ +- unsigned char max_rka; /* Max number of reinit keep alive */ +- unsigned char gpid; /* Supports group ids in VDP */ +- unsigned short input_len; /* Length of input data from ECP */ +- unsigned char input[ETH_DATA_LEN]; /* Input data from ECP */ +- LIST_HEAD(profile22_head, vsi22_profile) prof22_head; +- LIST_ENTRY(vdp22) entry; +-}; +- +-struct vdp22_user_data { /* Head for all VDP data */ +- LIST_HEAD(vdp22_head, vdp22) head; +-}; +- +-struct lldp_module *vdp22_register(void); +-void vdp22_unregister(struct lldp_module *); +-void vdp22_start(const char *); +-void vdp22_stop(char *); +-int vdp22_query(const char *); +- +-#endif +diff --git a/include/lldp_vdp_clif.h b/include/lldp_vdp_clif.h +deleted file mode 100644 +index ab51426..0000000 +--- a/include/lldp_vdp_clif.h ++++ /dev/null +@@ -1,32 +0,0 @@ +-/******************************************************************************* +- +- Implementation of VDP according to IEEE 802.1Qbg +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Jens Osterkamp +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-#ifndef _LLDP_VDP_CLIF_H +-#define _LLDP_VDP_CLIF_H +- +-struct lldp_module *vdp_cli_register(void); +- +-#endif +diff --git a/include/lldp_vdp_cmds.h b/include/lldp_vdp_cmds.h +deleted file mode 100644 +index ec0d575..0000000 +--- a/include/lldp_vdp_cmds.h ++++ /dev/null +@@ -1,48 +0,0 @@ +-/******************************************************************************* +- +- implementation of VDP according to IEEE 802.1Qbg +- (c) Copyright IBM Corp. 2010 +- +- Author(s): Jens Osterkamp +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-#ifndef _LLDP_VDP_CMDS_H +-#define _LLDP_VDP_CMDS_H +- +-struct arg_handlers *vdp_get_arg_handlers(); +-int vdp_clif_cmd(char *, int, char *, int); +- +-enum { +- MODE = 0, +- MGRID, +- TYPEID, +- TYPEIDVERSION, +- INSTANCEID, +- FORMAT, +-}; +- +-#define VAL_STATION "station" +-#define VAL_BRIDGE "bridge" +-#define ARG_VDP_MODE "mode" +-#define ARG_VDP_ROLE "role" +-#define VDP_PREFIX "vdp" +-#define VDP_BUF_SIZE 256 +- +-#endif +diff --git a/include/lldp_vdpnl.h b/include/lldp_vdpnl.h +deleted file mode 100644 +index d6fdca6..0000000 +--- a/include/lldp_vdpnl.h ++++ /dev/null +@@ -1,64 +0,0 @@ +-/******************************************************************************* +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2013 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-/* +- * Definition of the VSI data structure received via netlink interface +- */ +-#ifndef LLDP_VDPNL_H +-#define LLDP_VDPNL_H +- +-#include +-#include +- +-#define MAX_PAYLOAD 4096 /* Maximum Payload Size */ +- +-struct vdpnl_mac { /* MAC-VLAN pair */ +- unsigned short vlan; /* Vlan identifier */ +- unsigned char mac[ETH_ALEN]; /* Mac address */ +- unsigned char qos; /* Quality of service */ +-}; +- +-struct vdpnl_vsi { /* Data structure for VSI data via netlink */ +- char ifname[IFNAMSIZ]; /* Interface name */ +- int ifindex; /* Index number */ +- unsigned char request; /* VSI request mode */ +- unsigned short response; /* VSI response code */ +- unsigned char vsi_mgrid; +- unsigned char vsi_typeversion; +- unsigned char vsi_uuid[PORT_UUID_MAX]; +- unsigned long vsi_typeid; +- unsigned long req_seq; +- pid_t req_pid; +- int macsz; /* Entries in mac-vlan pair list */ +- struct vdpnl_mac *maclist; /* List of MAC-VLAN pairs */ +-}; +- +-int vdpnl_recv(unsigned char *, size_t); +-int vdpnl_send(struct vdpnl_vsi *); +-int vdp_request(struct vdpnl_vsi *); +-int vdp22_request(struct vdpnl_vsi *); +-int vdp_status(int, struct vdpnl_vsi *); +-int event_trigger(struct nlmsghdr *, pid_t); +-#endif +diff --git a/include/lldpad_status.h b/include/lldpad_status.h +index 163b5fb..df6e0f7 100644 +--- a/include/lldpad_status.h ++++ b/include/lldpad_status.h +@@ -44,6 +44,7 @@ typedef enum { + cmd_not_capable, + cmd_not_applicable, + cmd_no_access, ++ cmd_agent_not_supported, + } cmd_status; + + #endif /* LLDPAD_STATUS_H */ +diff --git a/include/messages.h b/include/messages.h +index 21e7f1e..d52bdac 100644 +--- a/include/messages.h ++++ b/include/messages.h +@@ -31,6 +31,7 @@ + + extern bool daemonize; + extern int loglvl; ++extern int omit_tstamp; + + void log_message(int loglvl, const char *pFormat, ...) + __attribute__((__format__(__printf__, 2, 3))); +diff --git a/include/qbg22.h b/include/qbg22.h +new file mode 100644 +index 0000000..eb3eb4d +--- /dev/null ++++ b/include/qbg22.h +@@ -0,0 +1,91 @@ ++/******************************************************************************* ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++/* ++ * Define IEEE 802.1Qbg module identification numbers and module interface ++ * structures which are exchanged between all the qbg modules. ++ * ++ * Messages are sent from: ++ * EVB --> ECP: Max number of retries (R) and retransmit timeout (RTE). ++ * ++ * EVB --> VDP: Max number of Reinit-keep-Alive (RKA) Resource wait delay (RWD) ++ * and groupid support. ++ * ++ * VDP --> ECP: VSI Information as payload ++ * ECP --> VDP: VSI Information as payload ++ * ++ * This is used in the module notify call back function. ++ */ ++ ++#ifndef LLDP_QBG22_H ++#define LLDP_QBG22_H ++ ++/* ++ * Modules Identifications ++ */ ++#define LLDP_MOD_EVB22 0x80c2 ++#define LLDP_MOD_ECP22 0x80c3 ++#define LLDP_MOD_VDP22 0x80c4 ++#define LLDP_MOD_VDP22_SUBTYPE 0 ++ ++ ++enum { /* Identify data type in union below */ ++ EVB22_TO_ECP22 = 1, /* Data from EVB to ECP */ ++ EVB22_TO_VDP22 = 2, /* Data from EVB to VDP */ ++ ECP22_TO_ULP = 3, /* Data from ECP to VDP, etc */ ++ VDP22_TO_ECP22 = 4, /* Data from VDP to ECP */ ++ /* ECP22 subtypes */ ++ ECP22_VDP = 1, /* VDP protocol */ ++ ECP22_PECSP = 2 /* Port extender control and status protocol */ ++}; ++ ++struct evb22_to_ecp22 { /* Notification from EVB to ECP */ ++ unsigned char max_retry;/* Max number of retries */ ++ unsigned char max_rte; /* Max number of acknowledgement wait */ ++}; ++ ++struct evb22_to_vdp22 { /* Notification from EVB to VDP */ ++ unsigned char max_retry;/* Max number of retries */ ++ unsigned char max_rte; /* Max number of acknowledgement wait */ ++ unsigned char max_rwd; /* Max number of resource wait delay */ ++ unsigned char max_rka; /* Max number of reinit keep alive */ ++ unsigned char gpid; /* Support group ids in VDP */ ++ unsigned char evbon; /* EVB TLV transmits enabled */ ++}; ++ ++struct ecp22_to_ulp { /* Notification from ECP to VDP, etc */ ++ unsigned short len; /* Size of bytestream */ ++ void *data; /* Pointer to data */ ++}; ++ ++struct qbg22_imm { /* Intermodule message data structure */ ++ int data_type; /* Identifies union data */ ++ union { /* Overlay possible data */ ++ struct evb22_to_ecp22 a; ++ struct evb22_to_vdp22 b; ++ struct ecp22_to_ulp c; ++ } u; ++}; ++#endif +diff --git a/include/qbg_ecp.h b/include/qbg_ecp.h +new file mode 100644 +index 0000000..a67385b +--- /dev/null ++++ b/include/qbg_ecp.h +@@ -0,0 +1,106 @@ ++/******************************************************************************* ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Jens Osterkamp ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++#ifndef QBG_ECP_H ++#define QBG_ECP_H ++ ++#include ++ ++#include "lldp_mod.h" ++#include "qbg_vdp.h" ++ ++#define ECP_SUBTYPE 0x0 ++ ++#define ECP_MAX_RETRIES 3 ++#define ECP_SEQUENCE_NR_START 0x0 ++ ++#define MSECS 1000 ++#define SECS (1000 * MSECS) ++ ++#define ECP_ACK_TIMER_DEFAULT (500 * MSECS) /* 500 ms */ ++#define ECP_LOCALCHANGE_TIMEOUT (1 * MSECS) /* 1 ms */ ++ ++#define ECP_ACK_TIMER_STOPPED (-1) ++ ++typedef enum { ++ ECP_REQUEST = 0, ++ ECP_ACK ++} ecp_mode; ++ ++struct ecp_buffer { /* ECP payload buffer */ ++ u8 frame[ETH_FRAME_LEN]; /* Payload buffer */ ++ u16 frame_len; /* # of bytes of valid data */ ++ u8 state; /* Buffer state */ ++ u8 localChange; /* Status changed */ ++ u8 rcvFrame; /* True if new frame received */ ++}; ++ ++struct ecp { ++ struct l2_packet_data *l2; ++ int sequence; ++ int retries; ++ int ackReceived; ++ int ackTimer; ++ u16 lastSequence; ++ u16 seqECPDU; ++ struct ecp_buffer rx; /* Receive buffer */ ++ struct ecp_buffer tx; /* Transmit buffer */ ++ struct agentstats stats; ++ char ifname[IFNAMSIZ]; /* Interface name */ ++}; ++ ++struct ecp_hdr { ++ u8 oui[3]; ++ u8 pad1; ++ u16 subtype; ++ u8 mode; ++ u16 seqnr; ++} __attribute__ ((__packed__)); ++ ++enum { ++ ECP_TX_INIT_TRANSMIT, ++ ECP_TX_TRANSMIT_ECPDU, ++ ECP_TX_WAIT_FOR_ACK, ++ ECP_TX_REQUEST_PDU ++}; ++ ++enum { ++ ECP_RX_IDLE, ++ ECP_RX_INIT_RECEIVE, ++ ECP_RX_RECEIVE_WAIT, ++ ECP_RX_RECEIVE_ECPDU, ++ ECP_RX_SEND_ACK, ++ ECP_RX_RESEND_ACK, ++}; ++ ++struct vdp_data; ++ ++void ecp_somethingChangedLocal(struct vdp_data *, bool); ++void ecp_rx_send_ack_frame(struct vdp_data *); ++ ++int ecp_init(char *); ++int ecp_deinit(char *); ++#endif /* _ECP_H */ +diff --git a/include/qbg_ecp22.h b/include/qbg_ecp22.h +new file mode 100644 +index 0000000..567f6df +--- /dev/null ++++ b/include/qbg_ecp22.h +@@ -0,0 +1,172 @@ ++/******************************************************************************* ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++#ifndef QBG_ECP22_H ++#define QBG_ECP22_H ++ ++#include ++ ++#include "lldp_mod.h" ++#include "qbg22.h" ++ ++enum { /* ECP Receive states */ ++ ECP22_RX_BEGIN, ++ ECP22_RX_WAIT, ++ ECP22_RX_WAIT2, ++ ECP22_RX_FIRST, ++ ECP22_RX_REC_ECPDU, ++ ECP22_RX_NEW_ECPDU, ++ ECP22_RX_SEND_ACK ++}; ++enum { /* ECP Transmit states */ ++ ECP22_TX_BEGIN, ++ ECP22_TX_INIT, ++ ECP22_TX_TXMIT_ECPDU, ++ ECP22_TX_WAIT_FORREQ, ++ ECP22_TX_WAIT_ONDATA, ++ ECP22_TX_ERROR ++}; ++ ++enum { ++ ECP22_REQUEST = 0, ++ ECP22_ACK ++} ecp22_mode; ++ ++struct ecp22_hdr { /* ECP22 header */ ++ u16 ver_op_sub; /* ECP22 version, operation, subtype */ ++ u16 seqno; /* ECP22 sequence number */ ++} __attribute__ ((__packed__)); ++ ++/* ++ * Define maximum ECP protocol payload length. Leave room for END TLV. ++ */ ++#define ECP22_MAXPAYLOAD_LEN (ETH_DATA_LEN - sizeof(struct ecp22_hdr) - 2) ++ ++struct ecp22_buffer { /* ECP payload buffer */ ++ unsigned char frame[ETH_FRAME_LEN]; /* Payload buffer */ ++ unsigned short frame_len; /* # of bytes of valid data */ ++ unsigned char state; /* Buffer state machine */ ++ unsigned char ecpdu_received; /* True when packet received */ ++ unsigned char ack_received; /* True when packet acknowledged */ ++ unsigned char retries; /* # of retries */ ++ unsigned short last_seqno; /* Seqno last acknowledged packet */ ++ unsigned short seqno; /* Seqno this packet */ ++ unsigned long errors; /* # of transmit errors */ ++}; ++ ++struct ecp22_payload_node { /* ECP Payload node */ ++ struct packed_tlv *ptlv; /* Pointer to packed TLV to send */ ++ unsigned short subtype; /* ECP subtype*/ ++ unsigned char mac[ETH_ALEN]; /* Destination MAC address */ ++ LIST_ENTRY(ecp22_payload_node) node; ++}; ++ ++/* ++ * ECP22 payload data ++ */ ++typedef LIST_HEAD(ecp22_list, ecp22_payload_node) ecp22_list; ++ ++struct ecp22_usedlist { /* List of valid ecp_payload_nodes */ ++ ecp22_list head; /* ECP payload data free list */ ++ struct ecp22_payload_node *last; /* Ptr to last entry in list */ ++}; ++ ++struct ecp22_freelist { /* List of free ecp_payload_nodes */ ++ ecp22_list head; /* ECP payload data free list */ ++ u16 freecnt; /* # of nodes on freelist */ ++}; ++ ++enum { ++ ecp22_maxpayload = 64 ++}; ++ ++struct ecp22 { /* ECP protocol data per interface */ ++ struct l2_packet_data *l2; ++ char ifname[IFNAMSIZ]; /* Interface name */ ++ LIST_ENTRY(ecp22) node; /* Successor */ ++ struct ecp22_buffer rx; /* Receive buffer */ ++ struct ecp22_buffer tx; /* Transmit buffer */ ++ struct agentstats stats; ++ struct ecp22_usedlist inuse; /* List of payload data */ ++ struct ecp22_freelist isfree; /* List of free payload nodes */ ++ unsigned char max_retries; /* Max # of retries (via EVB) */ ++ unsigned char max_rte; /* Wait time for ack (via EVB) */ ++}; ++ ++struct ecp22_user_data { /* ECP module data per interface */ ++ LIST_HEAD(ecp_head, ecp22) head; ++}; ++ ++/* ++ * Function prototypes ++ */ ++struct lldp_module *ecp22_register(void); ++void ecp22_unregister(struct lldp_module *); ++void ecp22_stop(char *); ++void ecp22_start(char *); ++ ++/* ++ * Functions to set and read ecp header operations field. ++ */ ++static inline void ecp22_hdr_set_op(struct ecp22_hdr *p, unsigned int op) ++{ ++ p->ver_op_sub &= 0xf3ff; ++ p->ver_op_sub |= (op & 0x3) << 10; ++} ++ ++static inline unsigned int ecp22_hdr_read_op(struct ecp22_hdr *p) ++{ ++ return (p->ver_op_sub >> 10) & 3; ++} ++ ++/* ++ * Functions to set and read ecp header subtype field. ++ */ ++static inline void ecp22_hdr_set_subtype(struct ecp22_hdr *p, unsigned int sub) ++{ ++ p->ver_op_sub &= 0xfc00; ++ p->ver_op_sub |= sub & 0x3ff; ++} ++ ++static inline unsigned int ecp22_hdr_read_subtype(struct ecp22_hdr *p) ++{ ++ return p->ver_op_sub & 0x3ff; ++} ++ ++/* ++ * Functions to set and read ecp header version field. ++ */ ++static inline void ecp22_hdr_set_version(struct ecp22_hdr *p, unsigned int ver) ++{ ++ p->ver_op_sub &= 0xfff; ++ p->ver_op_sub |= (ver & 0xf) << 12; ++} ++ ++static inline unsigned int ecp22_hdr_read_version(struct ecp22_hdr *p) ++{ ++ return (p->ver_op_sub >> 12) & 0xf; ++} ++ ++#endif +diff --git a/include/qbg_utils.h b/include/qbg_utils.h +new file mode 100644 +index 0000000..6033556 +--- /dev/null ++++ b/include/qbg_utils.h +@@ -0,0 +1,45 @@ ++/******************************************************************************* ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2010, 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++/* ++ * Header file for small utility functions called throught qbg modules. ++ */ ++ ++#ifndef QBG_UTILS_H ++#define QBG_UTILS_H ++ ++void hexdump_frame(const char *, char *, const unsigned char *, size_t); ++int modules_notify(int, int, char *, void *); ++ ++/* ++ * Required buffer space to display a VSI ID (as UUID or other formats). ++ * VDP_UUID_STRLEN = strlen("fa9b7fff-b0a0-4893-abcd-beef4ff18f8f") ++ * or strlen("fa9b:7fff:b0a0:4893:abcd:beef:4ff1:8f8f") ++ */ ++#define VDP_UUID_STRLEN 40 ++ ++/* Convert VSI IDs to strings */ ++int vdp_uuid2str(const unsigned char *, char *, size_t); ++#endif +diff --git a/include/qbg_vdp.h b/include/qbg_vdp.h +new file mode 100644 +index 0000000..e7de693 +--- /dev/null ++++ b/include/qbg_vdp.h +@@ -0,0 +1,170 @@ ++/******************************************************************************* ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Jens Osterkamp ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++#ifndef QBG_VDP_H ++#define QBG_VDP_H ++ ++#include "lldp_mod.h" ++#include "qbg_ecp.h" ++ ++#define LLDP_MOD_VDP (OUI_IEEE_8021Qbg + 1) ++ ++#define VDP_MODE_PREASSOCIATE 0x0 ++#define VDP_MODE_PREASSOCIATE_WITH_RR 0x1 ++#define VDP_MODE_ASSOCIATE 0x2 ++#define VDP_MODE_DEASSOCIATE 0x3 ++ ++#define VDP_RESPONSE_SUCCESS 0x0 ++#define VDP_RESPONSE_INVALID_FORMAT 0x1 ++#define VDP_RESPONSE_INSUFF_RESOURCES 0x2 ++#define VDP_RESPONSE_UNUSED_VTID 0x3 ++#define VDP_RESPONSE_VTID_VIOLATION 0x4 ++#define VDP_RESPONSE_VTID_VER_VIOLATION 0x5 ++#define VDP_RESPONSE_OUT_OF_SYNC 0x6 ++#define VDP_RESPONSE_UNKNOWN 0xfe ++#define VDP_RESPONSE_NO_RESPONSE 0xff ++ ++extern const char * const vsi_states[]; ++ ++#define VDP_FILTER_INFO_FORMAT_VID 0x1 ++#define VDP_FILTER_INFO_FORMAT_MACVID 0x2 ++#define VDP_FILTER_INFO_FORMAT_GROUPVID 0x3 ++#define VDP_FILTER_INFO_FORMAT_GROUPMACVID 0x4 ++ ++#define VDP_TIMER_GRANULARITY (100 * MSECS) /* 100 ms */ ++#define VDP_KEEPALIVE_TIMER_DEFAULT (10 * SECS) /* 10s */ ++#define VDP_ACK_TIMER_DEFAULT (2 * ECP_ACK_TIMER_DEFAULT * ECP_MAX_RETRIES) ++#define VDP_KEEPALIVE_TIMER_STOPPED (-1) ++#define VDP_ACK_TIMER_STOPPED (-1) ++#define VDP_LOCALCHANGE_TIMEOUT (1 * MSECS) /* 1 ms */ ++ ++#define VDP_ROLE_STATION 0 ++#define VDP_ROLE_BRIDGE 1 ++ ++enum { ++ VSI_UNASSOCIATED = 0, ++ VSI_ASSOC_PROCESSING, ++ VSI_ASSOCIATED, ++ VSI_PREASSOC_PROCESSING, ++ VSI_PREASSOCIATED, ++ VSI_DEASSOC_PROCESSING, ++ VSI_EXIT, ++}; ++ ++struct mac_vlan_p { ++ u8 mac[6]; ++ u16 vlan; ++} __attribute__ ((__packed__)); ++ ++struct mac_vlan { /* MAC,VLAN entry anchored by profiles */ ++ u8 mac[6]; ++ u16 vlan; ++ u8 qos; /* QOS field */ ++ pid_t req_pid; /* PID of requester for this profile */ ++ u32 req_seq; /* Seq # of requester for this profile */ ++ LIST_ENTRY(mac_vlan) entry; ++}; ++ ++struct tlv_info_vdp { /* VSI information in packet format */ ++ u8 oui[3]; ++ u8 sub; ++ u8 mode; ++ u8 response; ++ u8 mgrid; ++ u8 id[3]; ++ u8 version; ++ u8 instance[16]; ++ u8 format; ++ u16 entries; ++} __attribute__ ((__packed__)); ++ ++struct vsi_profile { ++ int mode; /* VSI profile association command */ ++ int response; /* Response from switch */ ++ u8 no_nlmsg; /* Don't send netlink msg on VSI_EXIT */ ++ u8 mgrid; /* Profile mgr id */ ++ int id; /* Profile id */ ++ u8 version; /* Profile id version number */ ++ u8 instance[16]; /* Profile UUID */ ++ u8 format; /* Format of MAC,VLAN list */ ++ u16 entries; /* Number of MAC,VLAN entries in macvid_head */ ++ LIST_HEAD(macvid_head, mac_vlan) macvid_head; ++ struct port *port; ++ int ackTimer; /* VDP ACK timer interval */ ++ int ackReceived; /* VDP ACK received for this profile */ ++ int keepaliveTimer; /* VDP keepalive timer interval */ ++ int state; /* State of VDP state machine for profile */ ++ int seqnr; /* Seqnr of ECP packet this profile was sent */ ++ bool localChange; /* True when state needs change */ ++ bool remoteChange; /* True when switch caused profile change */ ++ bool txmit; /* Profile transmitted */ ++ LIST_ENTRY(vsi_profile) profile; ++}; ++ ++struct vdp_data { ++ char ifname[IFNAMSIZ]; ++ u8 enabletx; ++ u8 vdpbit_on; /* Enable VDP Protocol */ ++ struct ecp ecp; ++ struct unpacked_tlv *vdp; ++ int role; ++ int keepaliveTimer; ++ int ackTimer; ++ int nroftimers; ++ LIST_HEAD(profile_head, vsi_profile) profile_head; ++ LIST_ENTRY(vdp_data) entry; ++}; ++ ++struct vdp_user_data { ++ LIST_HEAD(vdp_head, vdp_data) head; ++}; ++ ++struct lldp_module *vdp_register(void); ++void vdp_unregister(struct lldp_module *); ++struct vdp_data *vdp_data(char *); ++struct packed_tlv *vdp_gettlv(struct vdp_data *, struct vsi_profile *); ++void vdp_vsi_sm_station(struct vsi_profile *); ++struct vsi_profile *vdp_add_profile(struct vdp_data *, struct vsi_profile *); ++int vdp_remove_profile(struct vsi_profile *); ++void vdp_somethingChangedLocal(struct vsi_profile *, bool); ++void vdp_update(char *, u8); ++void vdp_ifup(char *, struct lldp_agent *); ++void vdp_ifdown(char *, struct lldp_agent *); ++ ++void vdp_ack_profiles(struct vdp_data *, int); ++void vdp_advance_sm(struct vdp_data *); ++int vdp_indicate(struct vdp_data *, struct unpacked_tlv *); ++int vdp_vsis_pending(struct vdp_data *); ++int vdp_vsis(char *); ++const char *vdp_response2str(int); ++void vdp_trace_profile(struct vsi_profile *); ++struct vsi_profile *vdp_alloc_profile(void); ++void vdp_delete_profile(struct vsi_profile *); ++struct vsi_profile *vdp_find_profile(struct vdp_data *, struct vsi_profile *); ++ ++#define MAC_ADDR_STRLEN 18 ++ ++#endif /* _LLDP_VDP_H */ +diff --git a/include/qbg_vdp22.h b/include/qbg_vdp22.h +new file mode 100644 +index 0000000..b345602 +--- /dev/null ++++ b/include/qbg_vdp22.h +@@ -0,0 +1,210 @@ ++/******************************************************************************* ++ ++ Implementation of VDP protocol for IEEE 802.1 Qbg Ratified Standard ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++#ifndef QBG_VDP22_H ++#define QBG_VDP22_H ++ ++/* ++ * Defintion of VDP22 data structures: ++ * For IEEE 802.1Qbg ratified standard the Virtual Station Information (VSI) ++ * in the VDP22 protocol is maintained as a queue with one entry per interface ++ * supporting VDP22. ++ * Each interface is the anchor for a list of active VSI manager identifiers. ++ * All VSIs with the same ++ * - manager-id ++ * - type-id and type version ++ * - VSI format type and VSI id ++ * - filter info format ++ * are grouped into one entry. This means if two VSIs differ only in the ++ * filter info format (for example), two seperate VSI list elements will be ++ * allocated and queued in the VSI queue of that interface name. ++ * ++ * Each VSI node maintains the VDP22 state machine for that association. ++ * ++ * Supported operations: ++ * - Find a VSI entry given the search criterias: ++ * manager-id, type-id, type-version, VSI-format, VSI-ID and filter-info ++ * (data and format). ++ * - Add new filter data to a matching VSI entry (and filter not already ++ * active). ++ * - Remove filter data from a matching VSI entry. ++ * - Add a new VSI node when no VSI match is found. ++ * - Remove a VSI node when no filter entry is active anymore. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++enum vdp22_role { /* State for VDP22 bridge processing */ ++ VDP22_BRIDGE = 1, /* Bridge role */ ++ VDP22_STATION /* State role */ ++}; ++ ++enum vdp22_cmdresp { /* VDP22 Protocol command responses */ ++ VDP22_RESP_SUCCESS = 0, /* Success */ ++ VDP22_RESP_INVALID_FORMAT = 1, ++ VDP22_RESP_NO_RESOURCES = 2, ++ VDP22_RESP_NO_VSIMGR = 3, /* No contact to VSI manager */ ++ VDP22_RESP_OTHER = 4, /* Other reasons */ ++ VDP22_RESP_NOADDR = 5, /* Invalid VID, MAC, GROUP etc */ ++ VDP22_RESP_DEASSOC = 252, /* Deassoc response */ ++ VDP22_RESP_TIMEOUT = 253, /* Timeout response */ ++ VDP22_RESP_KEEP = 254, /* Keep response */ ++ VDP22_RESP_NONE = 255 /* No response returned so far */ ++}; ++ ++enum { ++ VDP22_MGRIDSZ = 16, /* Size of manager identifier */ ++ VDP22_IDSZ = 16 /* Size of vsi identifier */ ++}; ++ ++struct vsi_origin { /* Originator of VSI request */ ++ pid_t req_pid; /* PID of requester for VSI */ ++ unsigned long req_seq; /* Seq # of requester for VSI */ ++}; ++ ++/* ++ * Generic filter data. Some field are unused, this depends ++ * on the filter info format value (see enum above). ++ */ ++struct fid22 { /* Filter data: GROUP,MAC,VLAN entry */ ++ unsigned long grpid; /* Group identifier */ ++ unsigned char mac[ETH_ALEN]; /* MAC address */ ++ unsigned short vlan; /* VLAN idenfier */ ++ struct vsi_origin requestor; ++}; ++ ++/* ++ * VSI information. One node per matching entry (same mgrid, type_id, type_ver, ++ * id_fmt, id and fif). Filter data can be added and removed. ++ */ ++enum vsi22_flags { /* Flags (or'ed in) */ ++ VDP22_BUSY = 1, /* This node is under work */ ++ VDP22_DELETE_ME = 2, /* Deallocate this node */ ++ VDP22_RETURN_VID = 4, /* Return wildcard vlan id */ ++ VDP22_NOTIFY = 8, /* Send netlink message to requestor */ ++ VDP22_NLCMD = 16 /* Netlink command pending */ ++}; ++ ++struct vdp22smi { /* Data structure for VDP22 state machine */ ++ int state; /* State of VDP state machine for VSI */ ++ bool kato; /* VSI KA ACK timeout hit for this VSI */ ++ bool ackreceived; /* VSI ACK received for this VSI */ ++ bool acktimeout; /* VSI ACK timeout hit for this VSI */ ++ bool localchg; /* True when state needs change */ ++ bool deassoc; /* True when deassoc received from switch */ ++ bool txmit; /* True when packed TLV transmitted */ ++ bool resp_ok; /* True when acked TLV received and match ok */ ++ int txmit_error; /* != 0 error code from transmit via ECP */ ++}; ++ ++struct vsi22 { ++ LIST_ENTRY(vsi22) node; /* Node element */ ++ unsigned char mgrid[VDP22_MGRIDSZ]; /* Manager identifier */ ++ unsigned char cc_vsi_mode; /* currently confirmed VSI mode */ ++ unsigned char vsi_mode; /* VSI mode: ASSOC, PREASSOC, etc */ ++ unsigned char resp_vsi_mode; /* Responsed VSI mode: ASSOC, etc */ ++ unsigned char status; /* Status, Request/Response */ ++ unsigned char hints; /* Indicate migration/suspend */ ++ unsigned long type_id; /* Type identifier */ ++ unsigned char type_ver; /* Type version */ ++ unsigned char vsi_fmt; /* Format of VSI identifier */ ++ unsigned char vsi[VDP22_IDSZ]; /* VSI identifier */ ++ unsigned char fif; /* Filter info format */ ++ unsigned short no_fdata; /* Entries in filter data */ ++ struct fid22 *fdata; /* Filter data variable length */ ++ struct vdp22 *vdp; /* Back pointer to VDP head */ ++ unsigned long flags; /* Flags, see above */ ++ struct vdp22smi smi; /* State machine information */ ++}; ++ ++struct vdp22 { /* Per interface VSI/VDP data */ ++ LIST_ENTRY(vdp22) node; /* Node element */ ++ char ifname[IFNAMSIZ + 1]; /* Interface name */ ++ unsigned char ecp_retries; /* # of ECP module retries */ ++ unsigned char ecp_rte; /* ECP module retry timeout exponent */ ++ unsigned char vdp_rwd; /* Resource wait delay exponent */ ++ unsigned char vdp_rka; /* Reinit keep alive exponent */ ++ unsigned char gpid; /* Supports group ids in VDP */ ++ unsigned char myrole; /* Station or bridge role */ ++ unsigned char evbon; /* True on EVB22 txmit enabled */ ++ unsigned char br_down; /* True when bridge down */ ++ unsigned short input_len; /* Length of input data from ECP */ ++ unsigned char input[ETH_DATA_LEN]; /* Input data from ECP */ ++ LIST_HEAD(vsi22_head, vsi22) vsi22_que; /* Active VSIs */ ++}; ++ ++struct vdp22_user_data { /* Head for all VDP data */ ++ LIST_HEAD(vdp22_head, vdp22) head; ++}; ++ ++struct lldp_module *vdp22_register(void); ++void vdp22_unregister(struct lldp_module *); ++void vdp22_start(const char *, int); ++void vdp22_showvsi(struct vsi22 *p); ++void vdp22_stop(char *); ++int vdp22_from_ecp22(struct vdp22 *); ++int vdp22_query(const char *); ++int vdp22_addreq(struct vsi22 *, struct vdp22 *); ++int vdp22_nlback(struct vsi22 *); ++int vdp22_clntback(struct vsi22 *); ++struct vsi22 *vdp22_copy_vsi(struct vsi22 *); ++void vdp22_listdel_vsi(struct vsi22 *); ++int vdp22br_resources(struct vsi22 *, int *); ++int vdp22_info(const char *); ++void vdp22_stop_timers(struct vsi22 *); ++int vdp22_start_localchange_timer(struct vsi22 *); ++ ++/* ++ * Functions to get and set vlan identifier and qos. ++ */ ++static inline unsigned short vdp22_get_ps(unsigned short x) ++{ ++ return (x >> 15) & 0x1; ++} ++ ++static inline unsigned short vdp22_get_qos(unsigned short x) ++{ ++ return (x >> 12) & 0xf; ++} ++ ++static inline unsigned short vdp22_set_qos(unsigned short x) ++{ ++ return (x & 0xf) << 12; ++} ++ ++static inline unsigned short vdp22_get_vlanid(unsigned short x) ++{ ++ return x & 0xfff; ++} ++ ++static inline unsigned short vdp22_set_vlanid(unsigned short x) ++{ ++ return (x & 0xfff); ++} ++#endif +diff --git a/include/qbg_vdp22_clif.h b/include/qbg_vdp22_clif.h +new file mode 100644 +index 0000000..20330b8 +--- /dev/null ++++ b/include/qbg_vdp22_clif.h +@@ -0,0 +1,55 @@ ++/******************************************************************************* ++ ++ Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2014 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++/* ++ * Client command interface for vdp22 module. ++ */ ++ ++#ifndef QBG_VDP22_CLIF_H ++#define QBG_VDP22_CLIF_H ++typedef enum { ++ cmd_getstats, ++ cmd_gettlv, ++ cmd_settlv, ++ cmd_get_lldp, ++ cmd_set_lldp, ++ cmd_quit, ++ cmd_license, ++ cmd_version, ++ cmd_help, ++ cmd_ping, ++ cmd_nop ++} vdp22_cmd; ++ ++typedef enum { ++ op_local = 0x1, ++ op_neighbor = 0x2, ++ op_arg = 0x4, ++ op_argval = 0x8, ++ op_config = 0x10, ++ op_delete = 0x20, ++ op_key = 0x40 ++} vdp22_op; ++#endif +diff --git a/include/qbg_vdp22_cmds.h b/include/qbg_vdp22_cmds.h +new file mode 100644 +index 0000000..8cfd32a +--- /dev/null ++++ b/include/qbg_vdp22_cmds.h +@@ -0,0 +1,40 @@ ++/******************************************************************************* ++ ++ Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2014 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++/* ++ * Command interface for vdp22 module. ++ */ ++ ++#ifndef QBG_VDP22_CMDS_H ++#define QBG_VDP22_CMDS_H ++ ++struct arg_handlers *vdp22_arg_handlers(); ++int vdp22_clif_cmd(void *, struct sockaddr_un *, socklen_t, char *, int, char *, ++ int); ++#define VAL_STATION "station" ++#define VAL_BRIDGE "bridge" ++#define ARG_VDP22_VSI "vsi" ++ ++#endif +diff --git a/include/qbg_vdp22def.h b/include/qbg_vdp22def.h +new file mode 100644 +index 0000000..52f4502 +--- /dev/null ++++ b/include/qbg_vdp22def.h +@@ -0,0 +1,75 @@ ++/******************************************************************************* ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++/* ++ * External interface definition for the ratified standard VDP protocol. ++ */ ++#ifndef QBG_VDP22DEF_H ++#define QBG_VDP22DEF_H ++ ++/* ++ * Define VDP22 filter formats. ++ */ ++enum vdp22_ffmt { /* Format of filter information */ ++ VDP22_FFMT_VID = 1, /* Vlan Identifier */ ++ VDP22_FFMT_MACVID, /* MAC address and Vlan Identifier */ ++ VDP22_FFMT_GROUPVID, /* Group and Vlan Identifier */ ++ VDP22_FFMT_GROUPMACVID /* Group, MAC and Vlan Identifier */ ++}; ++ ++/* ++ * Define VDP22 VSI Profile modes. ++ */ ++enum vdp22_modes { ++ VDP22_ENDTLV = 0, ++ VDP22_PREASSOC = 1, ++ VDP22_PREASSOC_WITH_RR, ++ VDP22_ASSOC, ++ VDP22_DEASSOC, ++ VDP22_MGRID, ++ VDP22_OUI = 0x7f ++}; ++ ++/* ++ * Define VDP22 VSI identifier format ++ */ ++enum vdp22_vsiid_fmt { ++ VDP22_ID_IP4 = 1, /* VSI ID is IPv4 address */ ++ VDP22_ID_IP6, /* VSI ID is IPv6 address */ ++ VDP22_ID_MAC, /* VSI ID is IEEE 802 MAC address */ ++ VDP22_ID_LOCAL, /* VSI ID is locally defined */ ++ VDP22_ID_UUID /* VSI ID is RFC4122 UUID */ ++}; ++ ++ ++/* ++ * Define VDP22 Migiration hints ++ */ ++enum vdp22_migration_hints { ++ VDP22_MIGTO = 16, /* M-bit migrate to hint */ ++ VDP22_MIGFROM = 32 /* S-bit migrate from hint */ ++}; ++ ++#endif +diff --git a/include/qbg_vdp_clif.h b/include/qbg_vdp_clif.h +new file mode 100644 +index 0000000..e4f9f78 +--- /dev/null ++++ b/include/qbg_vdp_clif.h +@@ -0,0 +1,32 @@ ++/******************************************************************************* ++ ++ Implementation of VDP according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Jens Osterkamp ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++#ifndef QBG_VDP_CLIF_H ++#define QBG_VDP_CLIF_H ++ ++struct lldp_module *vdp_cli_register(void); ++ ++#endif +diff --git a/include/qbg_vdp_cmds.h b/include/qbg_vdp_cmds.h +new file mode 100644 +index 0000000..2bbcb1c +--- /dev/null ++++ b/include/qbg_vdp_cmds.h +@@ -0,0 +1,48 @@ ++/******************************************************************************* ++ ++ implementation of VDP according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2010 ++ ++ Author(s): Jens Osterkamp ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++#ifndef QBG_VDP_CMDS_H ++#define QBG_VDP_CMDS_H ++ ++struct arg_handlers *vdp_get_arg_handlers(); ++int vdp_clif_cmd(char *, int, char *, int); ++ ++enum { ++ MODE = 0, ++ MGRID, ++ TYPEID, ++ TYPEIDVERSION, ++ INSTANCEID, ++ FORMAT, ++}; ++ ++#define VAL_STATION "station" ++#define VAL_BRIDGE "bridge" ++#define ARG_VDP_MODE "mode" ++#define ARG_VDP_ROLE "role" ++#define VDP_PREFIX "vdp" ++#define VDP_BUF_SIZE 256 ++ ++#endif +diff --git a/include/qbg_vdpnl.h b/include/qbg_vdpnl.h +new file mode 100644 +index 0000000..7b26bc7 +--- /dev/null ++++ b/include/qbg_vdpnl.h +@@ -0,0 +1,81 @@ ++/******************************************************************************* ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++/* ++ * Definition of the VSI data structure received via netlink interface ++ */ ++#ifndef QBG_VDPNL_H ++#define QBG_VDPNL_H ++ ++#include ++#include ++ ++#define MAX_PAYLOAD 4096 /* Maximum Payload Size */ ++ ++enum { ++ vdpnl_nlf1 = 1, /* Netlink message format 1 (draft 0.2) */ ++ vdpnl_nlf2 /* Netlink message format 2 (ratified) */ ++}; ++ ++struct vdpnl_mac { /* MAC-VLAN pair */ ++ unsigned short vlan; /* Vlan identifier */ ++ unsigned char mac[ETH_ALEN]; /* Mac address */ ++ unsigned char qos; /* Quality of service */ ++ unsigned char changed; /* Vlan changed by switch */ ++ unsigned long gpid; /* Group identifer */ ++}; ++ ++struct vdpnl_vsi { /* Data structure for VSI data via netlink */ ++ char ifname[IFNAMSIZ + 1]; /* Interface name */ ++ int ifindex; /* Index number */ ++ int vf; /* Virtual function number */ ++ unsigned char hints; /* VSI request mode migrition hints */ ++ unsigned char request; /* VSI request mode */ ++ unsigned short response; /* VSI response code */ ++ unsigned char vsi_mgrid; ++ unsigned char vsi_typeversion; ++ unsigned char vsi_idfmt; ++ unsigned char vsi_uuid[PORT_UUID_MAX]; ++ unsigned char vsi_mgrid2[PORT_UUID_MAX]; ++ unsigned char nl_version; /* Netlink message format version */ ++ unsigned long vsi_typeid; ++ unsigned long req_seq; ++ pid_t req_pid; ++ unsigned char filter_fmt; /* Filter format type */ ++ int macsz; /* Entries in mac-vlan pair list */ ++ struct vdpnl_mac *maclist; /* List of MAC-VLAN pairs */ ++}; ++ ++int vdpnl_recv(unsigned char *, size_t); ++int vdpnl_send(struct vdpnl_vsi *); ++int vdp_request(struct vdpnl_vsi *); ++int vdp22_request(struct vdpnl_vsi *, int); ++int vdp_status(int, struct vdpnl_vsi *); ++int vdp22_status(int, struct vdpnl_vsi *, int); ++int event_trigger(struct nlmsghdr *, pid_t); ++int vdp_str2vdpnl(char *, struct vdpnl_vsi *, char *); ++int vdp_vdpnl2str(struct vdpnl_vsi *, char *, size_t); ++int vdp22_sendevent(struct vdpnl_vsi *); ++#endif +diff --git a/lldp/agent.c b/lldp/agent.c +index 2e85aa5..4bc5394 100644 +--- a/lldp/agent.c ++++ b/lldp/agent.c +@@ -51,12 +51,10 @@ static const char *agent_sections[AGENT_MAX] = { + struct lldp_agent * + lldp_agent_find_by_type(const char *ifname, enum agent_type type) + { +- struct port *port; ++ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); + struct lldp_agent *agent; + +- port = port_find_by_name(ifname); +- +- if (port == NULL) ++ if (!port) + return NULL; + + LIST_FOREACH(agent, &port->agent_head, entry) { +@@ -109,12 +107,10 @@ void lldp_init_agent(struct port *port, struct lldp_agent *agent, int type) + int lldp_add_agent(const char *ifname, enum agent_type type) + { + int count; +- struct port *port; ++ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); + struct lldp_agent *agent, *newagent; + +- port = port_find_by_name(ifname); +- +- if (port == NULL) ++ if (!port) + return -1; + + /* check if lldp_agents for this if already exist */ +@@ -123,17 +119,15 @@ int lldp_add_agent(const char *ifname, enum agent_type type) + count++; + if (agent->type != type) + continue; +- else +- return -1; ++ return -1; + } + + /* if not, create one and initialize it */ +- LLDPAD_DBG("%s(%i): creating new agent for port %s.\n", __func__, +- __LINE__, ifname); +- newagent = (struct lldp_agent *)malloc(sizeof(struct lldp_agent)); +- if (newagent == NULL) { +- LLDPAD_DBG("%s(%i): creation of new agent failed !.\n", +- __func__, __LINE__); ++ LLDPAD_DBG("%s: creating new agent for port %s.\n", __func__, ++ ifname); ++ newagent = malloc(sizeof(*newagent)); ++ if (!newagent) { ++ LLDPAD_DBG("%s: creation of new agent failed !.\n", __func__); + return -1; + } + +diff --git a/lldp/l2_packet.h b/lldp/l2_packet.h +index 737ae54..b82b894 100644 +--- a/lldp/l2_packet.h ++++ b/lldp/l2_packet.h +@@ -40,7 +40,7 @@ + #define ETH_P_LLDP 0x88cc + + #define ETH_P_ECP 0x88b7 /* Draft 0.2 */ +-#define ETH_P_ECP22 0x8890 /* Ratified standard */ ++#define ETH_P_ECP22 0x8940 /* Ratified standard */ + + #ifndef ETH_MIN_DATA_LEN + #define ETH_MIN_DATA_LEN (ETH_ZLEN - ETH_HLEN) +diff --git a/lldp/l2_packet_linux.c b/lldp/l2_packet_linux.c +index a5fe8bf..08f1e55 100644 +--- a/lldp/l2_packet_linux.c ++++ b/lldp/l2_packet_linux.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include "eloop.h" + #include "ports.h" + #include "messages.h" +@@ -144,8 +145,9 @@ static void l2_packet_receive(int sock, void *eloop_ctx, UNUSED void *sock_ctx) + &fromlen); + + if (res < 0) { +- LLDPAD_INFO("receive ERROR = %d\n", res); +- perror("l2_packet_receive - recvfrom"); ++ LLDPAD_INFO("receive if %s ERROR = %d\n", l2->ifname, errno); ++ if (errno != ENETDOWN) ++ perror("l2_packet_receive - recvfrom"); + return; + } + +diff --git a/lldp/ports.c b/lldp/ports.c +index 0652ce8..3bd6a2a 100644 +--- a/lldp/ports.c ++++ b/lldp/ports.c +@@ -124,56 +124,43 @@ int get_lldp_agent_admin(const char *ifname, int type) + + void set_lldp_agent_admin(const char *ifname, int type, int admin) + { +- struct port *port = NULL; ++ struct port *port; + struct lldp_agent *agent; +- int all = 0; +- int tmp; ++ int ifindex = get_ifidx(ifname); + +- all = !strlen(ifname); ++ if (!ifindex) ++ return; + +- port = porthead; +- while (port != NULL) { +- if (all || !strncmp(ifname, port->ifname, IFNAMSIZ)) { +- /* don't change a port which has an explicit setting +- * on a global setting change +- */ +- if (all && (!get_config_setting(port->ifname, +- type, +- ARG_ADMINSTATUS, +- (void *)&tmp, +- CONFIG_TYPE_INT))) { +- port = port->next; +- continue; +- } ++ for (port = porthead; port; port = port->next) { ++ if (ifindex == port->ifindex) ++ break; ++ } + +- agent = lldp_agent_find_by_type(port->ifname, type); +- if (!agent) { +- port = port->next; +- continue; +- } ++ if (!port) ++ return; + +- if (agent->adminStatus != admin) { +- agent->adminStatus = admin; +- somethingChangedLocal(ifname, type); +- run_tx_sm(port, agent); +- run_rx_sm(port, agent); +- } ++ agent = lldp_agent_find_by_type(port->ifname, type); ++ if (!agent) ++ return; + +- if (!all) +- break; +- } +- port = port->next; ++ /* Set ifname with ifindex reported ifname */ ++ if (strncmp(port->ifname, ifname, IFNAMSIZ) != 0) ++ memcpy(port->ifname, ifname, IFNAMSIZ); ++ ++ if (agent->adminStatus != admin) { ++ agent->adminStatus = admin; ++ somethingChangedLocal(port->ifname, type); ++ run_tx_sm(port, agent); ++ run_rx_sm(port, agent); + } + } + + void set_lldp_port_enable(const char *ifname, int enable) + { +- struct port *port = NULL; ++ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); + struct lldp_agent *agent = NULL; + +- port = port_find_by_name(ifname); +- +- if (port == NULL) ++ if (!port) + return; + + port->portEnabled = (u8)enable; +@@ -192,9 +179,9 @@ void set_lldp_port_enable(const char *ifname, int enable) + + void set_port_oper_delay(const char *ifname) + { +- struct port *port = port_find_by_name(ifname); ++ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); + +- if (port == NULL) ++ if (!port) + return; + + port->dormantDelay = DORMANT_DELAY; +@@ -204,11 +191,9 @@ void set_port_oper_delay(const char *ifname) + + int set_port_hw_resetting(const char *ifname, int resetting) + { +- struct port *port = NULL; ++ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); + +- port = port_find_by_name(ifname); +- +- if (port == NULL) ++ if (!port) + return -1; + + port->hw_resetting = (u8)resetting; +@@ -218,22 +203,18 @@ int set_port_hw_resetting(const char *ifname, int resetting) + + int get_port_hw_resetting(const char *ifname) + { +- struct port *port = NULL; +- +- port = port_find_by_name(ifname); ++ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); + + if (port) + return port->hw_resetting; +- else +- return 0; ++ ++ return 0; + } + + int reinit_port(const char *ifname) + { ++ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); + struct lldp_agent *agent; +- struct port *port; +- +- port = port_find_by_name(ifname); + + if (!port) + return -1; +@@ -268,29 +249,23 @@ int reinit_port(const char *ifname) + return 0; + } + +-struct port *add_port(const char *ifname) ++struct port *add_port(int ifindex, const char *ifname) + { + struct port *newport; + +- newport = porthead; +- while (newport != NULL) { +- if (!strncmp(ifname, newport->ifname, IFNAMSIZ)) +- return 0; +- newport = newport->next; +- } ++ for (newport = porthead; newport; newport = newport->next) ++ if (ifindex == newport->ifindex) ++ return NULL; + +- newport = (struct port *)malloc(sizeof(struct port)); +- if (newport == NULL) { ++ newport = malloc(sizeof(*newport)); ++ if (!newport) { + LLDPAD_DBG("new port malloc failed\n"); + goto fail; + } +- memset(newport,0,sizeof(struct port)); ++ memset(newport, 0, sizeof(*newport)); ++ newport->ifindex = ifindex; + newport->next = NULL; +- newport->ifname = strdup(ifname); +- if (newport->ifname == NULL) { +- LLDPAD_DBG("new port name malloc failed\n"); +- goto fail; +- } ++ strncpy(newport->ifname, ifname, IFNAMSIZ); + + newport->bond_master = is_bond(ifname); + /* Initialize relevant port variables */ +@@ -318,16 +293,14 @@ struct port *add_port(const char *ifname) + return newport; + + fail: +- if(newport) { +- if(newport->ifname) +- free(newport->ifname); ++ if (newport) + free(newport); +- } + return NULL; + } + +-int remove_port(char *ifname) ++int remove_port(const char *ifname) + { ++ int ifindex = get_ifidx(ifname); + struct port *port; /* Pointer to port to remove */ + struct port *parent = NULL; /* Pointer to previous on port stack */ + struct lldp_agent *agent; +@@ -348,7 +321,7 @@ int remove_port(char *ifname) + LLDPAD_DBG("In %s: Found port %s\n", __func__, port->ifname); + + /* Set linkmode to off */ +- set_linkmode(ifname, 0); ++ set_linkmode(ifindex, port->ifname, 0); + + /* Close down the socket */ + l2_packet_deinit(port->l2); +@@ -394,9 +367,6 @@ int remove_port(char *ifname) + else + return -1; + +- if (port->ifname) +- free(port->ifname); +- + free(port); + + return 0; +diff --git a/lldp/ports.h b/lldp/ports.h +index 2aa15c9..21280e0 100644 +--- a/lldp/ports.h ++++ b/lldp/ports.h +@@ -76,7 +76,8 @@ enum portEnableStatus { + + /* lldp port specific structure */ + struct port { +- char *ifname; ++ struct port *next; ++ int ifindex; + u8 hw_resetting; + u8 portEnabled; + u8 prevPortEnabled; +@@ -87,8 +88,7 @@ struct port { + + LIST_HEAD(agent_head, lldp_agent) agent_head; + struct l2_packet_data *l2; +- +- struct port *next; ++ char ifname[IFNAMSIZ]; + }; + + extern struct port *porthead; +@@ -96,8 +96,8 @@ extern struct port *porthead; + #ifdef __cplusplus + extern "C" { + #endif +-struct port *add_port(const char *); +-int remove_port(char *); ++struct port *add_port(int ifindex, const char *); ++int remove_port(const char *); + #ifdef __cplusplus + } + #endif +@@ -118,15 +118,13 @@ void set_port_oper_delay(const char *ifname); + int reinit_port(const char *ifname); + void set_agent_oper_delay(const char *ifname, int type); + +-static inline struct port *port_find_by_name(const char *ifname) ++static inline struct port *port_find_by_ifindex(int ifindex) + { + struct port *port = porthead; + +- while (port) { +- if (!strncmp(ifname, port->ifname, IFNAMSIZ)) ++ for (port = porthead; port; port = port->next) ++ if (ifindex == port->ifindex) + return port; +- port = port->next; +- } + return NULL; + } + +diff --git a/lldp/tx.c b/lldp/tx.c +index 67933a7..69c1a1a 100644 +--- a/lldp/tx.c ++++ b/lldp/tx.c +@@ -118,8 +118,6 @@ void txInitializeLLDP(struct lldp_agent *agent) + } + + agent->tx.state = TX_LLDP_INITIALIZE; +- agent->rx.state = LLDP_WAIT_PORT_OPERATIONAL; +- + agent->tx.localChange = false; + agent->stats.statsFramesOutTotal = 0; + agent->timers.reinitDelay = REINIT_DELAY; +diff --git a/lldp_8021qaz.c b/lldp_8021qaz.c +index b3da01b..094676d 100644 +--- a/lldp_8021qaz.c ++++ b/lldp_8021qaz.c +@@ -419,12 +419,12 @@ inline void set_prio_map(u32 *prio_map, u8 prio, int tc) + * + * Returns 0 on success, error value otherwise. + */ +-static int get_dcbx_hw(const char *ifname, __u8 *dcbx) ++int get_dcbx_hw(const char *ifname, __u8 *dcbx) + { + int err = 0; + struct nlattr *attr; + struct sockaddr_nl dest_addr; +- static struct nl_handle *nlhandle; ++ static struct nl_sock *nlsocket; + struct nl_msg *nlm = NULL; + unsigned char *msg = NULL; + struct nlmsghdr *hdr; +@@ -434,28 +434,28 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx) + .dcb_pad = 0 + }; + +- if (!nlhandle) { +- nlhandle = nl_handle_alloc(); +- if (!nlhandle) { +- LLDPAD_WARN("%s: %s: nl_handle_alloc failed, %s\n", +- __func__, ifname, nl_geterror()); ++ if (!nlsocket) { ++ nlsocket = nl_socket_alloc(); ++ if (!nlsocket) { ++ LLDPAD_WARN("%s: %s: nl_socket_alloc failed\n", ++ __func__, ifname); + err = -ENOMEM; + goto out; + } +- nl_socket_set_local_port(nlhandle, 0); ++ nl_socket_set_local_port(nlsocket, 0); + } + +- err = nl_connect(nlhandle, NETLINK_ROUTE); ++ err = nl_connect(nlsocket, NETLINK_ROUTE); + if (err < 0) { + LLDPAD_WARN("%s: %s nlconnect failed abort get ieee, %s\n", +- __func__, ifname, nl_geterror()); ++ __func__, ifname, nl_geterror(err)); + goto out; + } + + nlm = nlmsg_alloc_simple(RTM_GETDCB, NLM_F_REQUEST); + if (!nlm) { +- LLDPAD_WARN("%s: %s nlmsg_alloc failed abort get ieee, %s\n", +- __func__, ifname, nl_geterror()); ++ LLDPAD_WARN("%s: %s nlmsg_alloc failed abort get ieee\n", ++ __func__, ifname); + err = -ENOMEM; + goto out; + } +@@ -472,14 +472,14 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx) + if (err < 0) + goto out; + +- err = nl_send_auto_complete(nlhandle, nlm); ++ err = nl_send_auto_complete(nlsocket, nlm); + if (err <= 0) { + LLDPAD_WARN("%s: %s 802.1Qaz get app attributes failed\n", + __func__, ifname); + goto out; + } + +- err = nl_recv(nlhandle, &dest_addr, &msg, NULL); ++ err = nl_recv(nlsocket, &dest_addr, &msg, NULL); + if (err <= 0) { + LLDPAD_WARN("%s: %s: nl_recv returned %d\n", __func__, ifname, + err); +@@ -492,6 +492,7 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx) + if (!attr) { + LLDPAD_DBG("%s: %s: nlmsg_find_attr failed, no GDCBX support\n", + __func__, ifname); ++ err = -EOPNOTSUPP; + goto out; + } + +@@ -499,8 +500,8 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx) + out: + nlmsg_free(nlm); + free(msg); +- if (nlhandle) +- nl_close(nlhandle); ++ if (nlsocket) ++ nl_close(nlsocket); + return err; + } + +@@ -524,7 +525,7 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent) + struct ieee_ets *ets = NULL; + struct ieee_pfc *pfc = NULL; + struct app_prio *data = NULL; +- int err; ++ int err, no_set_status; + + if (agent->type != NEAREST_BRIDGE) + return; +@@ -537,12 +538,19 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent) + if (err < 0) + return; + ++ /* If admin has explicitly enabled Rx/Tx, don't override it */ ++ no_set_status = get_config_setting(ifname, agent->type, ARG_ADMINSTATUS, ++ &adminstatus, CONFIG_TYPE_INT); ++ + /* If hardware is not DCBX IEEE compliant or it is managed + * by an LLD agent most likely a firmware agent abort + */ +- if (!(dcbx & DCB_CAP_DCBX_VER_IEEE) || +- (dcbx & DCB_CAP_DCBX_LLD_MANAGED)) ++ if (dcbx & DCB_CAP_DCBX_LLD_MANAGED) { ++ if (no_set_status) ++ set_lldp_agent_admin(ifname, agent->type, ++ (adminstatus & enabledRxOnly)); + return; ++ } + + /* If 802.1Qaz is already configured no need to continue */ + tlvs = ieee8021qaz_data(ifname); +@@ -552,17 +560,11 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent) + /* if there is no persistent adminStatus setting then set to enabledRx + * but do not persist that as a setting. + */ +- if (get_config_setting(ifname, agent->type, ARG_ADMINSTATUS, +- &adminstatus, CONFIG_TYPE_INT)) ++ if (no_set_status) + set_lldp_agent_admin(ifname, agent->type, enabledRxOnly); + + /* lookup port data */ +- port = porthead; +- while (port != NULL) { +- if (!strncmp(ifname, port->ifname, MAX_DEVICE_NAME_LEN)) +- break; +- port = port->next; +- } ++ port = port_find_by_ifindex(get_ifidx(ifname)); + + /* + * Check if link down and/or tlvs exist for current port. +@@ -633,8 +635,10 @@ initialized: + /* Query hardware and set maximum number of TCs with hardware values */ + len = get_ieee_hw(ifname, &ets, &pfc, &data, &cnt); + if (len > 0) { +- tlvs->ets->cfgl->max_tcs = ets->ets_cap; +- tlvs->pfc->local.pfc_cap = pfc->pfc_cap; ++ if (ets) ++ tlvs->ets->cfgl->max_tcs = ets->ets_cap; ++ if (pfc) ++ tlvs->pfc->local.pfc_cap = pfc->pfc_cap; + + free(ets); + free(pfc); +@@ -644,7 +648,7 @@ initialized: + /* if the dcbx field is filled in by the dcbx query then the + * kernel is supports IEEE mode, so make IEEE DCBX active by default. + */ +- if (!dcbx || (dcbx_get_legacy_version(ifname) & ~MASK_DCBX_FORCE)) { ++ if (dcbx_get_legacy_version(ifname) & ~MASK_DCBX_FORCE) { + tlvs->active = false; + } else { + tlvs->active = true; +@@ -786,7 +790,7 @@ static int get_ieee_hw(const char *ifname, struct ieee_ets **ets, + int rem; + int itr = 0; + struct sockaddr_nl dest_addr; +- static struct nl_handle *nlhandle; ++ struct nl_sock *nlsocket = NULL; + struct nl_msg *nlm; + unsigned char *msg = NULL; + struct nlmsghdr *hdr; +@@ -797,20 +801,19 @@ static int get_ieee_hw(const char *ifname, struct ieee_ets **ets, + .dcb_pad = 0 + }; + +- if (!nlhandle) { +- nlhandle = nl_handle_alloc(); +- if (!nlhandle) { +- LLDPAD_WARN("%s: %s: nl_handle_alloc failed, %s\n", +- __func__, ifname, nl_geterror()); +- *cnt = 0; +- return -ENOMEM; +- } +- nl_socket_set_local_port(nlhandle, 0); ++ nlsocket = nl_socket_alloc(); ++ if (!nlsocket) { ++ LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n", ++ __func__, ifname); ++ *cnt = 0; ++ return -ENOMEM; + } ++ nl_socket_set_local_port(nlsocket, 0); + +- if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) { ++ err = nl_connect(nlsocket, NETLINK_ROUTE); ++ if (err < 0) { + LLDPAD_WARN("%s: %s nlconnect failed abort get ieee, %s\n", +- __func__, ifname, nl_geterror()); ++ __func__, ifname, nl_geterror(err)); + goto out1; + } + +@@ -832,14 +835,14 @@ static int get_ieee_hw(const char *ifname, struct ieee_ets **ets, + if (err < 0) + goto out; + +- err = nl_send_auto_complete(nlhandle, nlm); ++ err = nl_send_auto_complete(nlsocket, nlm); + if (err <= 0) { + LLDPAD_WARN("%s: %s 802.1Qaz get app attributes failed\n", + __func__, ifname); + goto out; + } + +- err = nl_recv(nlhandle, &dest_addr, &msg, NULL); ++ err = nl_recv(nlsocket, &dest_addr, &msg, NULL); + if (err <= 0) { + LLDPAD_WARN("%s: %s: nl_recv returned %d\n", __func__, ifname, + err); +@@ -936,7 +939,8 @@ static int get_ieee_hw(const char *ifname, struct ieee_ets **ets, + out: + nlmsg_free(nlm); + free(msg); +- nl_close(nlhandle); ++ nl_close(nlsocket); ++ nl_socket_free(nlsocket); + out1: + *cnt = itr; + return err; +@@ -947,7 +951,7 @@ static int del_ieee_hw(const char *ifname, struct dcb_app *app_data) + int err = 0; + struct nlattr *ieee, *app; + struct sockaddr_nl dest_addr; +- static struct nl_handle *nlhandle; ++ struct nl_sock *nlsocket; + struct nl_msg *nlm; + struct dcbmsg d = { + .dcb_family = AF_UNSPEC, +@@ -955,19 +959,18 @@ static int del_ieee_hw(const char *ifname, struct dcb_app *app_data) + .dcb_pad = 0 + }; + +- if (!nlhandle) { +- nlhandle = nl_handle_alloc(); +- if (!nlhandle) { +- LLDPAD_WARN("%s: %s: nl_handle_alloc failed, %s\n", +- __func__, ifname, nl_geterror()); +- return -ENOMEM; +- } +- nl_socket_set_local_port(nlhandle, 0); ++ nlsocket = nl_socket_alloc(); ++ if (!nlsocket) { ++ LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n", ++ __func__, ifname); ++ return -ENOMEM; + } ++ nl_socket_set_local_port(nlsocket, 0); + +- if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) { ++ err = nl_connect(nlsocket, NETLINK_ROUTE); ++ if (err < 0) { + LLDPAD_WARN("%s: %s nlconnect failed abort hardware set, %s\n", +- __func__, ifname, nl_geterror()); ++ __func__, ifname, nl_geterror(err)); + err = -EIO; + goto out1; + } +@@ -1009,7 +1012,7 @@ static int del_ieee_hw(const char *ifname, struct dcb_app *app_data) + nla_nest_end(nlm, app); + } + nla_nest_end(nlm, ieee); +- err = nl_send_auto_complete(nlhandle, nlm); ++ err = nl_send_auto_complete(nlsocket, nlm); + if (err <= 0) + LLDPAD_WARN("%s: %s 802.1Qaz set attributes failed\n", + __func__, ifname); +@@ -1017,7 +1020,8 @@ static int del_ieee_hw(const char *ifname, struct dcb_app *app_data) + out: + nlmsg_free(nlm); + out2: +- nl_close(nlhandle); ++ nl_close(nlsocket); ++ nl_socket_free(nlsocket); + out1: + return err; + +@@ -1030,7 +1034,7 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data, + int err = 0; + struct nlattr *ieee, *app; + struct sockaddr_nl dest_addr; +- static struct nl_handle *nlhandle; ++ struct nl_sock *nlsocket; + struct nl_msg *nlm; + struct dcbmsg d = { + .dcb_family = AF_UNSPEC, +@@ -1038,15 +1042,13 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data, + .dcb_pad = 0 + }; + +- if (!nlhandle) { +- nlhandle = nl_handle_alloc(); +- if (!nlhandle) { +- LLDPAD_WARN("%s: %s: nl_handle_alloc failed, %s\n", +- __func__, ifname, nl_geterror()); +- return -ENOMEM; +- } +- nl_socket_set_local_port(nlhandle, 0); ++ nlsocket = nl_socket_alloc(); ++ if (!nlsocket) { ++ LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n", ++ __func__, ifname); ++ return -ENOMEM; + } ++ nl_socket_set_local_port(nlsocket, 0); + + if (!ets_data && !pfc_data && !app_data) { + err = 0; +@@ -1060,9 +1062,10 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data, + print_pfc(pfc_data); + #endif + +- if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) { ++ err = nl_connect(nlsocket, NETLINK_ROUTE); ++ if (err < 0) { + LLDPAD_WARN("%s: %s nlconnect failed abort hardware set, %s\n", +- __func__, ifname, nl_geterror()); ++ __func__, ifname, nl_geterror(err)); + err = -EIO; + goto out1; + } +@@ -1118,7 +1121,7 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data, + nla_nest_end(nlm, app); + } + nla_nest_end(nlm, ieee); +- err = nl_send_auto_complete(nlhandle, nlm); ++ err = nl_send_auto_complete(nlsocket, nlm); + if (err <= 0) + LLDPAD_WARN("%s: %s 802.1Qaz set attributes failed\n", + __func__, ifname); +@@ -1126,7 +1129,8 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data, + out: + nlmsg_free(nlm); + out2: +- nl_close(nlhandle); ++ nl_close(nlsocket); ++ nl_socket_free(nlsocket); + out1: + return err; + } +@@ -2146,29 +2150,18 @@ void ieee8021qaz_unregister(struct lldp_module *mod) + */ + void ieee8021qaz_ifdown(char *device_name, struct lldp_agent *agent) + { +- struct port *port = NULL; + struct ieee8021qaz_tlvs *tlvs; + + if (agent->type != NEAREST_BRIDGE) + return; + +- port = porthead; +- while (port != NULL) { +- if (!strncmp(device_name, port->ifname, MAX_DEVICE_NAME_LEN)) +- break; +- port = port->next; +- } +- + tlvs = ieee8021qaz_data(device_name); +- + if (!tlvs) + return; + +- if (tlvs) { +- ieee8021qaz_free_rx(tlvs->rx); +- free(tlvs->rx); +- tlvs->rx = NULL; +- } ++ ieee8021qaz_free_rx(tlvs->rx); ++ free(tlvs->rx); ++ tlvs->rx = NULL; + } + + /* +diff --git a/lldp_8021qaz_cmds.c b/lldp_8021qaz_cmds.c +index 1414a78..c2c270f 100644 +--- a/lldp_8021qaz_cmds.c ++++ b/lldp_8021qaz_cmds.c +@@ -132,7 +132,6 @@ static int + get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, + char *obuf, int obuf_len) + { +- struct ieee8021qaz_tlvs *tlvs; + char buf[250] = ""; + + if (cmd->cmd != cmd_gettlv) +@@ -147,18 +146,14 @@ get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, + return cmd_not_applicable; + } + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- + switch (lldpad_shm_get_dcbx(cmd->ifname)) { +- case dcbx_subtype0: ++ case DCBX_SUBTYPE0: + snprintf(buf, sizeof(buf), "auto"); + break; +- case dcbx_subtype1: ++ case DCBX_SUBTYPE1: + snprintf(buf, sizeof(buf), "CIN"); + break; +- case dcbx_subtype2: ++ case DCBX_SUBTYPE2: + snprintf(buf, sizeof(buf), "CEE"); + break; + default: +@@ -173,11 +168,32 @@ get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, + return cmd_success; + } + ++#define MAX_DCBX_HW_RETRIES 5 ++ ++static bool is_dcbx_hw(const char *ifname) ++{ ++ __u8 dcbx = 0; ++ int err, tries = 0; ++ ++query_retry: ++ err = get_dcbx_hw(ifname, &dcbx); ++ ++ if (err == -ENOMEM && tries < MAX_DCBX_HW_RETRIES) { ++ tries++; ++ goto query_retry; ++ } ++ ++ if (err < 0 || ++ !(dcbx & DCB_CAP_DCBX_VER_IEEE) || ++ dcbx & DCB_CAP_DCBX_LLD_MANAGED) ++ return false; ++ ++ return true; ++} ++ + static int set_arg_dcbx_mode(struct cmd *cmd, UNUSED char *args, + char *arg_value, char *obuf, int obuf_len) + { +- struct ieee8021qaz_tlvs *tlvs; +- + if (cmd->cmd != cmd_settlv) + return cmd_invalid; + +@@ -190,14 +206,14 @@ static int set_arg_dcbx_mode(struct cmd *cmd, UNUSED char *args, + return cmd_not_applicable; + } + ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; ++ + if (strcmp(arg_value, "reset")) + return cmd_invalid; + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; + +- lldpad_shm_set_dcbx(cmd->ifname, dcbx_subtype0); ++ lldpad_shm_set_dcbx(cmd->ifname, DCBX_SUBTYPE0); + snprintf(obuf, obuf_len, "mode = %s\n", arg_value); + + return cmd_success; +@@ -214,8 +230,8 @@ test_arg_dcbx_mode(UNUSED struct cmd *cmd, UNUSED char *args, + static int get_arg_willing(struct cmd *cmd, char *args, + UNUSED char *arg_value, char *obuf, int obuf_len) + { +- int willing = 0; +- struct ieee8021qaz_tlvs *tlvs; ++ char arg_path[256]; ++ int willing, err; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; +@@ -230,26 +246,20 @@ static int get_arg_willing(struct cmd *cmd, char *args, + return cmd_not_applicable; + } + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- switch (cmd->tlvid) { +- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: +- willing = tlvs->ets->cfgl->willing; +- break; +- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: +- willing = tlvs->pfc->local.willing; +- break; +- } ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, ++ cmd->tlvid, args); ++ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &willing, ++ CONFIG_TYPE_INT); + +- if (willing) +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int) strlen(args), args, +- (unsigned int) strlen(VAL_YES), VAL_YES); ++ if (err) ++ snprintf(obuf, obuf_len, "%02x%s%04d", ++ (unsigned int) strlen(args), args, 0); + else + snprintf(obuf, obuf_len, "%02x%s%04x%s", + (unsigned int) strlen(args), args, +- (unsigned int) strlen(VAL_NO), VAL_NO); ++ willing ? (unsigned int)strlen(VAL_YES) : ++ (unsigned int)strlen(VAL_NO), ++ willing ? VAL_YES : VAL_NO); + + return cmd_success; + } +@@ -264,8 +274,6 @@ static int _set_arg_willing(struct cmd *cmd, char *args, + if (cmd->cmd != cmd_settlv) + return cmd_invalid; + +- +- + /* To remain backward compatible and make it easier + * for everyone use to {0|1} notation we still support + * this but also support english variants as well +@@ -297,20 +305,23 @@ static int _set_arg_willing(struct cmd *cmd, char *args, + return cmd_not_applicable; + } + +- if (test) ++ ++ if (test) { ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; + return cmd_success; ++ } + + tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- +- switch (cmd->tlvid) { +- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: +- tlvs->ets->cfgl->willing = !!willing; +- break; +- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: +- tlvs->pfc->local.willing = !!willing; +- break; ++ if (tlvs) { ++ switch (cmd->tlvid) { ++ case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: ++ tlvs->ets->cfgl->willing = !!willing; ++ break; ++ case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: ++ tlvs->pfc->local.willing = !!willing; ++ break; ++ } + } + + snprintf(obuf, obuf_len, "willing = %s\n", +@@ -340,7 +351,9 @@ static int test_arg_willing(struct cmd *cmd, char *args, + static int get_arg_numtc(struct cmd *cmd, char *args, + UNUSED char *arg_value, char *obuf, int obuf_len) + { +- struct ieee8021qaz_tlvs *tlvs; ++ char arg_path[256]; ++ int max_tcs = 0; ++ int err = 0; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; +@@ -356,12 +369,18 @@ static int get_arg_numtc(struct cmd *cmd, char *args, + return cmd_not_applicable; + } + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; + +- snprintf(obuf, obuf_len, "%02x%s%04x%i", +- (unsigned int) strlen(args), args, 1, tlvs->ets->cfgl->max_tcs); ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, ++ cmd->tlvid, args); ++ err = get_config_setting(cmd->ifname, cmd->type, ++ arg_path, &max_tcs, CONFIG_TYPE_INT); ++ ++ if (!err) ++ snprintf(obuf, obuf_len, "%02x%s%04x%i", ++ (unsigned int) strlen(args), args, 1, max_tcs); ++ else ++ snprintf(obuf, obuf_len, "%02x%s%04d", ++ (unsigned int) strlen(args), args, 0); + + return cmd_success; + } +@@ -377,10 +396,9 @@ static int get_arg_up2tc(struct cmd *cmd, char *args, + UNUSED char *arg_value, + char *obuf, UNUSED int obuf_len) + { +- struct ieee8021qaz_tlvs *tlvs; +- char buf[250] = ""; +- u32 *pmap = NULL; +- int i; ++ char arg_path[256] = ""; ++ const char *buf = ""; ++ int err; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; +@@ -395,33 +413,18 @@ static int get_arg_up2tc(struct cmd *cmd, char *args, + return cmd_not_applicable; + } + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- switch (cmd->tlvid) { +- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: +- pmap = &tlvs->ets->cfgl->prio_map; +- break; +- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: +- pmap = &tlvs->ets->recl->prio_map; +- break; +- } ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, ++ cmd->tlvid, args); ++ err = get_config_setting(cmd->ifname, cmd->type, ++ arg_path, &buf, CONFIG_TYPE_STRING); + +- for (i = 0; i < 8; i++) { +- char cat[5]; +- +- if (i) +- snprintf(cat, sizeof(cat), ",%i:%i", i, +- get_prio_map(*pmap, i)); +- else +- snprintf(cat, sizeof(cat), "%i:%i", i, +- get_prio_map(*pmap, i)); +- strncat(buf, cat, sizeof(buf) - strlen(buf) - 1); +- } +- +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int) strlen(args), args, +- (unsigned int) strlen(buf), buf); ++ if (!err) ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int) strlen(args), args, ++ (unsigned int) strlen(buf), buf); ++ else ++ snprintf(obuf, obuf_len, "%02x%s%04d", ++ (unsigned int) strlen(args), args, 0); + + return cmd_success; + } +@@ -433,35 +436,33 @@ _set_arg_up2tc(struct cmd *cmd, char *args, const char *arg_value, + struct ieee8021qaz_tlvs *tlvs; + char arg_path[256]; + char *toked_maps, *parse; +- u32 *pmap; +- u32 save_pmap; +- u8 max; +- int i, err = cmd_success; ++ u32 *pmap = NULL; ++ u8 max = MAX_TCS; ++ int err = cmd_success; + + if (cmd->cmd != cmd_settlv) + return cmd_invalid; + ++ tlvs = ieee8021qaz_data(cmd->ifname); ++ + switch (cmd->tlvid) { + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- pmap = &tlvs->ets->cfgl->prio_map; +- max = tlvs->ets->cfgl->max_tcs; ++ if (tlvs) { ++ pmap = &tlvs->ets->cfgl->prio_map; ++ max = tlvs->ets->cfgl->max_tcs; ++ } + break; + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- pmap = &tlvs->ets->recl->prio_map; +- max = MAX_TCS; ++ if (tlvs) { ++ pmap = &tlvs->ets->recl->prio_map; ++ max = MAX_TCS; ++ } + break; + case INVALID_TLVID: + return cmd_invalid; + default: + return cmd_not_applicable; + } +- save_pmap = *pmap; + + parse = strdup(arg_value); + if (!parse) +@@ -526,29 +527,25 @@ _set_arg_up2tc(struct cmd *cmd, char *args, const char *arg_value, + } + + mask = ~(0xffffffff & (0xF << (4 * (7-prio)))); +- *pmap &= mask; +- *pmap |= tc << (4 * (7-prio)); ++ if (pmap && !test) { ++ *pmap &= mask; ++ *pmap |= tc << (4 * (7-prio)); ++ } + toked_maps = strtok(NULL, ","); + } +- } else { ++ } else if (pmap && !test) { + *pmap = 0; + } + + if (test) { +- *pmap = save_pmap; ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; + free(parse); + return cmd_success; + } + + /* Build output buffer */ +- strncat(obuf, "up2tc = ", obuf_len - strlen(obuf) - 1); +- for (i = 0; i < 8; i++) { +- char cat[5]; +- +- snprintf(cat, sizeof(cat), "%i:%i ", i, get_prio_map(*pmap, i)); +- strncat(obuf, cat, obuf_len - strlen(obuf) - 1); +- } +- strncat(obuf, "\n", obuf_len - strlen(obuf) - 1); ++ snprintf(obuf, obuf_len, "up2tc = %s\n", arg_value); + + /* Update configuration file with new attribute */ + snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, +@@ -576,26 +573,17 @@ static int test_arg_up2tc(struct cmd *cmd, char *args, + static int get_arg_tcbw(struct cmd *cmd, char *args, + UNUSED char *arg_value, char *obuf, UNUSED int obuf_len) + { +- struct ieee8021qaz_tlvs *tlvs; +- char buf[250] = ""; +- int i; +- u8 *bmap; ++ char arg_path[250] = ""; ++ const char *buf = ""; ++ int err; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; + + switch (cmd->tlvid) { + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- bmap = tlvs->ets->cfgl->tc_bw; + break; + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- bmap = tlvs->ets->recl->tc_bw; + break; + case INVALID_TLVID: + return cmd_invalid; +@@ -603,17 +591,18 @@ static int get_arg_tcbw(struct cmd *cmd, char *args, + return cmd_not_applicable; + } + +- for (i = 0; i < 8; i++) { +- char cat[6]; +- if (i) +- snprintf(cat, sizeof(cat), ",%i", bmap[i]); +- else +- snprintf(cat, sizeof(cat), "%i", bmap[i]); +- strncat(buf, cat, sizeof(buf) - strlen(buf) - 1); +- } ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, ++ cmd->tlvid, args); ++ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &buf, ++ CONFIG_TYPE_STRING); + +- snprintf(obuf, obuf_len, "%02x%s%04x%s", (unsigned int) strlen(args), +- args, (unsigned int) strlen(buf), buf); ++ if (!err) ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int) strlen(args), args, ++ (unsigned int) strlen(buf), buf); ++ else ++ snprintf(obuf, obuf_len, "%02x%s%04d", ++ (unsigned int) strlen(args), args, 0); + + return cmd_success; + } +@@ -626,7 +615,7 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, + char arg_path[256]; + char *toked_bw, *parse; + int i, err = cmd_success; +- u8 *tcbw, percent[8] = {0}, total = 0; ++ u8 *tcbw = NULL, percent[8] = {0}, total = 0; + + if (cmd->cmd != cmd_settlv) + return cmd_invalid; +@@ -634,15 +623,13 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, + switch (cmd->tlvid) { + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: + tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- tcbw = tlvs->ets->cfgl->tc_bw; ++ if (tlvs) ++ tcbw = tlvs->ets->cfgl->tc_bw; + break; + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: + tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- tcbw = tlvs->ets->recl->tc_bw; ++ if (tlvs) ++ tcbw = tlvs->ets->recl->tc_bw; + break; + case INVALID_TLVID: + return cmd_invalid; +@@ -668,9 +655,11 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, + err = cmd_invalid; + goto invalid; + } else if (test) { ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; + free(parse); + return cmd_success; +- } else { ++ } else if (tcbw) { + memcpy(tcbw, percent, sizeof(*tcbw) * MAX_TCS); + } + +@@ -708,26 +697,17 @@ static int test_arg_tcbw(struct cmd *cmd, char *args, + static int get_arg_tsa(struct cmd *cmd, char *args, UNUSED char *arg_value, + char *obuf, UNUSED int obuf_len) + { +- struct ieee8021qaz_tlvs *tlvs; +- char buf[250] = ""; +- int i; +- u8 *tsa; ++ const char *buf = ""; ++ char arg_path[250] = ""; ++ int err; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; + + switch (cmd->tlvid) { + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- tsa = tlvs->ets->cfgl->tsa_map; + break; + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- tsa = tlvs->ets->recl->tsa_map; + break; + case INVALID_TLVID: + return cmd_invalid; +@@ -735,40 +715,18 @@ static int get_arg_tsa(struct cmd *cmd, char *args, UNUSED char *arg_value, + return cmd_not_applicable; + } + +- for (i = 0; i < 8; i++) { +- char cnt[4]; +- int space_left; +- +- if (i) +- snprintf(cnt, sizeof(cnt), ",%i:", i); +- else +- snprintf(cnt, sizeof(cnt), "%i:", i); +- strncat(buf, cnt, sizeof(buf) - strlen(buf) - 1); +- +- space_left = sizeof(buf) - strlen(buf) - 1; +- switch (tsa[i]) { +- case IEEE8021Q_TSA_STRICT: +- strncat(buf, "strict", space_left); +- break; +- case IEEE8021Q_TSA_CBSHAPER: +- strncat(buf, "cb_shaper", space_left); +- break; +- case IEEE8021Q_TSA_ETS: +- strncat(buf, "ets", space_left); +- break; +- case IEEE8021Q_TSA_VENDOR: +- strncat(buf, "vendor", space_left); +- break; +- default: +- strncat(buf, "unknown", space_left); +- break; +- } +- } +- +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int) strlen(args), args, +- (unsigned int) strlen(buf), buf); +- ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", ++ TLVID_PREFIX, cmd->tlvid, args); ++ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &buf, ++ CONFIG_TYPE_STRING); ++ ++ if (!err) ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int) strlen(args), args, ++ (unsigned int) strlen(buf), buf); ++ else ++ snprintf(obuf, obuf_len, "%02x%s%04d", ++ (unsigned int) strlen(args), args, 0); + + return cmd_success; + } +@@ -781,7 +739,7 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, + char arg_path[256]; + char *toked_maps, *parse; + int i, err = cmd_success; +- u8 *tsa; ++ u8 *tsa = NULL; + + if (cmd->cmd != cmd_settlv) + return cmd_invalid; +@@ -789,15 +747,13 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, + switch (cmd->tlvid) { + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: + tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- tsa = tlvs->ets->cfgl->tsa_map; ++ if (tlvs) ++ tsa = tlvs->ets->cfgl->tsa_map; + break; + case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: + tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- tsa = tlvs->ets->recl->tsa_map; ++ if (tlvs) ++ tsa = tlvs->ets->recl->tsa_map; + break; + case INVALID_TLVID: + return cmd_invalid; +@@ -840,15 +796,17 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, + goto invalid; + } + +- if (!test) ++ if (!test && tsa) + tsa[tc] = type; + toked_maps = strtok(NULL, ","); + } +- } else if (!test) { ++ } else if (!test && tsa) { + memset(tsa, 0, MAX_TCS); + } + + if (test) { ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; + free(parse); + return cmd_success; + } +@@ -862,22 +820,24 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, + strncat(obuf, cnt, obuf_len - strlen(obuf) - 1); + + space_left = obuf_len - strlen(obuf) - 1; +- switch (tsa[i]) { +- case IEEE8021Q_TSA_STRICT: +- strncat(obuf, "strict ", space_left); +- break; +- case IEEE8021Q_TSA_CBSHAPER: +- strncat(obuf, "cb_shaper ", space_left); +- break; +- case IEEE8021Q_TSA_ETS: +- strncat(obuf, "ets ", space_left); +- break; +- case IEEE8021Q_TSA_VENDOR: +- strncat(obuf, "vendor ", space_left); +- break; +- default: +- strncat(obuf, "unknown ", space_left); +- break; ++ if (tsa) { ++ switch (tsa[i]) { ++ case IEEE8021Q_TSA_STRICT: ++ strncat(obuf, "strict ", space_left); ++ break; ++ case IEEE8021Q_TSA_CBSHAPER: ++ strncat(obuf, "cb_shaper ", space_left); ++ break; ++ case IEEE8021Q_TSA_ETS: ++ strncat(obuf, "ets ", space_left); ++ break; ++ case IEEE8021Q_TSA_VENDOR: ++ strncat(obuf, "vendor ", space_left); ++ break; ++ default: ++ strncat(obuf, "unknown ", space_left); ++ break; ++ } + } + } + strncat(obuf, "\n", obuf_len - strlen(obuf) - 1); +@@ -907,11 +867,8 @@ static int test_arg_tsa(struct cmd *cmd, char *args, char *arg_value, + static int get_arg_enabled(struct cmd *cmd, char *args, UNUSED char *arg_value, + char *obuf, UNUSED int obuf_len) + { +- struct ieee8021qaz_tlvs *tlvs; +- char buf[20] = ""; +- int i; +- bool first; +- u8 pfc; ++ char arg_path[256]; ++ int err, pfc; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; +@@ -925,33 +882,17 @@ static int get_arg_enabled(struct cmd *cmd, char *args, UNUSED char *arg_value, + return cmd_not_applicable; + } + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- +- pfc = tlvs->pfc->local.pfc_enable; +- +- first = true; +- for (i = 0; i < 8; i++) { +- if (pfc & (1 << i)) { +- char val[3]; +- +- if (first) { +- snprintf(val, sizeof(val), "%i", i); +- first = false; +- } else { +- snprintf(val, sizeof(val), ",%i", i); +- } +- strncat(buf, val, sizeof(buf) - strlen(buf) - 1); +- } +- } +- +- if (first) +- strncpy(buf, "none", sizeof(buf)); +- +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int) strlen(args), args, +- (unsigned int) strlen(buf), buf); ++ snprintf(arg_path, sizeof(arg_path), ++ "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); ++ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &pfc, ++ CONFIG_TYPE_INT); ++ ++ if (!err) ++ snprintf(obuf, obuf_len, "%02x%s%04x%i", ++ (unsigned int) strlen(args), args, 2, pfc); ++ else ++ snprintf(obuf, obuf_len, "%02x%s%04d", ++ (unsigned int) strlen(args), args, 0); + + + return cmd_success; +@@ -979,10 +920,6 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, + return cmd_not_applicable; + } + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- + parse = strdup(arg_value); + if (!parse) + return cmd_failed; +@@ -1014,6 +951,8 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, + } + + if (test) { ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; + free(parse); + return cmd_success; + } +@@ -1040,7 +979,10 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, + "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); + set_config_setting(cmd->ifname, cmd->type, arg_path, &mask, + CONFIG_TYPE_INT); +- tlvs->pfc->local.pfc_enable = mask; ++ ++ tlvs = ieee8021qaz_data(cmd->ifname); ++ if (tlvs) ++ tlvs->pfc->local.pfc_enable = mask; + somethingChangedLocal(cmd->ifname, cmd->type); + invalid: + free(parse); +@@ -1062,7 +1004,9 @@ static int test_arg_enabled(struct cmd *cmd, char *args, + static int get_arg_delay(struct cmd *cmd, char *args, + UNUSED char *arg_value, char *obuf, int obuf_len) + { +- struct ieee8021qaz_tlvs *tlvs; ++ unsigned int delay; ++ char arg_path[256]; ++ int err; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; +@@ -1076,13 +1020,17 @@ static int get_arg_delay(struct cmd *cmd, char *args, + return cmd_not_applicable; + } + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; ++ snprintf(arg_path, sizeof(arg_path), ++ "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); ++ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &delay, ++ CONFIG_TYPE_INT); + +- snprintf(obuf, obuf_len, "%02x%s%04x%02x", +- (unsigned int) strlen(args), args, 2, +- tlvs->pfc->local.delay); ++ if (!err) ++ snprintf(obuf, obuf_len, "%02x%s%04x%02x", ++ (unsigned int) strlen(args), args, 2, delay); ++ else ++ snprintf(obuf, obuf_len, "%02x%s%04d", ++ (unsigned int) strlen(args), args, 0); + + return cmd_success; + } +@@ -1106,14 +1054,15 @@ static int _set_arg_delay(struct cmd *cmd, char *args, + return cmd_not_applicable; + } + +- tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; +- +- if (test) ++ if (test) { ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; + return cmd_success; ++ } + +- tlvs->pfc->local.delay = delay; ++ tlvs = ieee8021qaz_data(cmd->ifname); ++ if (tlvs) ++ tlvs->pfc->local.delay = delay; + + snprintf(obuf, obuf_len, "delay = %i\n", delay); + +@@ -1140,13 +1089,38 @@ static int test_arg_delay(struct cmd *cmd, char *args, + return _set_arg_delay(cmd, args, arg_value, obuf, obuf_len, true); + } + ++static void arg_app_strncat_hw(char *new_app, int hw) ++{ ++ switch (hw) { ++ case IEEE_APP_SET: ++ strncat(new_app, "hw (pending set)\n", ++ sizeof(new_app) - strlen(new_app) - 2); ++ break; ++ case IEEE_APP_DEL: ++ strncat(new_app, "hw (pending delete)\n", ++ sizeof(new_app) - strlen(new_app) - 2); ++ break; ++ case IEEE_APP_DONE: ++ strncat(new_app, "hw (set)\n", ++ sizeof(new_app) - strlen(new_app) - 2); ++ break; ++ default: ++ strncat(new_app, " hw (unknown)\n", ++ sizeof(new_app) - strlen(new_app) - 2); ++ break; ++ } ++} ++ + static int get_arg_app(struct cmd *cmd, char *args, UNUSED char *arg_value, + char *obuf, int obuf_len) + { + struct ieee8021qaz_tlvs *tlvs; +- int i = 0; + struct app_obj *np; + char app_buf[2048] = "(prio,sel,proto)\n"; ++ char new_app[80] = ""; ++ const char *app; ++ u8 prio, sel; ++ int proto, hw = -1, i; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; +@@ -1161,55 +1135,93 @@ static int get_arg_app(struct cmd *cmd, char *args, UNUSED char *arg_value, + } + + tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; ++ for (i = 0; i < MAX_APP_ENTRIES; i++) { ++ char arg_path[256]; ++ char *parse, *app_tuple; ++ int err; + +- LIST_FOREACH(np, &tlvs->app_head, entry) { +- char new_app[80]; +- char state[15]; +- struct dcb_app *dcb_app = &np->app; ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s%i", ++ TLVID_PREFIX, TLVID_8021(LLDP_8021QAZ_APP), ++ ARG_APP, i); ++ errno = 0; ++ err = get_config_setting(cmd->ifname, cmd->type, arg_path, ++ &app, CONFIG_TYPE_STRING); ++ if (err) ++ continue; + +- switch (np->hw) { +- case IEEE_APP_SET: +- strcpy(state, "pending set"); ++ /* Parse cfg file input, bounds checking done on set app cmd */ ++ parse = strdup(app); ++ if (!parse) + break; +- case IEEE_APP_DEL: +- strcpy(state, "pending delete"); ++ app_tuple = strtok(parse, ","); ++ if (!app_tuple) + break; +- case IEEE_APP_DONE: +- strcpy(state, "set"); ++ prio = atoi(app_tuple); ++ app_tuple = strtok(NULL, ","); ++ if (!app_tuple) + break; +- default: +- strcpy(state, "unknown"); ++ sel = atoi(app_tuple); ++ ++ app_tuple = strtok(NULL, ","); ++ if (!app_tuple) + break; +- } + +- if (dcb_app->selector == 1) { ++ /* APP Data can be in hex or integer form */ ++ errno = 0; ++ proto = (int) strtol(app_tuple, NULL, 0); ++ if (sel == 1) { + snprintf(new_app, sizeof(new_app), +- "%i:(%i,%i,0x%04x) %s (%s)\n", i, +- dcb_app->priority, +- dcb_app->selector, +- dcb_app->protocol, +- np->peer ? "peer" : "local", +- state); ++ "%i:(%i,%i,0x%04x) local ", i, ++ prio, sel, proto); + } else { + snprintf(new_app, sizeof(new_app), +- "%i:(%i,%i,%i) %s hw (%s)\n", i, +- dcb_app->priority, +- dcb_app->selector, +- dcb_app->protocol, +- np->peer ? "peer" : "local", +- state); ++ "%i:(%i,%i,%i) local ", i, ++ prio, sel, proto); + } ++ ++ if (tlvs) { ++ LIST_FOREACH(np, &tlvs->app_head, entry) { ++ if (np->app.selector == sel && ++ np->app.protocol == proto && ++ np->app.priority == prio && ++ !np->peer) ++ hw = np->hw; ++ } ++ } ++ ++ arg_app_strncat_hw(new_app, hw); + strncat(app_buf, new_app, sizeof(app_buf) - strlen(app_buf) - 2); +- i++; ++ } ++ ++ if (tlvs) { ++ LIST_FOREACH(np, &tlvs->app_head, entry) { ++ if (!np->peer) ++ continue; ++ ++ if (np->app.selector == 1) { ++ snprintf(new_app, sizeof(new_app), ++ "%i:(%i,%i,0x%04x) peer ", i, ++ np->app.priority, ++ np->app.selector, ++ np->app.protocol); ++ } else { ++ snprintf(new_app, sizeof(new_app), ++ "%i:(%i,%i,%i) peer ", i, ++ np->app.priority, ++ np->app.selector, ++ np->app.protocol); ++ } ++ ++ arg_app_strncat_hw(new_app, np->hw); ++ strncat(app_buf, new_app, ++ sizeof(app_buf) - strlen(app_buf) - 2); ++ } + } + + snprintf(obuf, obuf_len, "%02x%s%04x%s", + (unsigned int) strlen(args), args, + (unsigned int) strlen(app_buf), app_buf); + +- + return cmd_success; + } + +@@ -1242,8 +1254,6 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, + } + + tlvs = ieee8021qaz_data(cmd->ifname); +- if (!tlvs) +- return cmd_device_not_found; + + parse = strdup(arg_value); + if (!parse) +@@ -1298,8 +1308,11 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, + + free(parse); + +- if (test) ++ if (test) { ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; + return cmd_success; ++ } + + snprintf(new_argval, sizeof(new_argval), + "%1u,%1u,%5u", (u8) prio, (u8) sel, (u16)pid); +@@ -1341,6 +1354,9 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, + return cmd_failed; + + /* Build app noting we verified prio, sel, and pid inputs */ ++ if (!tlvs) ++ goto write_app_config; ++ + ieee8021qaz_mod_app(&tlvs->app_head, 0, (u8) prio, (u8) sel, (u16) pid, + (cmd->ops & op_delete) ? op_delete : 0); + ieee8021qaz_app_sethw(cmd->ifname, &tlvs->app_head); +@@ -1348,45 +1364,28 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, + i = 0; + LIST_FOREACH(np, &tlvs->app_head, entry) { + char new_app[80]; +- char state[15]; +- struct dcb_app *dcb_app = &np->app; + +- switch (np->hw) { +- case IEEE_APP_SET: +- strcpy(state, "pending set"); +- break; +- case IEEE_APP_DEL: +- strcpy(state, "pending delete"); +- break; +- case IEEE_APP_DONE: +- strcpy(state, "set"); +- break; +- default: +- strcpy(state, "unknown"); +- break; +- } +- +- if (dcb_app->selector == 1) { ++ if (np->app.selector == 1) { + snprintf(new_app, sizeof(new_app), +- "%i:(%i,%i,0x%04x) %s (%s)\n", i, +- dcb_app->priority, +- dcb_app->selector, +- dcb_app->protocol, +- np->peer ? "peer" : "local", +- state); ++ "%i:(%i,%i,0x%04x) %s ", i, ++ np->app.priority, ++ np->app.selector, ++ np->app.protocol, ++ np->peer ? "peer" : "local"); + } else { + snprintf(new_app, sizeof(new_app), +- "%i:(%i,%i,%i) %s (%s)\n", i, +- dcb_app->priority, +- dcb_app->selector, +- dcb_app->protocol, +- np->peer ? "peer" : "local", +- state); ++ "%i:(%i,%i,%i) %s ", i, ++ np->app.priority, ++ np->app.selector, ++ np->app.protocol, ++ np->peer ? "peer" : "local"); + } ++ arg_app_strncat_hw(new_app, np->hw); + strncat(obuf, new_app, obuf_len - strlen(obuf) - 2); + i++; + } + ++write_app_config: + somethingChangedLocal(cmd->ifname, cmd->type); + + if (cmd->ops & op_delete) +@@ -1434,7 +1433,7 @@ get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, + snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", + TLVID_PREFIX, cmd->tlvid, arg); + +- if (!is_tlv_txdisabled(cmd->ifname, cmd->type, cmd->tlvid)) ++ if (is_tlv_txenabled(cmd->ifname, cmd->type, cmd->tlvid)) + value = true; + else + value = false; +@@ -1500,8 +1499,11 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, + err = get_config_setting(cmd->ifname, cmd->type, arg_path, + &curr, CONFIG_TYPE_BOOL); + +- if (test) ++ if (test) { ++ if (!is_dcbx_hw(cmd->ifname)) ++ return cmd_not_capable; + return cmd_success; ++ } + + snprintf(obuf, obuf_len, "enabled = %s\n", value ? "yes" : "no"); + +diff --git a/lldp_8023.c b/lldp_8023.c +index e8e3f31..eea4bc7 100644 +--- a/lldp_8023.c ++++ b/lldp_8023.c +@@ -320,40 +320,32 @@ static void ieee8023_free_tlv(struct ieee8023_data *bd) + } + } + +-static int ieee8023_bld_tlv(struct ieee8023_data *bd, +- struct lldp_agent *agent) ++static int ieee8023_bld_tlv(struct ieee8023_data *bd, struct lldp_agent *agent) + { +- int rc = 0; +- +- if (!port_find_by_name(bd->ifname)) { +- rc = EEXIST; +- goto out_err; +- } ++ if (!port_find_by_ifindex(get_ifidx(bd->ifname))) ++ return -EEXIST; + + if (ieee8023_bld_maccfg_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:ieee8023_bld_macfg_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return 0; + } + if (ieee8023_bld_powvmdi_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:ieee8023_bld_powvmdi_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return 0; + } + if (ieee8023_bld_linkagg_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:ieee8023_bld_linkagg_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return 0; + } + if (ieee8023_bld_maxfs_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:ieee8023_bld_maxfs_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return 0; + } +- rc = 0; +- +-out_err: +- return rc; ++ return 0; + } + + static void ieee8023_free_data(struct ieee8023_user_data *ud) +diff --git a/lldp_basman.c b/lldp_basman.c +index 4916e19..824dd9a 100644 +--- a/lldp_basman.c ++++ b/lldp_basman.c +@@ -541,42 +541,35 @@ static void basman_free_tlv(struct basman_data *bd) + /* build unpacked tlvs */ + static int basman_bld_tlv(struct basman_data *bd, struct lldp_agent *agent) + { +- int rc = EPERM; +- +- if (!port_find_by_name(bd->ifname)) { +- rc = EEXIST; +- goto out_err; +- } ++ if (!port_find_by_ifindex(get_ifidx(bd->ifname))) ++ return -EEXIST; + + if (basman_bld_portdesc_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:basman_bld_portdesc_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return -EPERM; + } + if (basman_bld_sysname_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:basman_bld_sysname_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return -EPERM; + } + if (basman_bld_sysdesc_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:basman_bld_sysdesc_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return -EPERM; + } + if (basman_bld_syscaps_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:basman_bld_syscaps_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return -EPERM; + } + if (basman_bld_manaddr_tlv(bd, agent)) { + LLDPAD_DBG("%s:%s:basman_bld_manaddr_tlv() failed\n", +- __func__, bd->ifname); +- goto out_err; ++ __func__, bd->ifname); ++ return -EPERM; + } +- rc = 0; +- +-out_err: +- return rc; ++ return 0; + } + + static void basman_free_data(struct basman_user_data *bud) +diff --git a/lldp_dcbx.c b/lldp_dcbx.c +index e9f41a8..9999e33 100644 +--- a/lldp_dcbx.c ++++ b/lldp_dcbx.c +@@ -210,7 +210,7 @@ int dcbx_bld_tlv(struct port *newport, struct lldp_agent *agent) + goto fail_add; + } + +- if (tlvs->dcbx_st == dcbx_subtype2) { ++ if (tlvs->dcbx_st == DCBX_SUBTYPE2) { + tlvs->pg2 = bld_dcbx2_pg_tlv(tlvs, &success); + if (!success) { + LLDPAD_INFO("bld_dcbx2_pg_tlv: failed\n"); +@@ -224,7 +224,7 @@ int dcbx_bld_tlv(struct port *newport, struct lldp_agent *agent) + } + } + +- if (tlvs->dcbx_st == dcbx_subtype2) { ++ if (tlvs->dcbx_st == DCBX_SUBTYPE2) { + tlvs->pfc2 = bld_dcbx2_pfc_tlv(tlvs, &success); + if (!success) { + LLDPAD_INFO("bld_dcbx2_pfc_tlv: failed\n"); +@@ -238,7 +238,7 @@ int dcbx_bld_tlv(struct port *newport, struct lldp_agent *agent) + } + } + +- if (tlvs->dcbx_st == dcbx_subtype2) { ++ if (tlvs->dcbx_st == DCBX_SUBTYPE2) { + tlvs->app2 = bld_dcbx2_app_tlv(tlvs, &success); + if (!success) { + LLDPAD_INFO("bld_dcbx2_app_tlv: failed\n"); +@@ -259,7 +259,7 @@ int dcbx_bld_tlv(struct port *newport, struct lldp_agent *agent) + goto fail_add; + } + +- if (tlvs->dcbx_st == dcbx_subtype2) { ++ if (tlvs->dcbx_st == DCBX_SUBTYPE2) { + tlvs->dcbx2 = bld_dcbx2_tlv(tlvs); + if (tlvs->dcbx2 == NULL) { + LLDPAD_INFO("add_port: bld_dcbx2_tlv failed\n"); +@@ -364,7 +364,7 @@ struct packed_tlv* dcbx_gettlv(struct port *port, struct lldp_agent *agent) + dcbx_free_tlv(tlvs); + + dcbx_bld_tlv(port, agent); +- if (tlvs->dcbx_st == dcbx_subtype2) { ++ if (tlvs->dcbx_st == DCBX_SUBTYPE2) { + /* Load Type127 - dcbx subtype 2*/ + if (tlv_ok(tlvs->dcbx2)) + ptlv = pack_tlv(tlvs->dcbx2); +@@ -484,7 +484,8 @@ void dcbx_unregister(struct lldp_module *mod) + + void dcbx_ifup(char *ifname, struct lldp_agent *agent) + { +- struct port *port = NULL; ++ int ifindex, ret; ++ struct port *port; + struct dcbx_tlvs *tlvs; + struct dcbd_user_data *dud; + struct dcbx_manifest *manifest; +@@ -501,14 +502,15 @@ void dcbx_ifup(char *ifname, struct lldp_agent *agent) + if (agent->type != NEAREST_BRIDGE) + return; + +- port = port_find_by_name(ifname); ++ ifindex = get_ifidx(ifname); ++ port = port_find_by_ifindex(ifindex); + + dud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_DCBX); + tlvs = dcbx_data(ifname); + + if (!port) + return; +- else if (tlvs) ++ if (tlvs) + goto initialized; + + /* Abort initialization on hardware that does not support +@@ -529,14 +531,12 @@ void dcbx_ifup(char *ifname, struct lldp_agent *agent) + if (dcb_support.dcbx && !(dcb_support.dcbx & DCB_CAP_DCBX_HOST)) + return; + +- /* if no adminStatus setting or wrong setting for adminStatus, +- * then set adminStatus to enabledRxTx. +- */ +- if (get_config_setting(ifname, agent->type, ARG_ADMINSTATUS, +- &adminstatus, CONFIG_TYPE_INT) || +- adminstatus == enabledTxOnly || +- adminstatus == enabledRxOnly) { +- ++ /* if no adminStatus setting default to enabled for DCBX */ ++ ret = get_config_setting(ifname, agent->type, ++ ARG_ADMINSTATUS, ++ &adminstatus, ++ CONFIG_TYPE_INT); ++ if (ret != cmd_success) { + /* set enableTx to true if it is not already set */ + snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, + (OUI_CEE_DCBX << 8) | 1, ARG_TLVTXENABLE); +@@ -634,7 +634,6 @@ initialized: + + void dcbx_ifdown(char *device_name, struct lldp_agent *agent) + { +- struct port *port = NULL; + struct dcbx_tlvs *tlvs; + + if (agent->type != NEAREST_BRIDGE) +@@ -644,30 +643,19 @@ void dcbx_ifdown(char *device_name, struct lldp_agent *agent) + if (is_bond(device_name)) + return; + +- port = porthead; +- while (port != NULL) { +- if (!strncmp(device_name, port->ifname, MAX_DEVICE_NAME_LEN)) +- break; +- port = port->next; +- } +- + tlvs = dcbx_data(device_name); +- + if (!tlvs) + return; + + /* remove dcb port */ +- if (check_port_dcb_mode(device_name)) { ++ if (check_port_dcb_mode(device_name)) + dcbx_remove_adapter(device_name); +- } + +- if (tlvs) { +- LIST_REMOVE(tlvs, entry); +- dcbx_free_tlv(tlvs); +- dcbx_free_manifest(tlvs->manifest); +- free(tlvs->manifest); +- free(tlvs); +- } ++ LIST_REMOVE(tlvs, entry); ++ dcbx_free_tlv(tlvs); ++ dcbx_free_manifest(tlvs->manifest); ++ free(tlvs->manifest); ++ free(tlvs); + } + + void clear_dcbx_manifest(struct dcbx_tlvs *dcbx) +@@ -745,12 +733,12 @@ int dcbx_rchange(struct port *port, struct lldp_agent *agent, struct unpacked_tl + if ((memcmp(tlv->info, &oui, DCB_OUI_LEN) != 0)) + return SUBTYPE_INVALID; + +- if ((tlv->info[DCB_OUI_LEN] == dcbx_subtype2) ++ if ((tlv->info[DCB_OUI_LEN] == DCBX_SUBTYPE2) + && (agent->lldpdu & RCVD_LLDP_DCBX2_TLV)) { + LLDPAD_INFO("Received duplicate DCBX2 TLVs\n"); + return TLV_ERR; + } +- if ((tlv->info[DCB_OUI_LEN] == dcbx_subtype1) ++ if ((tlv->info[DCB_OUI_LEN] == DCBX_SUBTYPE1) + && (agent->lldpdu & RCVD_LLDP_DCBX1_TLV)) { + LLDPAD_INFO("Received duplicate DCBX1 TLVs\n"); + return TLV_ERR; +@@ -760,14 +748,14 @@ int dcbx_rchange(struct port *port, struct lldp_agent *agent, struct unpacked_tl + * the currently configured legacy dcbx mode. + * However, capture if any legacy DCBX TLVs are recieved. + */ +- if (tlv->info[DCB_OUI_LEN] == dcbx_subtype2) { +- if (dcbx->dcbx_st == dcbx_subtype2) ++ if (tlv->info[DCB_OUI_LEN] == DCBX_SUBTYPE2) { ++ if (dcbx->dcbx_st == DCBX_SUBTYPE2) + dcbx->manifest->dcbx2 = tlv; + agent->lldpdu |= RCVD_LLDP_DCBX2_TLV; + dcbx->rxed_tlvs = true; + return TLV_OK; +- } else if (tlv->info[DCB_OUI_LEN] == dcbx_subtype1) { +- if (dcbx->dcbx_st == dcbx_subtype1) ++ } else if (tlv->info[DCB_OUI_LEN] == DCBX_SUBTYPE1) { ++ if (dcbx->dcbx_st == DCBX_SUBTYPE1) + dcbx->manifest->dcbx1 = tlv; + agent->lldpdu |= RCVD_LLDP_DCBX1_TLV; + dcbx->rxed_tlvs = true; +@@ -783,10 +771,10 @@ int dcbx_rchange(struct port *port, struct lldp_agent *agent, struct unpacked_tl + + if (!dcbx->active && !ieee8021qaz_tlvs_rxed(dcbx->ifname) && + dcbx->rxed_tlvs && (not_present || enabled)) { +- if (dcbx->dcbx_st == dcbx_subtype2) ++ if (dcbx->dcbx_st == DCBX_SUBTYPE2) + LLDPAD_DBG("CEE DCBX %s going ACTIVE\n", + dcbx->ifname); +- else if (dcbx->dcbx_st == dcbx_subtype1) ++ else if (dcbx->dcbx_st == DCBX_SUBTYPE1) + LLDPAD_DBG("CIN DCBX %s going ACTIVE\n", + dcbx->ifname); + set_dcbx_mode(port->ifname, +diff --git a/lldp_dcbx_cfg.c b/lldp_dcbx_cfg.c +index 0dc23ea..f44c653 100644 +--- a/lldp_dcbx_cfg.c ++++ b/lldp_dcbx_cfg.c +@@ -320,7 +320,7 @@ int dcbx_default_cfg_file(void) + + tmp_setting = config_setting_add(dcbx_setting, "dcbx_version", + CONFIG_TYPE_INT); +- if (!tmp_setting || !config_setting_set_int(tmp_setting, dcbx_subtype2)) ++ if (!tmp_setting || !config_setting_set_int(tmp_setting, DCBX_SUBTYPE2)) + goto error; + + config_write_file(&lldpad_cfg, cfg_file_name); +@@ -1104,10 +1104,10 @@ int get_dcbx_version(int *result) + + if (get_int_config(dcbx_setting, "dcbx_version", TYPE_INT, result)) { + switch (*result) { +- case dcbx_subtype1: +- case dcbx_subtype2: +- case dcbx_force_subtype1: +- case dcbx_force_subtype2: ++ case DCBX_SUBTYPE1: ++ case DCBX_SUBTYPE2: ++ case DCBX_FORCE_SUBTYPE1: ++ case DCBX_FORCE_SUBTYPE2: + rval = 1; + break; + default: +diff --git a/lldp_dcbx_cmds.c b/lldp_dcbx_cmds.c +index 1ce4d4c..7fdf6c4 100644 +--- a/lldp_dcbx_cmds.c ++++ b/lldp_dcbx_cmds.c +@@ -229,7 +229,7 @@ static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, + return _set_arg_tlvtxenable(cmd, arg, argvalue, obuf, obuf_len, true); + } + +-struct arg_handlers *dcbx_get_arg_handlers() ++struct arg_handlers *dcbx_get_arg_handlers(void) + { + return &arg_handlers[0]; + } +@@ -298,10 +298,10 @@ static cmd_status set_dcbx_config(char *ibuf, int ilen) + if (ilen == DCBX_CFG_OFF + CFG_DCBX_DLEN) { + version = (*(ibuf+off+DCBX_VERSION)) ^ '0'; + switch (version) { +- case dcbx_subtype1: +- case dcbx_subtype2: +- case dcbx_force_subtype1: +- case dcbx_force_subtype2: ++ case DCBX_SUBTYPE1: ++ case DCBX_SUBTYPE2: ++ case DCBX_FORCE_SUBTYPE1: ++ case DCBX_FORCE_SUBTYPE2: + rval = save_dcbx_version(version); + break; + default: +@@ -533,7 +533,7 @@ static int handle_dcbx_cmd(u8 cmd, u8 feature, char *ibuf, int ilen, char *rbuf) + return status; + } + +-int dcbx_clif_cmd(void *data, ++int dcbx_clif_cmd(UNUSED void *data, + UNUSED struct sockaddr_un *from, + UNUSED socklen_t fromlen, + char *ibuf, int ilen, +@@ -549,10 +549,8 @@ int dcbx_clif_cmd(void *data, + pfc_attribs pfc_data; + app_attribs app_data; + llink_attribs llink_data; +- struct port *port; + struct dcbx_tlvs *dcbx; +- +- data = (struct clif_data *) data; ++ int dcb_enable; + + if (hexstr2bin(ibuf+DCB_CMD_OFF, &cmd, sizeof(cmd)) || + hexstr2bin(ibuf+DCB_FEATURE_OFF, &feature, sizeof(feature))) +@@ -586,17 +584,13 @@ int dcbx_clif_cmd(void *data, + memcpy(port_id, ibuf+DCB_PORT_OFF, plen); + port_id[plen] = '\0'; + +- /* Confirm port is a lldpad managed port */ +- port = port_find_by_name(port_id); +- if (!port) +- return cmd_device_not_found; +- +- dcbx = dcbx_data(port->ifname); +- if (!dcbx) +- return cmd_device_not_found; ++ if (get_hw_state(port_id, &dcb_enable) < 0) ++ return cmd_not_capable; + ++ dcbx = dcbx_data(port_id); + /* OPER and PEER cmd not applicable while in IEEE-DCBX modes */ +- if (dcbx->active == 0 && (cmd == CMD_GET_PEER || cmd == CMD_GET_OPER)) ++ if ((!dcbx || dcbx->active == 0) && ++ (cmd == CMD_GET_PEER || cmd == CMD_GET_OPER)) + return cmd_not_applicable; + + switch(feature) { +@@ -789,7 +783,7 @@ static cmd_status get_pg_data(pg_attribs *pg_data, int cmd, char *port_id, + for (i = 0; i < MAX_BANDWIDTH_GROUPS; i++) + sprintf(rbuf+PG_PG_PCNT(i), "%02x", pg_data->tx.pg_percent[i]); + for (i = 0; i < MAX_USER_PRIORITIES; i++) { +- if (pg_data->tx.up[i].strict_priority == dcb_link) ++ if (pg_data->tx.up[i].strict_priority == DCB_LINK) + value = LINK_STRICT_PGID; + else + value = pg_data->tx.up[i].pgid; +@@ -797,27 +791,27 @@ static cmd_status get_pg_data(pg_attribs *pg_data, int cmd, char *port_id, + } + for (i = 0; i < MAX_USER_PRIORITIES; i++) { + if ((cmd != CMD_GET_PEER) || +- (cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1)) ++ (cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1)) + sprintf(rbuf+PG_UP_PCNT(i), "%02x", + pg_data->tx.up[i].percent_of_pg_cap); +- else if (cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype2) ++ else if (cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE2) + sprintf(rbuf+PG_UP_PCNT(i), "%c%c", + CLIF_NOT_SUPPLIED, CLIF_NOT_SUPPLIED); + } + for (i = 0; i < MAX_USER_PRIORITIES; i++) { + if ((cmd != CMD_GET_PEER) || +- (cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1)) { +- if (pg_data->tx.up[i].strict_priority == dcb_link) +- value = dcb_none; ++ (cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1)) { ++ if (pg_data->tx.up[i].strict_priority == DCB_LINK) ++ value = DCB_NONE; + else + value = pg_data->tx.up[i].strict_priority; + sprintf(rbuf+PG_UP_STRICT(i), "%1x", value); +- } else if (cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype2) { ++ } else if (cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE2) { + sprintf(rbuf+PG_UP_STRICT(i), "%c", CLIF_NOT_SUPPLIED); + } + } + +- if ((cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1) || ++ if ((cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1) || + (cmd == CMD_GET_OPER)) + sprintf(rbuf+PG_UP_NUM_TC, "%c", CLIF_NOT_SUPPLIED); + else +@@ -858,7 +852,7 @@ static int get_pfc_data(pfc_attribs *pfc_data, int cmd, char *port_id, + sprintf(rbuf+PFC_UP(i), "%1x", pfc_data->admin[i]); + } + +- if ((cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1) || ++ if ((cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1) || + (cmd == CMD_GET_OPER)) + sprintf(rbuf+PFC_NUM_TC, "%c", CLIF_NOT_SUPPLIED); + else +@@ -978,7 +972,7 @@ static int set_pg_config(pg_attribs *pg_data, char *port_id, char *ibuf, + flag = *(ibuf+off+PG_UP_PGID(i)); + if (flag == CLIF_NOT_SUPPLIED) { + if (pg_data->tx.up[i].strict_priority == +- dcb_link) ++ DCB_LINK) + flag = LINK_STRICT_PGID; + else + flag = pg_data->tx.up[i].pgid; +@@ -1021,8 +1015,8 @@ static int set_pg_config(pg_attribs *pg_data, char *port_id, char *ibuf, + pg_data->tx.up[i].strict_priority |= flag; + pg_data->rx.up[i].strict_priority |= flag; + } else { +- pg_data->tx.up[i].strict_priority &= ~dcb_group; +- pg_data->rx.up[i].strict_priority &= ~dcb_group; ++ pg_data->tx.up[i].strict_priority &= ~DCB_GROUP; ++ pg_data->rx.up[i].strict_priority &= ~DCB_GROUP; + } + } + +@@ -1040,14 +1034,14 @@ static int set_pg_config(pg_attribs *pg_data, char *port_id, char *ibuf, + for (i = 0; i < MAX_USER_PRIORITIES; i++) { + if (pg_data->tx.up[i].pgid == LINK_STRICT_PGID || + (!used[pg_data->tx.up[i].pgid] && +- pg_data->tx.up[i].strict_priority & dcb_link)) { ++ pg_data->tx.up[i].strict_priority & DCB_LINK)) { + pg_data->tx.up[i].pgid = flag; + pg_data->rx.up[i].pgid = flag; +- pg_data->tx.up[i].strict_priority = dcb_link; +- pg_data->rx.up[i].strict_priority = dcb_link; ++ pg_data->tx.up[i].strict_priority = DCB_LINK; ++ pg_data->rx.up[i].strict_priority = DCB_LINK; + } else { +- pg_data->tx.up[i].strict_priority &= ~dcb_link; +- pg_data->rx.up[i].strict_priority &= ~dcb_link; ++ pg_data->tx.up[i].strict_priority &= ~DCB_LINK; ++ pg_data->rx.up[i].strict_priority &= ~DCB_LINK; + } + } + } else if (ilen != off) { +@@ -1104,9 +1098,9 @@ static int set_pfc_config(pfc_attribs *pfc_data, char *port_id, char *ibuf, + if (flag == CLIF_NOT_SUPPLIED) + continue; + if (flag) +- pfc_data->admin[i] = pfc_enabled; ++ pfc_data->admin[i] = PFC_ENABLED; + else +- pfc_data->admin[i] = pfc_disabled; ++ pfc_data->admin[i] = PFC_DISABLED; + } + } else if (ilen != off) { + /* at least needs to include the protocol settings */ +diff --git a/lldp_dcbx_nl.c b/lldp_dcbx_nl.c +index 33cf257..7a2dad2 100644 +--- a/lldp_dcbx_nl.c ++++ b/lldp_dcbx_nl.c +@@ -39,6 +39,7 @@ + #include "linux/rtnetlink.h" + #include "linux/dcbnl.h" + #include "lldp.h" ++#include "lldp_util.h" + #include "dcb_types.h" + #include "dcb_protocol.h" + #include "dcb_driver_interface.h" +@@ -641,9 +642,10 @@ int get_hw_state(char *ifname, int *dcb_state) + + int set_hw_state(char *ifname, int dcb_state) + { +- int err = 0; ++ int err; ++ int ifindex = get_ifidx(ifname); + +- err = set_linkmode(ifname, dcb_state); ++ err = set_linkmode(ifindex, ifname, dcb_state); + + if (err) + LLDPAD_DBG("ERROR %s: set_linkmode dcbstate %i\n", +@@ -751,9 +753,9 @@ int set_hw_pfc(char *ifname, dcb_pfc_list_type pfc_data, + + for (i = 0; i < MAX_TRAFFIC_CLASSES; i++) { + if (pfc_temp[i]) +- pfc[i] = pfc_enabled; ++ pfc[i] = PFC_ENABLED; + else +- pfc[i] = pfc_disabled; ++ pfc[i] = PFC_DISABLED; + } + + rval = set_pfc_cfg(ifname, &pfc[0]); +diff --git a/lldp_ecp.c b/lldp_ecp.c +deleted file mode 100644 +index 8e92253..0000000 +--- a/lldp_ecp.c ++++ /dev/null +@@ -1,1093 +0,0 @@ +-/****************************************************************************** +- +- Implementation of ECP according to 802.1Qbg +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Jens Osterkamp +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "eloop.h" +-#include "lldp.h" +-#include "lldp_evb.h" +-#include "lldp_qbg_utils.h" +-#include "lldp_vdp.h" +-#include "messages.h" +-#include "config.h" +-#include "lldp/l2_packet.h" +- +-#include "lldp_tlv.h" +- +-static void ecp_tx_run_sm(struct vdp_data *); +-static void ecp_rx_run_sm(struct vdp_data *); +- +-/* ecp_localchange_handler - triggers the processing of a local change +- * @eloop_data: data structure of event loop +- * @user_ctx: user context, vdp_data here +- * +- * no return value +- * +- * called from ecp_somethingchangedlocal when a change is pending. Calls +- * the ECP tx station state machine. A oneshot handler. This detour is taken +- * to not having to call the ecp code from the vdp state machine. Instead, we +- * return to the event loop, giving other code a chance to do work. +- */ +-static void ecp_localchange_handler(UNUSED void *eloop_data, void *user_ctx) +-{ +- struct vdp_data *vd; +- +- vd = (struct vdp_data *) user_ctx; +- if (vd->ecp.tx.localChange) { +- LLDPAD_DBG("%s:%s ecp.tx.localChange %i\n", +- __func__, vd->ecp.ifname, vd->ecp.tx.localChange); +- ecp_tx_run_sm(vd); +- } +-} +- +-/* ecp_start_localchange_timer - starts the ECP localchange timer +- * @vd: vdp_data for the interface +- * +- * returns 0 on success, -1 on error +- * +- * starts the ECP localchange timer when a localchange has been signaled from +- * the VDP state machine. +- */ +-static int ecp_start_localchange_timer(struct vdp_data *vd) +-{ +- return eloop_register_timeout(0, ECP_LOCALCHANGE_TIMEOUT, +- ecp_localchange_handler, +- NULL, (void *) vd); +-} +- +-/* ecp_stop_localchange_timer - stop the ECP localchange timer +- * @vd: vdp_data for the interface +- * +- * returns the number of removed handlers +- * +- * stops the ECP localchange timer. Used e.g. when the host interface goes down. +- */ +-static int ecp_stop_localchange_timer(struct vdp_data *vd) +-{ +- LLDPAD_DBG("%s:%s stopping ecp localchange timer\n", __func__, +- vd->ecp.ifname); +- return eloop_cancel_timeout(ecp_localchange_handler, NULL, (void *) vd); +-} +- +-/* ecp_ackTimer_expired - checks for expired ack timer +- * @vd: vdp_data for interface +- * +- * returns true or false +- * +- * returns true if ack timer has expired, false otherwise. +- */ +-static bool ecp_ackTimer_expired(struct vdp_data *vd) +-{ +- return (vd->ecp.ackTimer == 0); +-} +- +-/* ecp_ack_timeout_handler - handles the ack timer expiry +- * @eloop_data: data structure of event loop +- * @user_ctx: user context, vdp_data here +- * +- * no return value +- * +- * called when the ECP timer has expired. Calls the ECP station state machine. +- */ +-static void ecp_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) +-{ +- struct vdp_data *vd; +- +- vd = (struct vdp_data *) user_ctx; +- if (vd->ecp.ackTimer > 0) +- vd->ecp.ackTimer -= ECP_ACK_TIMER_DEFAULT; +- +- if (ecp_ackTimer_expired(vd) == true) { +- LLDPAD_DBG("%s:%s ecp_ackTimer_expired (%i)\n", +- __func__, vd->ecp.ifname, vd->ecp.ackTimer); +- ecp_tx_run_sm(vd); +- } else { +- LLDPAD_DBG("%s:%s BUG! handler called but" +- "vdp->ecp.ackTimer not expired (%i)\n", +- __func__, vd->ecp.ifname, vd->ecp.ackTimer); +- } +-} +- +-/* ecp_start_ack_timer - starts the ECP ack timer +- * @vd: vdp_data for the interface +- * +- * returns 0 on success, -1 on error +- * +- * starts the ECP ack timer when a frame has been sent out. +- */ +-static int ecp_start_ack_timer(struct vdp_data *vd) +-{ +- return eloop_register_timeout(0, ECP_ACK_TIMER_DEFAULT, +- ecp_ack_timeout_handler, +- NULL, (void *) vd); +-} +- +-/* ecp_stop_ack_timer - stop the ECP ack timer +- * @vd: vdp_data for the interface +- * +- * returns the number of removed handlers +- * +- * stops the ECP ack timer. Used e.g. when the host interface goes down. +- */ +-static int ecp_stop_ack_timer(struct vdp_data *vd) +-{ +- LLDPAD_DBG("%s:%s stopping ecp ack timer\n", __func__, vd->ecp.ifname); +- return eloop_cancel_timeout(ecp_ack_timeout_handler, NULL, (void *) vd); +-} +- +-/* ecp_tx_stop_ackTimer - stop the ECP ack timer +- * @vd: currently used port +- * +- * returns the number of removed handlers +- * +- * stops the ECP ack timer. used when a ack frame for the port has been +- * received. +- */ +-static void ecp_tx_stop_ackTimer(struct vdp_data *vd) +-{ +- vd->ecp.ackTimer = ECP_ACK_TIMER_STOPPED; +- LLDPAD_DBG("%s:%s stopped ecp ack timer\n", __func__, vd->ecp.ifname); +- ecp_stop_ack_timer(vd); +-} +- +-int ecp_deinit(char *ifname) +-{ +- struct vdp_data *vd; +- +- LLDPAD_DBG("%s:%s stopping ECP\n", __func__, ifname); +- vd = vdp_data(ifname); +- if (!vd) { +- LLDPAD_ERR("%s:%s unable to find vd\n", __func__, ifname); +- return -1; +- } +- +- ecp_stop_ack_timer(vd); +- ecp_stop_localchange_timer(vd); +- ecp_tx_stop_ackTimer(vd); +- return 0; +-} +- +-static const char *ecp_tx_states[] = { +- "ECP_TX_INIT_TRANSMIT", +- "ECP_TX_TRANSMIT_ECPDU", +- "ECP_TX_WAIT_FOR_ACK", +- "ECP_TX_REQUEST_PDU" +-}; +- +-/* ecp_somethingChangedLocal - set flag if port has changed +- * @vd: port to set the flag for +- * @mode: mode to set the flag to +- * +- * no return value +- * +- * set the localChange flag with a mode to indicate a port has changed. +- * used to signal an ecpdu needs to be sent out. +- */ +- +-void ecp_somethingChangedLocal(struct vdp_data *vd, bool flag) +-{ +- if (!vd) +- return; +- +- LLDPAD_DBG("%s:%s vd->ecp.tx.localChange to %s\n", __func__, +- vd->ecp.ifname, (flag == true) ? "true" : "false"); +- vd->ecp.tx.localChange = flag; +- ecp_start_localchange_timer(vd); +-} +- +-/* +- * Append some data at the end of the transmit data buffer. Make sure the +- * End TLV always fits into the buffer. +- */ +-static u8 end_tlv[2] = { 0x0, 0x0 }; /* END TLV */ +- +-static int ecp_append(u8 *buffer, u32 *pos, void *data, u32 len) +-{ +- if (*pos + len > ETH_FRAME_LEN - sizeof end_tlv) +- return 0; +- memcpy(buffer + *pos, data, len); +- *pos += len; +- return 1; +-} +- +-/* ecp_build_ECPDU - create an ecp protocol data unit +- * @vd: currently used port +- * +- * returns true on success, false on failure +- * +- * creates the frame header with the ports mac address, the ecp header with REQ +- * plus a list of packed TLVs created from the profiles on this +- * port. +- */ +-static bool ecp_build_ECPDU(struct vdp_data *vd) +-{ +- struct l2_ethhdr eth; +- struct ecp_hdr ecp_hdr; +- u8 own_addr[ETH_ALEN]; +- u32 fb_offset = 0; +- struct packed_tlv *ptlv = NULL; +- struct vsi_profile *p; +- int rc; +- +- /* TODO: use LLDP group MAC addresses to support +- * S-channels/multichannel +- */ +- memcpy(eth.h_dest, nearest_bridge, ETH_ALEN); +- l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr); +- memcpy(eth.h_source, &own_addr, ETH_ALEN); +- eth.h_proto = htons(ETH_P_ECP); +- memset(vd->ecp.tx.frame, 0, sizeof vd->ecp.tx.frame); +- ecp_append(vd->ecp.tx.frame, &fb_offset, (void *)ð, sizeof eth); +- +- ecp_hdr.oui[0] = 0x0; +- ecp_hdr.oui[1] = 0x1b; +- ecp_hdr.oui[2] = 0x3f; +- ecp_hdr.pad1 = 0x0; +- ecp_hdr.subtype = ECP_SUBTYPE; +- ecp_hdr.mode = ECP_REQUEST; +- +- vd->ecp.lastSequence++; +- ecp_hdr.seqnr = htons(vd->ecp.lastSequence); +- ecp_append(vd->ecp.tx.frame, &fb_offset, (void *)&ecp_hdr, +- sizeof ecp_hdr); +- +- /* create packed_tlvs for all profiles on this interface */ +- LIST_FOREACH(p, &vd->profile_head, profile) { +- +- if (!p->localChange) { +- LLDPAD_DBG("%s:%s skipping unchanged profile\n", +- __func__, vd->ecp.ifname); +- continue; +- } +- +- ptlv = vdp_gettlv(vd, p); +- +- if (!ptlv) { +- LLDPAD_DBG("%s:%s ptlv not created\n", __func__, +- vd->ecp.ifname); +- continue; +- } +- +- rc = ecp_append(vd->ecp.tx.frame, &fb_offset, ptlv->tlv, +- ptlv->size); +- ptlv = free_pkd_tlv(ptlv); +- if (rc) +- p->seqnr = vd->ecp.lastSequence; +- else +- break; +- } +- ecp_append(vd->ecp.tx.frame, &fb_offset, end_tlv, sizeof end_tlv); +- vd->ecp.tx.frame_len = MAX(fb_offset, (unsigned)ETH_ZLEN); +- return true; +-} +- +-/* ecp_tx_Initialize - initializes the ecp tx state machine +- * @vd: currently used port +- * +- * no return value +- * +- * initializes some variables for the ecp tx state machine. +- */ +-static void ecp_tx_Initialize(struct vdp_data *vd) +-{ +- memset(vd->ecp.tx.frame, 0, sizeof vd->ecp.tx.frame); +- ecp_somethingChangedLocal(vd, true); +- vd->ecp.lastSequence = ECP_SEQUENCE_NR_START; +- vd->ecp.stats.statsFramesOutTotal = 0; +- vd->ecp.ackTimer = ECP_ACK_TIMER_STOPPED; +- vd->ecp.retries = 0; +-} +- +-/* ecp_txFrame - transmit ecp frame +- * @vd: currently used port +- * +- * returns the number of characters sent on success, -1 on failure +- * +- * sends out the frame stored in the frame structure using l2_packet_send. +- */ +-static u8 ecp_txFrame(struct vdp_data *vd) +-{ +- int status = 0; +- +- status = l2_packet_send(vd->ecp.l2, (u8 *)&nearest_bridge, +- htons(ETH_P_ECP), vd->ecp.tx.frame, vd->ecp.tx.frame_len); +- vd->ecp.stats.statsFramesOutTotal++; +- vd->ecp.tx.frame_len = 0; +- return status; +-} +- +-/* ecp_tx_create_frame - create ecp frame +- * @vd: currently used port +- * +- * no return value +- */ +-static void ecp_tx_create_frame(struct vdp_data *vd) +-{ +- /* send REQs */ +- if (vd->ecp.tx.localChange) { +- int ret; +- +- LLDPAD_DBG("%s:%s sending REQs\n", __func__, vd->ecp.ifname); +- ret = ecp_build_ECPDU(vd); +- +- /* ECPDU construction succesful, send out frame */ +- if (ret == true) { +- hexdump_frame(vd->ecp.ifname, "frame-out", +- vd->ecp.tx.frame, vd->ecp.tx.frame_len); +- ecp_txFrame(vd); +- } +- } +- +- ecp_somethingChangedLocal(vd, false); +-} +- +-/* ecp_tx_start_ackTimer - starts the ECP ack timer +- * @vd: vdp_data to process +- * +- * returns 0 on success, -1 on error +- * +- * starts the ack timer when a frame has been sent out. +- */ +-static void ecp_tx_start_ackTimer(struct vdp_data *vd) +-{ +- vd->ecp.ackTimer = ECP_ACK_TIMER_DEFAULT; +- LLDPAD_DBG("%s-%s: starting ecp ack timer\n", __func__, vd->ifname); +- ecp_start_ack_timer(vd); +-} +- +-/* ecp_tx_change_state - changes the ecp tx sm state +- * @vd: currently used port +- * @newstate: new state for the sm +- * +- * no return value +- * +- * checks state transistion for consistency and finally changes the state of +- * the profile. +- */ +-static void ecp_tx_change_state(struct vdp_data *vd, u8 newstate) +-{ +- switch(newstate) { +- case ECP_TX_INIT_TRANSMIT: +- break; +- case ECP_TX_TRANSMIT_ECPDU: +- assert((vd->ecp.tx.state == ECP_TX_INIT_TRANSMIT) || +- (vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK) || +- (vd->ecp.tx.state == ECP_TX_REQUEST_PDU)); +- break; +- case ECP_TX_WAIT_FOR_ACK: +- assert(vd->ecp.tx.state == ECP_TX_TRANSMIT_ECPDU); +- break; +- case ECP_TX_REQUEST_PDU: +- assert(vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK); +- break; +- default: +- LLDPAD_ERR("%s: LLDP TX state machine invalid state %d\n", +- vd->ifname, newstate); +- } +- LLDPAD_DBG("%s-%s: state change %s -> %s\n", __func__, +- vd->ifname, ecp_tx_states[vd->ecp.tx.state], +- ecp_tx_states[newstate]); +- vd->ecp.tx.state = newstate; +- return; +-} +- +-/* ecp_set_tx_state - sets the ecp tx sm state +- * @vd: currently used port +- * +- * returns true or false +- * +- * switches the state machine to the next state depending on the input +- * variables. returns true or false depending on wether the state machine +- * can be run again with the new state or can stop at the current state. +- */ +-static bool ecp_set_tx_state(struct vdp_data *vd) +-{ +- struct port *port = port_find_by_name(vd->ifname); +- +- if (!port) { +- LLDPAD_ERR("%s: port not found\n", __func__); +- return 0; +- } +- +- if ((port->portEnabled == false) && (port->prevPortEnabled == true)) { +- LLDPAD_ERR("set_tx_state: port was disabled\n"); +- ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT); +- } +- port->prevPortEnabled = port->portEnabled; +- +- switch (vd->ecp.tx.state) { +- case ECP_TX_INIT_TRANSMIT: +- if (port->portEnabled && (vd->enabletx == true) +- && vd->ecp.tx.localChange) { +- ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); +- return true; +- } +- return false; +- case ECP_TX_TRANSMIT_ECPDU: +- if (vd->enabletx == false) { +- ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT); +- return true; +- } +- ecp_tx_change_state(vd, ECP_TX_WAIT_FOR_ACK); +- return false; +- case ECP_TX_WAIT_FOR_ACK: +- if (ecp_ackTimer_expired(vd)) { +- vd->ecp.retries++; +- if (vd->ecp.retries < ECP_MAX_RETRIES) { +- ecp_somethingChangedLocal(vd, true); +- ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); +- return true; +- } +- if (vd->ecp.retries == ECP_MAX_RETRIES) { +- LLDPAD_DBG("%s-%s: retries expired\n", +- __func__, vd->ifname); +- ecp_tx_stop_ackTimer(vd); +- ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU); +- return true; +- } +- } +- if (vd->ecp.ackReceived && +- vd->ecp.seqECPDU == vd->ecp.lastSequence) { +- vd->ecp.ackReceived = false; +- if (vdp_vsis_pending(vd)) { +- LLDPAD_DBG("%s-%s: still work pending\n", +- __func__, vd->ifname); +- ecp_somethingChangedLocal(vd, true); +- } +- ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU); +- return true; +- } +- return false; +- case ECP_TX_REQUEST_PDU: +- if (vd->ecp.tx.localChange) { +- ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); +- return true; +- } +- return false; +- default: +- LLDPAD_ERR("%s: LLDP TX state machine in invalid state %d\n", +- vd->ifname, vd->ecp.tx.state); +- return false; +- } +-} +- +-/* ecp_tx_run_sm - state machine for ecp tx +- * @vd: currently used vdp_data +- * +- * no return value +- * +- * runs the state machine for ecp tx. +- */ +-void ecp_tx_run_sm(struct vdp_data *vd) +-{ +- do { +- LLDPAD_DBG("%s-%s: ecp_tx - %s\n", __func__, +- vd->ifname, ecp_tx_states[vd->ecp.tx.state]); +- +- switch(vd->ecp.tx.state) { +- case ECP_TX_INIT_TRANSMIT: +- ecp_tx_Initialize(vd); +- break; +- case ECP_TX_TRANSMIT_ECPDU: +- ecp_tx_create_frame(vd); +- ecp_tx_start_ackTimer(vd); +- ecp_somethingChangedLocal(vd, false); +- break; +- case ECP_TX_WAIT_FOR_ACK: +- if (vd->ecp.ackReceived) { +- LLDPAD_DBG("%s-%s: ECP_TX_WAIT_FOR_ACK " +- "ackReceived seqECPDU %#x " +- "lastSequence %#x\n", __func__, +- vd->ifname, vd->ecp.seqECPDU, +- vd->ecp.lastSequence); +- ecp_somethingChangedLocal(vd, false); +- ecp_tx_stop_ackTimer(vd); +- } +- break; +- case ECP_TX_REQUEST_PDU: +- vd->ecp.retries = 0; +- LLDPAD_DBG("%s-%s: ECP_TX_REQUEST_PDU lastSeq %#x\n", +- __func__, vd->ifname, vd->ecp.lastSequence); +- break; +- default: +- LLDPAD_ERR("%s: LLDP TX state machine in invalid state %d\n", +- vd->ifname, vd->ecp.tx.state); +- } +- } while (ecp_set_tx_state(vd) == true); +-} +- +-static const char *ecp_rx_states[] = { +- "ECP_RX_IDLE", +- "ECP_RX_INIT_RECEIVE", +- "ECP_RX_RECEIVE_WAIT", +- "ECP_RX_RECEIVE_ECPDU", +- "ECP_RX_SEND_ACK", +- "ECP_RX_RESEND_ACK", +-}; +- +-/* ecp_rx_Initialize - initializes the ecp rx state machine +- * @vd: vd for the state machine +- * +- * no return value +- * +- * initialize some variables, get rid of old frame if necessary +- */ +-static void ecp_rx_Initialize(struct vdp_data *vd) +-{ +- vd->ecp.rx.rcvFrame = false; +- vd->ecp.ackReceived = false; +- vd->ecp.rx.frame_len = 0; +-} +- +-/* ecp_rx_SendAckFrame - send ack frame +- * @vd: port used by ecp +- * +- * currently always returns 0 +- * +- * copies current received frame over to frame out, fills in address of this +- * port and set mode field to ACK. used by ecp_rx_send_ack_frame. +- */ +-static int ecp_rx_SendAckFrame(struct vdp_data *vd) +-{ +- u16 tlv_offset = 0; +- struct ecp_hdr *ecp_hdr; +- struct l2_ethhdr *hdr; +- u8 own_addr[ETH_ALEN]; +- +- LLDPAD_DBG("%s:%s acking frame\n", __func__, vd->ecp.ifname); +- /* copy over to transmit buffer */ +- memcpy(vd->ecp.tx.frame, vd->ecp.rx.frame, vd->ecp.rx.frame_len); +- vd->ecp.tx.frame_len = vd->ecp.rx.frame_len; +- +- /* use my own addr to send ACK */ +- hdr = (struct l2_ethhdr *)vd->ecp.tx.frame; +- l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr); +- memcpy(hdr->h_source, &own_addr, ETH_ALEN); +- +- tlv_offset = sizeof(struct l2_ethhdr); +- ecp_hdr = (struct ecp_hdr *)&vd->ecp.tx.frame[tlv_offset]; +- ecp_hdr->mode = ECP_ACK; +- +- tlv_offset = sizeof(struct l2_ethhdr) + sizeof(struct ecp_hdr); +- LLDPAD_DBG("%s:%s zeroing out rest of ack frame from %i to %i\n", +- __func__, vd->ecp.ifname, tlv_offset, vd->ecp.rx.frame_len); +- memset(&vd->ecp.tx.frame[tlv_offset], 0, +- vd->ecp.rx.frame_len - tlv_offset); +- return 0; +-} +- +-/* ecp_rx_send_ack_frame - send out ack frame for received frame +- * @vd: vd for the state machine +- * +- * no return value +- * +- * creates an ack frame for a just received frame, prints the about to be +- * sent frame and finally transmits it. +- */ +-void ecp_rx_send_ack_frame(struct vdp_data *vd) +-{ +- ecp_rx_SendAckFrame(vd); +- hexdump_frame(vd->ecp.ifname, "frame-ack", vd->ecp.tx.frame, +- vd->ecp.tx.frame_len); +- ecp_txFrame(vd); +-} +- +-/* ecp_rx_ReceiveFrame - receive ecp frame +- * @ctx: rx callback context, struct vd * in this case +- * @ifindex: index of interface +- * @buf: buffer which contains the frame just received +- * @len: size of buffer (frame) +- * +- * no return value +- * +- * creates a local copy of the buffer and checks the header. keeps some +- * statistics about ecp frames. Checks if it is a request or an ack frame +- * and branches to ecp rx or ecp tx state machine. +- */ +-static void ecp_rx_ReceiveFrame(void *ctx, UNUSED int ifindex, const u8 *buf, +- size_t len) +-{ +- struct vdp_data *vd; +- struct port *port; +- u8 frame_error = 0; +- u16 tlv_offset; +- struct l2_ethhdr *hdr; +- struct l2_ethhdr example_hdr,*ex; +- struct ecp_hdr *ecp_hdr; +- +- if (!ctx) { +- LLDPAD_WARN("%s: no ctx - can't process frame\n", __func__); +- return; +- } +- +- vd = (struct vdp_data *)ctx; +- port = port_find_by_name(vd->ifname); +- if (port == NULL) +- return; +- +- LLDPAD_DBG("%s:%s received packet with size %i\n", __func__, +- vd->ecp.ifname, (int)len); +- if (vd->enabletx == false) +- return; +- +- if (vd->ecp.rx.frame_len == len && +- (memcmp(buf, vd->ecp.rx.frame, len) == 0)) { +- vd->ecp.stats.statsFramesInTotal++; +- return; +- } +- +- memset(vd->ecp.rx.frame, 0, len); +- memcpy(vd->ecp.rx.frame, buf, len); +- +- vd->ecp.rx.frame_len = (u16)len; +- ex = &example_hdr; +- memcpy(ex->h_dest, nearest_bridge, ETH_ALEN); +- ex->h_proto = htons(ETH_P_ECP); +- hdr = (struct l2_ethhdr *)vd->ecp.rx.frame; +- +- if ((memcmp(hdr->h_dest, ex->h_dest, ETH_ALEN) != 0)) { +- LLDPAD_ERR("%s:%s ERROR multicast address error in incoming frame." +- " Dropping frame.\n", __func__, vd->ecp.ifname); +- frame_error++; +- return; +- } +- +- if (hdr->h_proto != example_hdr.h_proto) { +- LLDPAD_ERR("%s:%s ERROR ethertype %#x not ECP ethertype", +- __func__, vd->ecp.ifname, htons(hdr->h_proto)); +- frame_error++; +- return; +- } +- +- if (!frame_error) { +- vd->ecp.stats.statsFramesInTotal++; +- vd->ecp.rx.rcvFrame = true; +- } +- +- tlv_offset = sizeof(struct l2_ethhdr); +- ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; +- vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr); +- hexdump_frame(vd->ecp.ifname, "frame-in", vd->ecp.rx.frame, +- vd->ecp.rx.frame_len); +- +- switch(ecp_hdr->mode) { +- case ECP_REQUEST: +- LLDPAD_DBG("%s:%s received REQ frame\n", __func__, +- vd->ecp.ifname); +- vd->ecp.ackReceived = false; +- ecp_rx_run_sm(vd); +- break; +- case ECP_ACK: +- LLDPAD_DBG("%s:%s received ACK frame\n", __func__, +- vd->ecp.ifname); +- vd->ecp.ackReceived = true; +- vdp_ack_profiles(vd, vd->ecp.seqECPDU); +- ecp_tx_run_sm(vd); +- vd->ecp.ackReceived = false; +- break; +- default: +- LLDPAD_ERR("%s:%s ERROR: unknown mode %i\n", __func__, +- vd->ecp.ifname, ecp_hdr->mode); +- return; +- } +- +-} +- +-/* ecp_rx_change_state - changes the ecp rx sm state +- * @vd: currently used port +- * @newstate: new state for the sm +- * +- * no return value +- * +- * checks state transistion for consistency and finally changes the state of +- * the profile. +- */ +-static void ecp_rx_change_state(struct vdp_data *vd, u8 newstate) +-{ +- switch(newstate) { +- case ECP_RX_IDLE: +- break; +- case ECP_RX_INIT_RECEIVE: +- break; +- case ECP_RX_RECEIVE_WAIT: +- assert((vd->ecp.rx.state == ECP_RX_INIT_RECEIVE) || +- (vd->ecp.rx.state == ECP_RX_IDLE) || +- (vd->ecp.rx.state == ECP_RX_SEND_ACK) || +- (vd->ecp.rx.state == ECP_RX_RESEND_ACK)); +- break; +- case ECP_RX_RECEIVE_ECPDU: +- assert(vd->ecp.rx.state == ECP_RX_RECEIVE_WAIT); +- break; +- case ECP_RX_SEND_ACK: +- assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU); +- break; +- case ECP_RX_RESEND_ACK: +- assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU); +- break; +- default: +- LLDPAD_ERR("%s:%s LLDP RX state machine invalid state %d\n", +- __func__, vd->ecp.ifname, newstate); +- } +- +- LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, +- vd->ecp.ifname, ecp_rx_states[vd->ecp.rx.state], +- ecp_rx_states[newstate]); +- +- vd->ecp.rx.state = newstate; +-} +- +-/* ecp_init - initialize ecp module +- * @ifname: interface for which the module is initialized +- * +- * returns 0 on success, -1 on error +- * +- * finds the port to the interface name, sets up the receive handle for +- * incoming ecp frames and initializes the ecp rx and tx state machines. +- * should usually be called when a successful exchange of EVB TLVs has been +- * made and ECP and VDP protocols are supported by both sides. +- */ +-int ecp_init(char *ifname) +-{ +- struct vdp_data *vd; +- +- LLDPAD_DBG("%s:%s starting ECP\n", __func__, ifname); +- vd = vdp_data(ifname); +- if (!vd) { +- LLDPAD_ERR("%s:%s unable to find vd\n", __func__, ifname); +- return -1; +- } +- +- if (!vd->ecp.l2) +- vd->ecp.l2 = l2_packet_init(vd->ifname, NULL, ETH_P_ECP, +- ecp_rx_ReceiveFrame, vd, 1); +- +- if (!vd->ecp.l2) { +- LLDPAD_ERR("%s:%s failed to access layer 2 access ETH_P_ECP\n", +- __func__, ifname); +- return -1; +- } +- strncpy(vd->ecp.ifname, ifname, sizeof vd->ecp.ifname); +- ecp_rx_change_state(vd, ECP_RX_IDLE); +- ecp_rx_run_sm(vd); +- ecp_somethingChangedLocal(vd, true); +- return 0; +-} +- +-/* ecp_rx_validate_frame - validates received frame +- * @vd: vdp_data used by ecp +- * +- * no return value +- * +- * checks wether received frame has correct subtype and mode +- */ +- +-static void ecp_rx_validate_frame(struct vdp_data *vd) +-{ +- u16 tlv_offset = 0; +- struct ecp_hdr *ecp_hdr; +- +- LLDPAD_DBG("%s:%s validating frame\n", __func__, vd->ecp.ifname); +- tlv_offset = sizeof(struct l2_ethhdr); +- ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; +- LLDPAD_DBG("%s:%s ecp packet with subtype %#x mode %#x seq %#04x\n", +- __func__, vd->ecp.ifname, ecp_hdr->subtype, ecp_hdr->mode, +- ntohs(ecp_hdr->seqnr)); +- +- if (ecp_hdr->subtype != ECP_SUBTYPE) { +- LLDPAD_ERR("%s:%s ERROR: unknown subtype\n", __func__, +- vd->ecp.ifname); +- return; +- } +- +- if ((ecp_hdr->oui[0] != 0x0) || (ecp_hdr->oui[1] != 0x1b) || +- (ecp_hdr->oui[2] != 0x3f)) { +- LLDPAD_ERR("%s:%s ERROR: incorrect OUI 0x%02x%02x%02x\n", +- __func__, vd->ecp.ifname, ecp_hdr->oui[0], +- ecp_hdr->oui[1], ecp_hdr->oui[2]); +- return; +- } +- +- switch(ecp_hdr->mode) { +- case ECP_REQUEST: +- break; +- case ECP_ACK: +- break; +- default: +- LLDPAD_ERR("%s:%s ERROR: unknown mode %i\n", __func__, +- vd->ecp.ifname, ecp_hdr->mode); +- return; +- } +- +- /* FIXME: also done in ecp_rx_ReceiveFrame, +- * are both necessary ? */ +- vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr); +-} +- +-/* ecp_rx_ProcessFrame - process received ecp frames +- * @vd: currently used port +- * +- * no return value +- * +- * walks through the packed vsi tlvs in an ecp frame, extracts them +- * and passes them to the VDP ULP with vdp_indicate. +- */ +-static void ecp_rx_ProcessFrame(struct vdp_data *vd) +-{ +- u16 tlv_cnt = 0; +- u8 tlv_type = 0; +- u16 tlv_length = 0; +- u16 tlv_offset = 0; +- u16 *tlv_head_ptr = NULL; +- u8 frame_error = 0; +- bool tlv_stored = false; +- struct ecp_hdr *ecp_hdr; +- int vdp_called; +- +- LLDPAD_DBG("%s:%s processing frame\n", __func__, vd->ecp.ifname); +- tlv_offset = sizeof(struct l2_ethhdr); +- +- ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; +- LLDPAD_DBG("%s:%s ecp packet with subtype %#x mode %#x seq %#04x\n", +- __func__, vd->ifname, ecp_hdr->subtype, +- ecp_hdr->mode, ntohs(ecp_hdr->seqnr)); +- if (ecp_hdr->mode == ECP_ACK) +- return; +- +- /* processing of VSI_TLVs starts here */ +- tlv_offset += sizeof(struct ecp_hdr); +- vdp_called = 0; +- do { +- tlv_cnt++; +- +- if (tlv_offset > vd->ecp.rx.frame_len) { +- LLDPAD_ERR("%s:%s ERROR: Frame overrun! tlv_offset %i" +- " frame_len %i cnt %i\n", __func__, +- vd->ecp.ifname, tlv_offset, +- vd->ecp.rx.frame_len, tlv_cnt); +- frame_error++; +- goto out; +- } +- +- if (tlv_offset + 2 > vd->ecp.rx.frame_len) { +- LLDPAD_DBG("%s:%s tlv EOF problem size=%d offset=%d\n", +- __func__, vd->ecp.ifname, +- vd->ecp.rx.frame_len, tlv_offset); +- frame_error++; +- goto out; +- } +- +- tlv_head_ptr = (u16 *)&vd->ecp.rx.frame[tlv_offset]; +- tlv_length = htons(*tlv_head_ptr) & 0x01FF; +- tlv_type = (u8)(htons(*tlv_head_ptr) >> 9); +- +- u16 tmp_offset = tlv_offset + tlv_length; +- if (tmp_offset > vd->ecp.rx.frame_len) { +- LLDPAD_ERR("%s:%s ERROR: Frame overflow: offset=%d " +- "rx.size=%d\n", __func__, vd->ecp.ifname, +- tmp_offset, vd->ecp.rx.frame_len); +- frame_error++; +- goto out; +- } +- +- u8 *info = (u8 *)&vd->ecp.rx.frame[tlv_offset + +- sizeof(*tlv_head_ptr)]; +- +- struct unpacked_tlv *tlv = create_tlv(); +- +- if (!tlv) { +- LLDPAD_DBG("%s:%s failed malloc for incoming TLV\n", +- __func__, vd->ecp.ifname); +- goto out; +- } +- +- if ((tlv_length == 0) && (tlv->type != TYPE_0)) { +- LLDPAD_DBG("%s:%s tlv_length == 0\n", __func__, +- vd->ecp.ifname); +- free_unpkd_tlv(tlv); +- goto out; +- } +- +- tlv->type = tlv_type; +- tlv->length = tlv_length; +- tlv->info = (u8 *)malloc(tlv_length); +- if (tlv->info) { +- memset(tlv->info,0, tlv_length); +- memcpy(tlv->info, info, tlv_length); +- } else { +- LLDPAD_DBG("%s:%s failed malloc for incoming TLV info\n", +- __func__, vd->ecp.ifname); +- free_unpkd_tlv(tlv); +- goto out; +- } +- +- /* Validate the TLV */ +- tlv_offset += sizeof(*tlv_head_ptr) + tlv_length; +- +- if (tlv->type == TYPE_127) { /* private TLV */ +- /* give VSI TLV to VDP */ +- if (!vdp_indicate(vd, tlv)) { +- tlv_stored = true; +- ++vdp_called; +- } else { +- /* TODO +- * put it in a list and try again later until +- * timer and retries have expired +- */ +- tlv_stored = false; +- } +- } +- +- if ((tlv->type != TYPE_0) && !tlv_stored) { +- LLDPAD_DBG("%s:%s TLV (%u) was not stored (%p)\n", +- __func__, vd->ecp.ifname, tlv->type, tlv); +- tlv = free_unpkd_tlv(tlv); +- vd->ecp.stats.statsTLVsUnrecognizedTotal++; +- } +- tlv = NULL; +- tlv_stored = false; +- } while (tlv_offset < vd->ecp.rx.frame_len); +-out: +- if (frame_error) { +- vd->ecp.stats.statsFramesDiscardedTotal++; +- vd->ecp.stats.statsFramesInErrorsTotal++; +- } +- if (vdp_called) +- vdp_advance_sm(vd); +-} +- +-/* ecp_set_rx_state - sets the ecp rx sm state +- * @vd: currently used port +- * +- * returns true or false +- * +- * switches the state machine to the next state depending on the input +- * variables. returns true or false depending on wether the state machine +- * can be run again with the new state or can stop at the current state. +- */ +-static bool ecp_set_rx_state(struct vdp_data *vd) +-{ +- struct port *port = port_find_by_name(vd->ifname); +- +- if (!port) +- return false; +- +- if (port->portEnabled == false) +- ecp_rx_change_state(vd, ECP_RX_IDLE); +- +- switch(vd->ecp.rx.state) { +- case ECP_RX_IDLE: +- if (port->portEnabled == true) { +- ecp_rx_change_state(vd, ECP_RX_INIT_RECEIVE); +- return true; +- } +- return false; +- case ECP_RX_INIT_RECEIVE: +- if (vd->enabletx == true) { +- ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT); +- return true; +- } +- return false; +- case ECP_RX_RECEIVE_WAIT: +- if (vd->enabletx == false) { +- ecp_rx_change_state(vd, ECP_RX_IDLE); +- return true; +- } +- if (vd->ecp.rx.rcvFrame == true) { +- ecp_rx_change_state(vd, ECP_RX_RECEIVE_ECPDU); +- return true; +- } +- return false; +- case ECP_RX_RECEIVE_ECPDU: +- if (vd->ecp.seqECPDU == vd->ecp.lastSequence) { +- LLDPAD_DBG("%s:%s seqECPDU %x, lastSequence %x\n", +- __func__, vd->ecp.ifname, vd->ecp.seqECPDU, +- vd->ecp.lastSequence); +- ecp_rx_change_state(vd, ECP_RX_RESEND_ACK); +- return true; +- } +- if (vd->ecp.seqECPDU != vd->ecp.lastSequence) { +- ecp_rx_change_state(vd, ECP_RX_RESEND_ACK); +- return true; +- } +- return false; +- case ECP_RX_SEND_ACK: +- case ECP_RX_RESEND_ACK: +- ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT); +- return false; +- default: +- LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", +- __func__, vd->ecp.ifname, vd->ecp.rx.state); +- return false; +- } +-} +- +-/* ecp_rx_run_sm - state machine for ecp rx +- * @vd: currently used port +- * +- * no return value +- * +- * runs the state machine for ecp rx. +- */ +-static void ecp_rx_run_sm(struct vdp_data *vd) +-{ +- ecp_set_rx_state(vd); +- do { +- LLDPAD_DBG("%s:%s ecp_rx - %s\n", __func__, vd->ecp.ifname, +- ecp_rx_states[vd->ecp.tx.state]); +- +- switch(vd->ecp.rx.state) { +- case ECP_RX_IDLE: +- break; +- case ECP_RX_INIT_RECEIVE: +- ecp_rx_Initialize(vd); +- break; +- case ECP_RX_RECEIVE_WAIT: +- break; +- case ECP_RX_RECEIVE_ECPDU: +- vd->ecp.rx.rcvFrame = false; +- ecp_rx_validate_frame(vd); +- break; +- case ECP_RX_SEND_ACK: +- ecp_rx_ProcessFrame(vd); +- break; +- case ECP_RX_RESEND_ACK: +- ecp_rx_ProcessFrame(vd); +- if (!vd->ecp.ackReceived) { +- ecp_rx_send_ack_frame(vd); +- } +- break; +- default: +- LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", +- __func__, vd->ecp.ifname, vd->ecp.rx.state); +- } +- } while (ecp_set_rx_state(vd) == true); +-} +diff --git a/lldp_evb.c b/lldp_evb.c +index c5c52bb..4b3752e 100644 +--- a/lldp_evb.c ++++ b/lldp_evb.c +@@ -32,7 +32,7 @@ + #include "lldp_tlv.h" + #include "lldp_evb.h" + #include "lldp_evb_cmds.h" +-#include "lldp_vdp.h" ++#include "qbg_vdp.h" + #include "messages.h" + #include "config.h" + +diff --git a/lldp_evb22.c b/lldp_evb22.c +new file mode 100644 +index 0000000..85c6abc +--- /dev/null ++++ b/lldp_evb22.c +@@ -0,0 +1,565 @@ ++/****************************************************************************** ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2012 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++#define _GNU_SOURCE ++#include ++#include ++ ++#include "lldp.h" ++#include "lldp_tlv.h" ++#include "lldp_evb22.h" ++#include "qbg_ecp22.h" ++#include "qbg_vdp22.h" ++#include "qbg_utils.h" ++#include "lldp_evb_cmds.h" ++#include "messages.h" ++#include "config.h" ++ ++extern struct lldp_head lldp_head; ++ ++struct evb22_data *evb22_data(char *ifname, enum agent_type type) ++{ ++ struct evb22_user_data *ud; ++ struct evb22_data *ed = NULL; ++ ++ ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_EVB22); ++ if (ud) { ++ LIST_FOREACH(ed, &ud->head, entry) { ++ if (!strncmp(ifname, ed->ifname, IFNAMSIZ) && ++ (type == ed->agenttype)) ++ break; ++ } ++ } ++ return ed; ++} ++ ++static void evb22_format_tlv(char *buf, size_t len, struct evb22_tlv *tlv) ++{ ++ int comma = 0; ++ char bridge_txt[32], station_txt[32]; ++ ++ memset(bridge_txt, 0, sizeof bridge_txt); ++ if (evb_ex_bgid(tlv->bridge_s)) { ++ strcat(bridge_txt, "bgid"); ++ comma = 1; ++ } ++ if (evb_ex_rrcap(tlv->bridge_s)) { ++ if (comma) ++ strcat(bridge_txt, ","); ++ strcat(bridge_txt, "rrcap"); ++ comma = 1; ++ } ++ if (evb_ex_rrctr(tlv->bridge_s)) { ++ if (comma) ++ strcat(bridge_txt, ","); ++ strcat(bridge_txt, "rrctr"); ++ } ++ ++ comma = 0; ++ memset(station_txt, 0, sizeof station_txt); ++ if (evb_ex_sgid(tlv->station_s)) { ++ strcat(station_txt, "sgid"); ++ comma = 1; ++ } ++ if (evb_ex_rrreq(tlv->station_s)) { ++ if (comma) ++ strcat(station_txt, ","); ++ strcat(station_txt, "rrreq"); ++ comma = 1; ++ } ++ if (evb_ex_rrstat(tlv->station_s)) { ++ if (comma) ++ strcat(station_txt, ","); ++ strcat(station_txt, "rrstat"); ++ } ++ snprintf(buf, len, "bridge:%s(%#02x) station:%s(%#02x) " ++ "retries:%d rte:%d mode:%d r/l:%d rwd:%d " ++ "r/l:%d rka:%d", bridge_txt, tlv->bridge_s, ++ station_txt, tlv->station_s, ++ evb_ex_retries(tlv->r_rte), evb_ex_rte(tlv->r_rte), ++ evb_ex_evbmode(tlv->evb_mode), evb_ex_rol(tlv->evb_mode), ++ evb_ex_rwd(tlv->evb_mode), ++ evb_ex_rol(tlv->rl_rka), evb_ex_rka(tlv->rl_rka)); ++} ++ ++static void evb22_print_tlvinfo(char *ifname, struct evb22_tlv *tlv) ++{ ++ char buf[256]; ++ ++ evb22_format_tlv(buf, sizeof buf, tlv); ++ LLDPAD_DBG("%s evb %s\n", ifname, buf); ++} ++ ++static void evb22_dump_tlv(char *ifname, struct unpacked_tlv *tlv) ++{ ++ int i, left = 0; ++ char buffer[256]; ++ ++ for (i = 0; i < tlv->length; i++) { ++ int c; ++ ++ c = snprintf(buffer + left, ++ sizeof buffer - left, ++ "%02x ", tlv->info[i]); ++ ++ if (c < 0 || (c >= (int)sizeof buffer - left)) ++ break; ++ else ++ left += c; ++ } ++ ++ LLDPAD_DBG("%s:%s type %i length %i info %s\n", ++ __func__, ifname, tlv->type, tlv->length, buffer); ++} ++ ++static void common_tlv(struct evb22_data *ed) ++{ ++ struct evb22_tlv *recv = &ed->last; ++ struct evb22_tlv *mine = &ed->policy; ++ u8 val; ++ ++ /* Set retries and rte value */ ++ val = evb_ex_retries(recv->r_rte); ++ if (evb_ex_retries(mine->r_rte) > val) ++ val = evb_ex_retries(mine->r_rte); ++ ed->out.r_rte = evb_set_retries(val); ++ val = evb_ex_rte(recv->r_rte); ++ if (evb_ex_rte(mine->r_rte) > val) ++ val = evb_ex_rte(mine->r_rte); ++ ed->out.r_rte |= evb_set_rte(val); ++ ++ /* Set evbmode */ ++ ed->out.evb_mode = evb_set_evbmode(evb_ex_evbmode(mine->evb_mode)); ++ val = evb_ex_rwd(recv->evb_mode); ++ if (evb_ex_rwd(mine->evb_mode) > val) ++ val = evb_ex_rwd(mine->evb_mode); ++ else ++ ed->out.evb_mode |= evb_set_rol(1); ++ ed->out.evb_mode |= evb_set_rwd(val); ++ ++ /* Set rka */ ++ ed->out.rl_rka = 0; ++ val = evb_ex_rka(recv->rl_rka); ++ if (evb_ex_rka(mine->rl_rka) > val) ++ val = evb_ex_rka(mine->rl_rka); ++ else ++ ed->out.rl_rka = evb_set_rol(1); ++ ed->out.rl_rka |= evb_set_rka(val); ++} ++ ++/* ++ * Fill the EVB DU for LLDP transmition. Sender is bridge. ++ */ ++static void bridge_tlv(struct evb22_data *ed) ++{ ++ struct evb22_tlv *recv = &ed->last; ++ struct evb22_tlv *mine = &ed->policy; ++ ++ /* Copy my last station status */ ++ ed->out.station_s = recv->station_s; ++ ++ /* Set bridge status */ ++ ed->out.bridge_s = mine->bridge_s; ++ if (evb_ex_rrreq(recv->station_s) && evb_ex_rrcap(mine->bridge_s)) ++ ed->out.bridge_s |= evb_set_rrctr(1); ++ common_tlv(ed); ++} ++ ++/* ++ * Fill the EVB DU for LLDP transmition. Sender is station. ++ */ ++static void station_tlv(struct evb22_data *ed) ++{ ++ struct evb22_tlv *recv = &ed->last; ++ struct evb22_tlv *mine = &ed->policy; ++ u8 val; ++ ++ /* Copy my last bridge status */ ++ ed->out.bridge_s = recv->bridge_s; ++ ++ /* ++ * Set station status, 2nd byte of OUI is 0x80. If 0x00 ++ * nothing received from bridge. ++ */ ++ if (recv->oui[1] == 0) ++ val = EVB_RRSTAT_DONT; ++ else if (evb_ex_rrctr(recv->bridge_s)) ++ val = EVB_RRSTAT_YES; ++ else ++ val = EVB_RRSTAT_NO; ++ ed->out.station_s = evb_maskoff_rrstat(mine->station_s) ++ | evb_set_rrstat(val); ++ common_tlv(ed); ++} ++ ++/* ++ * Checks values received in TLV and takes over some values. ++ * Sets the new suggestion in member tie to be send out to switch. ++ * ++ * Also notify depending modules about the new values. ++ */ ++static void evb22_update_tlv(struct evb22_data *ed) ++{ ++ struct qbg22_imm qbg; ++ ++ if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) ++ station_tlv(ed); ++ else ++ bridge_tlv(ed); ++ ++ qbg.data_type = EVB22_TO_ECP22; ++ qbg.u.a.max_rte = evb_ex_rte(ed->out.r_rte); ++ qbg.u.a.max_retry = evb_ex_retries(ed->out.r_rte); ++ modules_notify(LLDP_MOD_ECP22, LLDP_MOD_EVB22, ed->ifname, &qbg); ++ ++ qbg.data_type = EVB22_TO_VDP22; ++ qbg.u.b.max_rka = evb_ex_rka(ed->out.rl_rka); ++ qbg.u.b.max_rwd = evb_ex_rwd(ed->out.evb_mode); ++ qbg.u.b.max_rte = evb_ex_rte(ed->out.r_rte); ++ qbg.u.b.max_retry = evb_ex_retries(ed->out.r_rte); ++ /* Support group identifiers when advertised by both sides */ ++ qbg.u.b.gpid = evb_ex_bgid(ed->out.bridge_s) ++ && evb_ex_sgid(ed->out.station_s); ++ qbg.u.b.evbon = ed->txmit; ++ modules_notify(LLDP_MOD_VDP22, LLDP_MOD_EVB22, ed->ifname, &qbg); ++} ++ ++/* ++ * Build the packed EVB TLV. ++ * Returns a pointer to the packed tlv or 0 on failure. ++ */ ++static struct packed_tlv *evb22_build_tlv(struct evb22_data *ed) ++{ ++ struct packed_tlv *ptlv = 0; ++ u8 infobuf[sizeof(struct evb22_tlv)]; ++ struct unpacked_tlv tlv = { ++ .type = ORG_SPECIFIC_TLV, ++ .length = sizeof(struct evb22_tlv), ++ .info = infobuf ++ }; ++ ++ evb22_update_tlv(ed); ++ memcpy(tlv.info, &ed->out, tlv.length); ++ ptlv = pack_tlv(&tlv); ++ if (ptlv) { ++ LLDPAD_DBG("%s:%s TLV about to be sent out:\n", __func__, ++ ed->ifname); ++ evb22_dump_tlv(ed->ifname, &tlv); ++ } else ++ LLDPAD_DBG("%s:%s failed to pack EVB TLV\n", __func__, ++ ed->ifname); ++ return ptlv; ++} ++ ++/* ++ * Function call to build and return module specific packed EVB TLV. ++ * Returned packed_tlv is free'ed by caller of this function. ++ */ ++static struct packed_tlv *evb22_gettlv(struct port *port, ++ struct lldp_agent *agent) ++{ ++ struct evb22_data *ed; ++ ++ if (agent->type != NEAREST_CUSTOMER_BRIDGE) ++ return 0; ++ ed = evb22_data(port->ifname, agent->type); ++ if (!ed) { ++ LLDPAD_ERR("%s:%s agent %d failed\n", __func__, port->ifname, ++ agent->type); ++ return 0; ++ } ++ return (ed->txmit) ? evb22_build_tlv(ed) : 0; ++} ++ ++/* ++ * evb_rchange: process received EVB TLV LLDPDU ++ * ++ * TLV not consumed on error ++ */ ++static int evb22_rchange(struct port *port, struct lldp_agent *agent, ++ struct unpacked_tlv *tlv) ++{ ++ struct evb22_data *ed; ++ u8 oui_subtype[OUI_SUB_SIZE] = LLDP_MOD_EVB22_OUI; ++ ++ if (agent->type != NEAREST_CUSTOMER_BRIDGE) ++ return 0; ++ ed = evb22_data(port->ifname, agent->type); ++ ++ if (!ed) ++ return SUBTYPE_INVALID; ++ ++ if (tlv->type == TYPE_127) { ++ /* check for length */ ++ if (tlv->length < OUI_SUB_SIZE) ++ return TLV_ERR; ++ ++ /* check for oui */ ++ if (memcmp(tlv->info, &oui_subtype, OUI_SUB_SIZE)) ++ return SUBTYPE_INVALID; ++ ++ /* disable rx if tx has been disabled by administrator */ ++ if (!ed->txmit) { ++ LLDPAD_WARN("%s:%s agent %d EVB Config disabled\n", ++ __func__, ed->ifname, agent->type); ++ return TLV_OK; ++ } ++ ++ LLDPAD_DBG("%s:%s agent %d received tlv:\n", __func__, ++ port->ifname, agent->type); ++ evb22_dump_tlv(ed->ifname, tlv); ++ memcpy(&ed->last, tlv->info, tlv->length); ++ evb22_print_tlvinfo(ed->ifname, &ed->last); ++ ++ evb22_update_tlv(ed); ++ somethingChangedLocal(ed->ifname, agent->type); ++ ++ LLDPAD_DBG("%s:%s agent %d new tlv:\n", __func__, port->ifname, ++ agent->type); ++ evb22_print_tlvinfo(ed->ifname, &ed->out); ++ /* TODO vdp_update(port->ifname, ed->tie.ccap); */ ++ } ++ return TLV_OK; ++} ++ ++/* ++ * Stop all modules which depend on EVB capabilities. ++ */ ++static void evb22_stop_modules(char *ifname) ++{ ++ LLDPAD_DBG("%s:%s STOP\n", __func__, ifname); ++ ecp22_stop(ifname); ++ vdp22_stop(ifname); ++} ++ ++static void evb22_ifdown(char *ifname, struct lldp_agent *agent) ++{ ++ struct evb22_data *ed; ++ ++ if (agent->type != NEAREST_CUSTOMER_BRIDGE) ++ return; ++ LLDPAD_DBG("%s:%s agent %d called\n", __func__, ifname, agent->type); ++ ++ ed = evb22_data(ifname, agent->type); ++ if (!ed) { ++ LLDPAD_DBG("%s:%s agent %d does not exist.\n", __func__, ++ ifname, agent->type); ++ return; ++ } ++ if (ed->vdp_start) ++ evb22_stop_modules(ifname); ++ LIST_REMOVE(ed, entry); ++ free(ed); ++ LLDPAD_INFO("%s:%s agent %d removed\n", __func__, ifname, agent->type); ++} ++ ++/* ++ * Fill up evb structure with reasonable info from the configuration file. ++ */ ++static void evb22_init_tlv(struct evb22_data *ed, struct lldp_agent *agent) ++{ ++ u8 mode; ++ ++ memset(&ed->last, 0, sizeof ed->last); ++ memset(&ed->out, 0, sizeof ed->out); ++ memset(&ed->policy, 0, sizeof ed->policy); ++ ++ ed->txmit = evb22_conf_enabletx(ed->ifname, agent->type); ++ if (!ed->txmit) ++ LLDPAD_DBG("%s:%s agent %d EVB tx is currently disabled\n", ++ __func__, ed->ifname, agent->type); ++ ++ hton24(ed->policy.oui, LLDP_MOD_EVB22); ++ ed->policy.sub = LLDP_MOD_EVB22_SUBTYPE; ++ hton24(ed->out.oui, LLDP_MOD_EVB22); ++ ed->out.sub = LLDP_MOD_EVB22_SUBTYPE; ++ ++ mode = evb22_conf_evbmode(ed->ifname, agent->type); ++ ed->policy.evb_mode = evb_set_rol(0) ++ | evb_set_rwd(evb22_conf_rwd(ed->ifname, agent->type)) ++ | evb_set_evbmode(mode); ++ if (mode == EVB_STATION) { ++ mode = evb22_conf_rrreq(ed->ifname, agent->type); ++ ed->policy.station_s = evb_set_rrstat(EVB_RRSTAT_DONT) ++ | evb_set_sgid(evb22_conf_gid(ed->ifname, agent->type)) ++ | evb_set_rrreq(mode); ++ ed->policy.bridge_s = 0; ++ } else { ++ mode = evb22_conf_rrcap(ed->ifname, agent->type); ++ ed->policy.bridge_s = evb_set_rrcap(mode) ++ | evb_set_bgid(evb22_conf_gid(ed->ifname, agent->type)); ++ ed->policy.station_s = 0; ++ } ++ ed->policy.r_rte = ++ evb_set_retries(evb22_conf_retries(ed->ifname, agent->type)) ++ | evb_set_rte(evb22_conf_rte(ed->ifname, agent->type)); ++ ed->policy.rl_rka = evb_set_rol(0) ++ | evb_set_rka(evb22_conf_rka(ed->ifname, agent->type)); ++} ++ ++static void evb22_ifup(char *ifname, struct lldp_agent *agent) ++{ ++ struct evb22_data *ed; ++ struct evb22_user_data *ud; ++ ++ if (agent->type != NEAREST_CUSTOMER_BRIDGE) ++ return; ++ LLDPAD_DBG("%s:%s agent %d called\n", __func__, ifname, agent->type); ++ if (is_tlv_txenabled(ifname, agent->type, ++ TLVID(OUI_IEEE_8021Qbg, LLDP_EVB_SUBTYPE))) { ++ LLDPAD_ERR("%s:%s evb draft 0.2 protocol already enabled\n", ++ __func__, ifname); ++ return; ++ } ++ ++ ed = evb22_data(ifname, agent->type); ++ if (ed) { ++ LLDPAD_DBG("%s:%s agent %d already exists\n", __func__, ifname, ++ agent->type); ++ return; ++ } ++ ++ /* not found, alloc/init per-port tlv data */ ++ ed = (struct evb22_data *) calloc(1, sizeof *ed); ++ if (!ed) { ++ LLDPAD_ERR("%s:%s agent %d malloc %zu failed\n", ++ __func__, ifname, agent->type, sizeof *ed); ++ return; ++ } ++ strncpy(ed->ifname, ifname, IFNAMSIZ); ++ ed->agenttype = agent->type; ++ evb22_init_tlv(ed, agent); ++ ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_EVB22); ++ LIST_INSERT_HEAD(&ud->head, ed, entry); ++ LLDPAD_DBG("%s:%s agent %d added\n", __func__, ifname, agent->type); ++} ++ ++/* ++ * Start all modules which depend on EVB capabilities: ECP, VDP, CDCP. ++ */ ++static void evb22_start_modules(char *ifname, int role) ++{ ++ LLDPAD_DBG("%s:%s START role:%d\n", __func__, ifname, role); ++ ecp22_start(ifname); ++ vdp22_start(ifname, role); ++} ++ ++/* ++ * Check for stable interfaces. When an interface goes up the carrier might ++ * come and go during a start up time. Define a window during which the port ++ * is considered unstable for EVB/VDP protocols. ++ * ++ * Use the dormantDelay counter of the port to determine a stable interface. ++ */ ++static int evb22_timer(struct port *port, struct lldp_agent *agent) ++{ ++ struct evb22_data *ed; ++ ++ if (agent->type != NEAREST_CUSTOMER_BRIDGE) ++ return 0; ++ ed = evb22_data(port->ifname, agent->type); ++ if (!ed) ++ return 0; ++ if (!ed->vdp_start) { ++ ed->vdp_start = true; ++ evb22_start_modules(port->ifname, ++ evb_ex_evbmode(ed->policy.evb_mode)); ++ } ++ return 0; ++} ++ ++static u8 evb22_mibdelete(struct port *port, struct lldp_agent *agent) ++{ ++ struct evb22_data *ed; ++ ++ ed = evb22_data(port->ifname, agent->type); ++ if (ed && (agent->type == ed->agenttype)) { ++ memset(&ed->last, 0, sizeof ed->last); ++ /* TODO vdp_update(port->ifname, 0); */ ++ } ++ return 0; ++} ++ ++/* ++ * Remove all interface/agent specific evb data. ++ */ ++static void evb22_free_data(struct evb22_user_data *ud) ++{ ++ struct evb22_data *ed; ++ ++ if (ud) { ++ while (!LIST_EMPTY(&ud->head)) { ++ ed = LIST_FIRST(&ud->head); ++ LIST_REMOVE(ed, entry); ++ free(ed); ++ } ++ } ++} ++ ++void evb22_unregister(struct lldp_module *mod) ++{ ++ if (mod->data) { ++ evb22_free_data((struct evb22_user_data *) mod->data); ++ free(mod->data); ++ } ++ free(mod); ++ LLDPAD_DBG("%s:done\n", __func__); ++} ++ ++static const struct lldp_mod_ops evb22_ops = { ++ .lldp_mod_gettlv = evb22_gettlv, ++ .lldp_mod_rchange = evb22_rchange, ++ .lldp_mod_mibdelete = evb22_mibdelete, ++ .timer = evb22_timer, ++ .lldp_mod_ifdown = evb22_ifdown, ++ .lldp_mod_ifup = evb22_ifup, ++ .lldp_mod_register = evb22_register, ++ .lldp_mod_unregister = evb22_unregister, ++ .get_arg_handler = evb22_get_arg_handlers ++}; ++ ++struct lldp_module *evb22_register(void) ++{ ++ struct lldp_module *mod; ++ struct evb22_user_data *ud; ++ ++ mod = calloc(1, sizeof *mod); ++ if (!mod) { ++ LLDPAD_ERR("%s: failed to malloc module data\n", __func__); ++ return NULL; ++ } ++ ud = calloc(1, sizeof *ud); ++ if (!ud) { ++ free(mod); ++ LLDPAD_ERR("%s failed to malloc module user data\n", __func__); ++ return NULL; ++ } ++ LIST_INIT(&ud->head); ++ mod->id = LLDP_MOD_EVB22; ++ mod->ops = &evb22_ops; ++ mod->data = ud; ++ LLDPAD_DBG("%s:done\n", __func__); ++ return mod; ++} +diff --git a/lldp_evb22_clif.c b/lldp_evb22_clif.c +new file mode 100644 +index 0000000..336273f +--- /dev/null ++++ b/lldp_evb22_clif.c +@@ -0,0 +1,201 @@ ++/****************************************************************************** ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++#include ++#include ++ ++#include "lldp_tlv.h" ++#include "clif_msgs.h" ++#include "lldp_mod.h" ++#include "lldptool.h" ++#include "lldp.h" ++#include "lldp_evb22.h" ++#include "lldp_evb22_clif.h" ++ ++static void show_tlv(char *buf, size_t len, struct evb22_tlv *tlv) ++{ ++ int comma = 0; ++ char bridge_txt[32], station_txt[32]; ++ ++ memset(bridge_txt, 0, sizeof bridge_txt); ++ if (evb_ex_bgid(tlv->bridge_s)) { ++ strcat(bridge_txt, "bgid"); ++ comma = 1; ++ } ++ if (evb_ex_rrcap(tlv->bridge_s)) { ++ if (comma) ++ strcat(bridge_txt, ","); ++ strcat(bridge_txt, "rrcap"); ++ comma = 1; ++ } ++ if (evb_ex_rrctr(tlv->bridge_s)) { ++ if (comma) ++ strcat(bridge_txt, ","); ++ strcat(bridge_txt, "rrctr"); ++ } ++ ++ comma = 0; ++ memset(station_txt, 0, sizeof station_txt); ++ if (evb_ex_sgid(tlv->station_s)) { ++ strcat(station_txt, "sgid"); ++ comma = 1; ++ } ++ if (evb_ex_rrreq(tlv->station_s)) { ++ if (comma) ++ strcat(station_txt, ","); ++ strcat(station_txt, "rrreq"); ++ comma = 1; ++ } ++ if (evb_ex_rrstat(tlv->station_s)) { ++ if (comma) ++ strcat(station_txt, ","); ++ strcat(station_txt, "rrstat"); ++ } ++ ++ snprintf(buf, len, "bridge:%s(%#02x)\n" ++ "\tstation:%s(%#02x)\n" ++ "\tretries:%d rte:%d\n" ++ "\tmode:%s r/l:%d rwd:%d\n" ++ "\tr/l:%d rka:%d\n", ++ bridge_txt, tlv->bridge_s, ++ station_txt, tlv->station_s, ++ evb_ex_retries(tlv->r_rte), evb_ex_rte(tlv->r_rte), ++ evb_ex_evbmode(tlv->evb_mode) == EVB_STATION ? ++ "station" : "bridge", ++ evb_ex_rol(tlv->evb_mode), ++ evb_ex_rwd(tlv->evb_mode), ++ evb_ex_rol(tlv->rl_rka), evb_ex_rka(tlv->rl_rka)); ++} ++ ++static void evb22_print_cfg_tlv(u16 len, char *info) ++{ ++ struct evb22_tlv tlv; ++ char buf[256]; ++ ++ if (len != 5) { ++ printf("Bad evbcfg TLV: %s\n", info); ++ return; ++ } ++ memset(&tlv, 0, sizeof tlv); ++ memset(buf, 0, sizeof buf); ++ hexstr2bin(&info[0], &tlv.bridge_s, sizeof tlv.bridge_s); ++ hexstr2bin(&info[2], &tlv.station_s, sizeof tlv.station_s); ++ hexstr2bin(&info[4], &tlv.r_rte, sizeof tlv.r_rte); ++ hexstr2bin(&info[6], &tlv.evb_mode, sizeof tlv.evb_mode); ++ hexstr2bin(&info[8], &tlv.rl_rka, sizeof tlv.rl_rka); ++ show_tlv(buf, sizeof buf, &tlv); ++ printf("%s", buf); ++} ++ ++static struct type_name_info evb22_tlv_names[] = { ++ { ++ .type = TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), ++ .name = "EVB Configuration TLV", ++ .key = "evb", ++ .print_info = evb22_print_cfg_tlv ++ }, ++ { ++ .type = INVALID_TLVID ++ } ++}; ++ ++static int evb22_print_help() ++{ ++ struct type_name_info *tn = &evb22_tlv_names[0]; ++ ++ while (tn->type != INVALID_TLVID) { ++ if (tn->key && strlen(tn->key) && tn->name) { ++ printf(" %s", tn->key); ++ if (strlen(tn->key)+3 < 8) ++ printf("\t"); ++ printf("\t: %s\n", tn->name); ++ } ++ tn++; ++ } ++ ++ return 0; ++} ++ ++static void evb22_cli_unregister(struct lldp_module *mod) ++{ ++ free(mod); ++} ++ ++/* return 1: if it printed the TLV ++ * 0: if it did not ++ */ ++static int evb22_print_tlv(u32 tlvid, u16 len, char *info) ++{ ++ struct type_name_info *tn = &evb22_tlv_names[0]; ++ ++ while (tn->type != INVALID_TLVID) { ++ if (tlvid == tn->type) { ++ printf("%s\n", tn->name); ++ if (tn->print_info) { ++ printf("\t"); ++ tn->print_info(len-4, info); ++ } ++ return 1; ++ } ++ tn++; ++ } ++ ++ return 0; ++} ++ ++static u32 evb22_lookup_tlv_name(char *tlvid_str) ++{ ++ struct type_name_info *tn = &evb22_tlv_names[0]; ++ ++ while (tn->type != INVALID_TLVID) { ++ if (!strcasecmp(tn->key, tlvid_str)) ++ return tn->type; ++ tn++; ++ } ++ return INVALID_TLVID; ++} ++ ++static const struct lldp_mod_ops evb22_ops_clif = { ++ .lldp_mod_register = evb22_cli_register, ++ .lldp_mod_unregister = evb22_cli_unregister, ++ .print_tlv = evb22_print_tlv, ++ .lookup_tlv_name = evb22_lookup_tlv_name, ++ .print_help = evb22_print_help ++}; ++ ++struct lldp_module *evb22_cli_register(void) ++{ ++ struct lldp_module *mod; ++ ++ mod = calloc(1, sizeof(*mod)); ++ if (!mod) { ++ fprintf(stderr, "%s failed to malloc module data\n", __func__); ++ return NULL; ++ } ++ mod->id = LLDP_MOD_EVB22; ++ mod->ops = &evb22_ops_clif; ++ ++ return mod; ++} +diff --git a/lldp_evb22_cmds.c b/lldp_evb22_cmds.c +new file mode 100644 +index 0000000..cebfeb2 +--- /dev/null ++++ b/lldp_evb22_cmds.c +@@ -0,0 +1,750 @@ ++/****************************************************************************** ++ ++ Implementation of EVB TLVs for LLDP ++ (c) Copyright IBM Corp. 2012 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++#define _GNU_SOURCE ++ ++#include ++#include ++#include ++ ++#include "lldp.h" ++#include "lldp_evb22.h" ++#include "lldp_tlv.h" ++#include "lldp_mand_clif.h" ++#include "config.h" ++#include "clif_msgs.h" ++#include "messages.h" ++ ++/* ++ * Defines for configuration file name tags. ++ */ ++#define EVB_BUF_SIZE 256 ++#define EVB_CONF_MODE "evbmode" ++#define EVB_CONF_RRREQ "evbrrreq" ++#define EVB_CONF_RRCAP "evbrrcap" ++#define EVB_CONF_GPID "evbgpid" ++#define EVB_CONF_RETRIES "ecpretries" ++#define EVB_CONF_RTE "ecprte" ++#define EVB_CONF_RWD "vdprwd" ++#define EVB_CONF_RKA "vdprka" ++#define EVB_CONF_BRIDGE "bridge" ++#define EVB_CONF_STATION "station" ++ ++/* ++ * Read EVB specific data from the configuration file. ++ */ ++static const char *evb22_conf_string(char *ifname, enum agent_type type, ++ char *ext, int def) ++{ ++ char arg_path[EVB_BUF_SIZE]; ++ const char *param = NULL; ++ ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", ++ TLVID_PREFIX, TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), ++ ext); ++ if (get_cfg(ifname, type, arg_path, ¶m, CONFIG_TYPE_STRING)) ++ LLDPAD_INFO("%s:%s agent %d loading EVB policy for %s" ++ " failed, using default (%d)\n", __func__, ++ ifname, type, ext, def); ++ return param; ++} ++ ++static int evb22_conf_int(char *ifname, enum agent_type type, ++ char *ext, int def, int cfgtype) ++{ ++ char arg_path[EVB_BUF_SIZE]; ++ int param; ++ ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", ++ TLVID_PREFIX, TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), ++ ext); ++ if (get_cfg(ifname, type, arg_path, ¶m, cfgtype)) { ++ LLDPAD_INFO("%s:%s agent %d loading EVB policy for %s" ++ " failed, using default (%d)\n", __func__, ++ ifname, type, ext, def); ++ return def; ++ } ++ return param; ++} ++ ++/* ++ * Read EXP parameter. Defaults to 8 --> 10 * 2 ^ 8 = 2560us > 2ms. ++ */ ++static int exponent(char *ifname, enum agent_type type, char *txt, int def) ++{ ++ int value; ++ ++ value = evb22_conf_int(ifname, type, txt, def, CONFIG_TYPE_INT); ++ if (value > 31) { ++ LLDPAD_DBG("%s:%s agent %d invalid %s %d\n", __func__, ++ ifname, type, txt, value); ++ value = def; ++ } ++ LLDPAD_DBG("%s:%s agent %d policy %s %d\n", __func__, ++ ifname, type, txt, value); ++ return value; ++} ++ ++/* ++ * Read retransmission exponent parameter. ++ */ ++int evb22_conf_rte(char *ifname, enum agent_type type) ++{ ++ return exponent(ifname, type, EVB_CONF_RTE, 8); ++} ++ ++/* ++ * Read reinit keep alive parameter. Same as RTE. ++ */ ++int evb22_conf_rka(char *ifname, enum agent_type type) ++{ ++ return exponent(ifname, type, EVB_CONF_RKA, 20); ++} ++ ++/* ++ * Read resource wait delay parameter. Same as RTE. ++ */ ++int evb22_conf_rwd(char *ifname, enum agent_type type) ++{ ++ return exponent(ifname, type, EVB_CONF_RWD, 20); ++} ++ ++/* ++ * Read max retries parameter. Defaults to 3. ++ */ ++int evb22_conf_retries(char *ifname, enum agent_type type) ++{ ++ int value; ++ ++ value = evb22_conf_int(ifname, type, EVB_CONF_RETRIES, 3, ++ CONFIG_TYPE_INT); ++ if (value > 7) { ++ LLDPAD_DBG("%s:%s agent %d invalid %s %d\n", __func__, ++ ifname, type, EVB_CONF_RETRIES, value); ++ value = 3; ++ } ++ LLDPAD_DBG("%s:%s agent %d policy %s %d\n", __func__, ++ ifname, type, EVB_CONF_RETRIES, value); ++ return value; ++} ++ ++/* ++ * Read station group id parameter. Defaults to false. ++ */ ++int evb22_conf_gid(char *ifname, enum agent_type type) ++{ ++ int value; ++ ++ value = evb22_conf_int(ifname, type, EVB_CONF_GPID, false, ++ CONFIG_TYPE_BOOL); ++ LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, ++ ifname, type, EVB_CONF_GPID, value ? "true" : "false"); ++ return value; ++} ++ ++/* ++ * Read reflective-relay bridge capability parameter. Defaults to false. ++ */ ++int evb22_conf_rrcap(char *ifname, enum agent_type type) ++{ ++ int value; ++ ++ value = evb22_conf_int(ifname, type, EVB_CONF_RRCAP, false, ++ CONFIG_TYPE_BOOL); ++ LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, ++ ifname, type, EVB_CONF_RRCAP, value ? "true" : "false"); ++ return value; ++} ++ ++/* ++ * Read reflective-relay station request parameter. Defaults to false. ++ */ ++int evb22_conf_rrreq(char *ifname, enum agent_type type) ++{ ++ int value; ++ ++ value = evb22_conf_int(ifname, type, EVB_CONF_RRREQ, false, ++ CONFIG_TYPE_BOOL); ++ LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, ++ ifname, type, EVB_CONF_RRREQ, value ? "true" : "false"); ++ return value; ++} ++ ++/* ++ * Read station/bridge role from configuration file. Defaults to station ++ */ ++int evb22_conf_evbmode(char *ifname, enum agent_type type) ++{ ++ int mode = EVB_STATION; ++ const char *value; ++ ++ value = evb22_conf_string(ifname, type, EVB_CONF_MODE, mode); ++ if (value) { ++ if (!strcasecmp(value, EVB_CONF_BRIDGE)) ++ mode = EVB_BRIDGE; ++ else if (strcasecmp(value, EVB_CONF_STATION)) { ++ LLDPAD_ERR("%s:%s agent %d invalid evbmode %s\n", ++ __func__, ifname, type, value); ++ value = EVB_CONF_STATION; ++ } ++ } else ++ value = EVB_CONF_STATION; ++ LLDPAD_DBG("%s:%s agent %d policy %s %s(%#x)\n", __func__, ++ ifname, type, EVB_CONF_MODE, value, mode); ++ return mode; ++} ++ ++/* ++ * Read transmit status from configuration file. ++ */ ++int evb22_conf_enabletx(char *ifname, enum agent_type type) ++{ ++ return is_tlv_txenabled(ifname, type, ++ TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE)); ++} ++ ++static int evb22_cmdok(struct cmd *cmd, cmd_status expected) ++{ ++ if (cmd->cmd != expected) ++ return cmd_invalid; ++ switch (cmd->tlvid) { ++ case TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE): ++ return cmd_success; ++ case INVALID_TLVID: ++ return cmd_invalid; ++ default: ++ return cmd_not_applicable; ++ } ++} ++ ++static int get_arg_evbmode(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ struct evb22_data *ed; ++ char *s; ++ cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ed = evb22_data((char *) &cmd->ifname, cmd->type); ++ if (!ed) ++ return cmd_invalid; ++ if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) ++ s = EVB_CONF_STATION; ++ else ++ s = EVB_CONF_BRIDGE; ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); ++ return cmd_success; ++} ++ ++static int set2_arg_evbmode(struct cmd *cmd, char *arg, const char *argvalue, ++ bool test) ++{ ++ char arg_path[EVB_BUF_SIZE]; ++ struct evb22_data *ed; ++ cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); ++ u8 mode; ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ if (strcasecmp(argvalue, EVB_CONF_BRIDGE) ++ && strcasecmp(argvalue, EVB_CONF_STATION)) ++ return cmd_bad_params; ++ ed = evb22_data((char *) &cmd->ifname, cmd->type); ++ if (!ed) ++ return cmd_invalid; ++ if (test) ++ return cmd_success; ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", ++ TLVID_PREFIX, cmd->tlvid, arg); ++ ++ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, ++ CONFIG_TYPE_STRING)) { ++ LLDPAD_ERR("%s: error saving EVB mode (%s)\n", ed->ifname, ++ argvalue); ++ return cmd_failed; ++ } ++ mode = strcasecmp(argvalue, EVB_CONF_BRIDGE) ? EVB_STATION : EVB_BRIDGE; ++ ed->policy.evb_mode = evb_maskoff_evbmode(ed->policy.evb_mode) | ++ evb_set_evbmode(mode); ++ LLDPAD_INFO("%s: changed EVB mode (%s)\n", ed->ifname, argvalue); ++ return cmd_success; ++} ++ ++static int set_arg_evbmode(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return set2_arg_evbmode(cmd, arg, argvalue, false); ++} ++ ++static int test_arg_evbmode(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return set2_arg_evbmode(cmd, arg, argvalue, true); ++} ++ ++static int get_txmit(struct evb22_data *ed) ++{ ++ return ed->txmit; ++} ++ ++static void set_txmit(struct evb22_data *ed, int value) ++{ ++ ed->txmit = value; ++} ++ ++static int get_gpid(struct evb22_data *ed) ++{ ++ int mode = evb_ex_evbmode(ed->policy.evb_mode); ++ ++ if (mode == EVB_STATION && evb_ex_sgid(ed->policy.station_s)) ++ return 1; ++ if (mode == EVB_BRIDGE && evb_ex_bgid(ed->policy.bridge_s)) ++ return 1; ++ return 0; ++} ++ ++static void set_gpid(struct evb22_data *ed, int value) ++{ ++ if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) ++ ed->policy.station_s = evb_maskoff_sgid(ed->policy.station_s) ++ | evb_set_sgid(value); ++ else ++ ed->policy.bridge_s = evb_maskoff_bgid(ed->policy.bridge_s) ++ | evb_set_bgid(value); ++} ++ ++static void set_rrcap(struct evb22_data *ed, int value) ++{ ++ ed->policy.bridge_s = evb_maskoff_rrcap(ed->policy.bridge_s) ++ | evb_set_rrcap(value); ++} ++ ++static int get_rrcap(struct evb22_data *ed) ++{ ++ return evb_ex_rrcap(ed->policy.bridge_s); ++} ++ ++static void set_rrreq(struct evb22_data *ed, int value) ++{ ++ ed->policy.station_s = evb_maskoff_rrreq(ed->policy.station_s) ++ | evb_set_rrreq(value); ++} ++ ++static int get_rrreq(struct evb22_data *ed) ++{ ++ return evb_ex_rrreq(ed->policy.station_s); ++} ++ ++/* ++ * Read a boolean value from the command line argument and apply the new ++ * value to parameter. ++ */ ++static int scan_bool(struct cmd *cmd, char *arg, char *argvalue, bool test, ++ void (*fct)(struct evb22_data *, int)) ++{ ++ int value; ++ char arg_path[EVB_BUF_SIZE]; ++ struct evb22_data *ed; ++ cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ if (!strcasecmp(argvalue, VAL_YES)) ++ value = 1; ++ else if (!strcasecmp(argvalue, VAL_NO)) ++ value = 0; ++ else ++ return cmd_bad_params; ++ ed = evb22_data((char *) &cmd->ifname, cmd->type); ++ if (!ed) ++ return cmd_invalid; ++ if (test) ++ return cmd_success; ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", ++ TLVID_PREFIX, cmd->tlvid, arg); ++ if (set_cfg(cmd->ifname, cmd->type, arg_path, &value, ++ CONFIG_TYPE_BOOL)){ ++ LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", ed->ifname, ++ argvalue); ++ return cmd_failed; ++ } ++ LLDPAD_INFO("%s: changed EVB %s (%s)\n", ed->ifname, arg, argvalue); ++ (*fct)(ed, value); ++ somethingChangedLocal(cmd->ifname, cmd->type); ++ return cmd_success; ++} ++ ++static int show_bool(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len, ++ int (*fct)(struct evb22_data *)) ++{ ++ struct evb22_data *ed; ++ char *s; ++ cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ed = evb22_data((char *) &cmd->ifname, cmd->type); ++ if (!ed) ++ return cmd_invalid; ++ if ((*fct)(ed)) ++ s = VAL_YES; ++ else ++ s = VAL_NO; ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); ++ return cmd_success; ++} ++ ++static int get_arg_tlvtxenable(struct cmd *cmd, char *arg, ++ UNUSED char *argvalue, char *obuf, int obuf_len) ++{ ++ return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_txmit); ++} ++ ++static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_bool(cmd, arg, argvalue, false, set_txmit); ++} ++ ++static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ /* ++ * Make sure either evb draft 0.2 or evb ratified standard is ++ * running at the same time but not both. ++ */ ++ if (!strcasecmp(argvalue, VAL_YES) ++ && is_tlv_txenabled(cmd->ifname, cmd->type, ++ TLVID(OUI_IEEE_8021Qbg, ++ LLDP_EVB_SUBTYPE))) { ++ LLDPAD_ERR("%s:%s evb draft 0.2 protocol already enabled\n", ++ __func__, cmd->ifname); ++ return cmd_failed; ++ } ++ return scan_bool(cmd, arg, argvalue, true, 0); ++} ++ ++static int get_arg_gpid(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_gpid); ++} ++ ++static int set_arg_gpid(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_bool(cmd, arg, argvalue, false, set_gpid); ++} ++ ++static int test_arg_gpid(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_bool(cmd, arg, argvalue, true, 0); ++} ++ ++static int get_arg_rrcap(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_rrcap); ++} ++ ++static int set_arg_rrcap(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_bool(cmd, arg, argvalue, false, set_rrcap); ++} ++ ++static int test_arg_rrcap(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_bool(cmd, arg, argvalue, true, 0); ++} ++ ++static int get_arg_rrreq(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_rrreq); ++} ++ ++static int set_arg_rrreq(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_bool(cmd, arg, argvalue, false, set_rrreq); ++} ++ ++static int test_arg_rrreq(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_bool(cmd, arg, argvalue, true, 0); ++} ++ ++ ++static void set_retries(struct evb22_data *ed, int value) ++{ ++ ed->policy.r_rte = evb_maskoff_retries(ed->policy.r_rte) ++ | evb_set_retries(value); ++} ++ ++static int get_retries(struct evb22_data *ed) ++{ ++ return evb_ex_retries(ed->policy.r_rte); ++} ++ ++static void set_rte(struct evb22_data *ed, int value) ++{ ++ ed->policy.r_rte = evb_maskoff_rte(ed->policy.r_rte) ++ | evb_set_rte(value); ++} ++ ++static int get_rte(struct evb22_data *ed) ++{ ++ return evb_ex_rte(ed->policy.r_rte); ++} ++ ++static void set_rwd(struct evb22_data *ed, int value) ++{ ++ ed->policy.evb_mode = evb_maskoff_rwd(ed->policy.evb_mode) ++ | evb_set_rwd(value); ++} ++ ++static int get_rwd(struct evb22_data *ed) ++{ ++ return evb_ex_rwd(ed->policy.evb_mode); ++} ++ ++static void set_rka(struct evb22_data *ed, int value) ++{ ++ ed->policy.rl_rka = evb_maskoff_rka(ed->policy.rl_rka) ++ | evb_set_rka(value); ++} ++ ++static int get_rka(struct evb22_data *ed) ++{ ++ return evb_ex_rka(ed->policy.rl_rka); ++} ++ ++static int scan_31bit(struct cmd *cmd, char *arg, const char *argvalue, ++ bool test, void (*fct)(struct evb22_data *, int), ++ int limit) ++{ ++ char arg_path[EVB_BUF_SIZE]; ++ struct evb22_data *ed; ++ int value; ++ char *endp; ++ cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ value = strtoul(argvalue, &endp, 0); ++ if (*endp != '\0' || value > limit) ++ return cmd_bad_params; ++ ed = evb22_data((char *) &cmd->ifname, cmd->type); ++ if (!ed) ++ return cmd_invalid; ++ if (test) ++ return cmd_success; ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", ++ TLVID_PREFIX, cmd->tlvid, arg); ++ if (set_cfg(ed->ifname, cmd->type, arg_path, &value, ++ CONFIG_TYPE_INT)){ ++ LLDPAD_ERR("%s: error saving EVB %s (%d)\n", ed->ifname, arg, ++ value); ++ return cmd_failed; ++ } ++ LLDPAD_INFO("%s: changed EVB %s (%s)\n", ed->ifname, arg, argvalue); ++ (*fct)(ed, value); ++ somethingChangedLocal(cmd->ifname, cmd->type); ++ return cmd_success; ++} ++ ++static int show_31bit(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len, ++ int (*fct)(struct evb22_data *)) ++{ ++ struct evb22_data *ed; ++ char s[EVB_BUF_SIZE]; ++ cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ed = evb22_data((char *) &cmd->ifname, cmd->type); ++ if (!ed) ++ return cmd_invalid; ++ if (sprintf(s, "%i", (*fct)(ed)) <= 0) ++ return cmd_invalid; ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); ++ return cmd_success; ++} ++ ++static int get_arg_retries(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_retries); ++} ++ ++static int set_arg_retries(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_31bit(cmd, arg, argvalue, false, set_retries, 7); ++} ++ ++static int test_arg_retries(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_31bit(cmd, arg, argvalue, true, 0, 7); ++} ++ ++static int get_arg_rte(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rte); ++} ++ ++static int set_arg_rte(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_31bit(cmd, arg, argvalue, false, set_rte, 31); ++} ++ ++static int test_arg_rte(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_31bit(cmd, arg, argvalue, true, 0, 31); ++} ++ ++static int get_arg_rwd(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rwd); ++} ++ ++static int set_arg_rwd(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_31bit(cmd, arg, argvalue, false, set_rwd, 31); ++} ++ ++static int test_arg_rwd(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_31bit(cmd, arg, argvalue, true, 0, 31); ++} ++ ++static int get_arg_rka(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rka); ++} ++ ++static int set_arg_rka(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_31bit(cmd, arg, argvalue, false, set_rka, 31); ++} ++ ++static int test_arg_rka(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return scan_31bit(cmd, arg, argvalue, true, 0, 31); ++} ++ ++static struct arg_handlers arg_handlers[] = { ++ { ++ .arg = EVB_CONF_RKA, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_rka, ++ .handle_set = set_arg_rka, ++ .handle_test = test_arg_rka ++ }, ++ { ++ .arg = EVB_CONF_RWD, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_rwd, ++ .handle_set = set_arg_rwd, ++ .handle_test = test_arg_rwd ++ }, ++ { ++ .arg = EVB_CONF_RTE, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_rte, ++ .handle_set = set_arg_rte, ++ .handle_test = test_arg_rte ++ }, ++ { ++ .arg = EVB_CONF_RETRIES, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_retries, ++ .handle_set = set_arg_retries, ++ .handle_test = test_arg_retries ++ }, ++ { ++ .arg = EVB_CONF_RRREQ, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_rrreq, ++ .handle_set = set_arg_rrreq, ++ .handle_test = test_arg_rrreq ++ }, ++ { ++ .arg = EVB_CONF_RRCAP, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_rrcap, ++ .handle_set = set_arg_rrcap, ++ .handle_test = test_arg_rrcap ++ }, ++ { ++ .arg = EVB_CONF_GPID, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_gpid, ++ .handle_set = set_arg_gpid, ++ .handle_test = test_arg_gpid ++ }, ++ { ++ .arg = EVB_CONF_MODE, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_evbmode, ++ .handle_set = set_arg_evbmode, ++ .handle_test = test_arg_evbmode ++ }, ++ { ++ .arg = ARG_TLVTXENABLE, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_tlvtxenable, ++ .handle_set = set_arg_tlvtxenable, ++ .handle_test = test_arg_tlvtxenable ++ }, ++ { ++ .arg = 0 ++ } ++}; ++ ++struct arg_handlers *evb22_get_arg_handlers() ++{ ++ return &arg_handlers[0]; ++} +diff --git a/lldp_evb_cmds.c b/lldp_evb_cmds.c +index 923d56d..eec4f33 100644 +--- a/lldp_evb_cmds.c ++++ b/lldp_evb_cmds.c +@@ -32,7 +32,7 @@ + + #include "lldp.h" + #include "lldp_evb.h" +-#include "lldp_vdp.h" ++#include "qbg_vdp.h" + #include "lldp_tlv.h" + #include "lldp_mand_clif.h" + #include "config.h" +@@ -167,8 +167,12 @@ static int evb_cmdok(struct cmd *cmd, cmd_status expected) + { + if (cmd->cmd != expected) + return cmd_invalid; ++ + switch (cmd->tlvid) { + case TLVID_8021Qbg(LLDP_EVB_SUBTYPE): ++ if (cmd->type != NEAREST_CUSTOMER_BRIDGE) ++ return cmd_agent_not_supported; ++ + return cmd_success; + case INVALID_TLVID: + return cmd_invalid; +@@ -181,17 +185,19 @@ static int + get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, + char *obuf, int obuf_len) + { +- struct evb_data *ed; +- char *s; + cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); ++ char *s, arg_path[EVB_BUF_SIZE]; ++ int value; + + if (good_cmd != cmd_success) + return good_cmd; + +- ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (ed->txmit) ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", ++ TLVID_PREFIX, cmd->tlvid, arg); ++ if (get_cfg(cmd->ifname, cmd->type, arg_path, &value, CONFIG_TYPE_BOOL)) ++ value = false; ++ ++ if (value) + s = VAL_YES; + else + s = VAL_NO; +@@ -221,10 +227,11 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, + return cmd_bad_params; + + ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (vdp_vsis(ed->ifname)) +- return cmd_failed; ++ if (ed) { ++ if (vdp_vsis(ed->ifname)) ++ return cmd_failed; ++ } ++ + if (test) + return cmd_success; + +@@ -233,12 +240,14 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, + + if (set_cfg(cmd->ifname, cmd->type, arg_path, &value, + CONFIG_TYPE_BOOL)){ +- LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", ed->ifname, ++ LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", cmd->ifname, + argvalue); + return cmd_failed; + } +- ed->txmit = value; +- LLDPAD_INFO("%s: changed EVB enabletx (%s)\n", ed->ifname, argvalue); ++ if (ed) ++ ed->txmit = value; ++ ++ LLDPAD_INFO("%s: changed EVB enabletx (%s)\n", cmd->ifname, argvalue); + somethingChangedLocal(cmd->ifname, cmd->type); + + return cmd_success; +@@ -253,26 +262,37 @@ static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, + static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, + UNUSED char *obuf, UNUSED int obuf_len) + { ++ /* ++ * Make sure either evb draft 0.2 or evb ratified standard is ++ * running at the same time but not both. ++ */ ++ if (!strcasecmp(argvalue, VAL_YES) ++ && is_tlv_txenabled(cmd->ifname, cmd->type, ++ TLVID(OUI_IEEE_8021Qbg22, ++ LLDP_EVB22_SUBTYPE))) { ++ LLDPAD_ERR("%s:%s evb protocol already enabled\n", ++ __func__, cmd->ifname); ++ return cmd_failed; ++ } + return _set_arg_tlvtxenable(cmd, arg, argvalue, true); + } + + static int get_arg_fmode(struct cmd *cmd, char *arg, UNUSED char *argvalue, + char *obuf, int obuf_len) + { +- char *s; +- struct evb_data *ed; + cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); ++ char *s; ++ u8 mode; + + if (good_cmd != cmd_success) + return good_cmd; + +- ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (ed->policy.smode & LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY) ++ mode = evb_conf_fmode(cmd->ifname, cmd->type); ++ if (mode & LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY) + s = VAL_EVB_FMODE_REFLECTIVE_RELAY; + else + s = VAL_EVB_FMODE_BRIDGE; ++ + snprintf(obuf, obuf_len, "%02x%s%04x%s", + (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); + return cmd_success; +@@ -296,25 +316,28 @@ static int _set_arg_fmode(struct cmd *cmd, const char *argvalue, bool test) + return cmd_bad_params; + + ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (vdp_vsis(ed->ifname)) +- return cmd_failed; ++ if (ed) { ++ if (vdp_vsis(ed->ifname)) ++ return cmd_failed; ++ } ++ + if (test) + return cmd_success; + + snprintf(arg_path, sizeof(arg_path), "%s%08x.fmode", + TLVID_PREFIX, cmd->tlvid); + +- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, ++ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, + CONFIG_TYPE_STRING)) { + LLDPAD_ERR("%s: saving EVB forwarding mode failed\n", +- ed->ifname); ++ cmd->ifname); + return cmd_failed; + } + +- ed->policy.smode = smode; +- LLDPAD_INFO("%s: changed EVB forwarding mode (%s)\n", ed->ifname, ++ if (ed) ++ ed->policy.smode = smode; ++ ++ LLDPAD_INFO("%s: changed EVB forwarding mode (%s)\n", cmd->ifname, + argvalue); + somethingChangedLocal(cmd->ifname, cmd->type); + return cmd_success; +@@ -338,27 +361,25 @@ get_arg_capabilities(struct cmd *cmd, char *arg, UNUSED char *argvalue, + { + int comma = 0; + char t[EVB_BUF_SIZE]; +- struct evb_data *ed; ++ u8 scap; + cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); + + if (good_cmd != cmd_success) + return good_cmd; +- ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; + ++ scap = evb_conf_capa(cmd->ifname, cmd->type); + memset(t, 0, sizeof t); +- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) { ++ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) { + strcat(t, VAL_EVB_CAPA_RTE); + comma = 1; + } +- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP) { ++ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP) { + if (comma) + strcat(t, " "); + strcat(t, VAL_EVB_CAPA_ECP); + comma = 1; + } +- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP) { ++ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP) { + if (comma) + strcat(t, " "); + strcat(t, VAL_EVB_CAPA_VDP); +@@ -415,25 +436,25 @@ _set_arg_capabilities(struct cmd *cmd, const char *argvalue, bool test) + return cmd_bad_params; + + ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (vdp_vsis(ed->ifname)) +- return cmd_failed; ++ if (ed) ++ if (vdp_vsis(ed->ifname)) ++ return cmd_failed; + if (test) + return cmd_success; + + snprintf(arg_path, sizeof(arg_path), "%s%08x.capabilities", + TLVID_PREFIX, cmd->tlvid); + +- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, ++ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, + CONFIG_TYPE_STRING)) { + LLDPAD_ERR("%s: saving EVB capabilities (%#x) failed\n", +- ed->ifname, scap); ++ cmd->ifname, scap); + return cmd_failed; + } + +- ed->policy.scap = scap; +- LLDPAD_INFO("%s: changed EVB capabilities (%#x)\n", ed->ifname, scap); ++ if (ed) ++ ed->policy.scap = scap; ++ LLDPAD_INFO("%s: changed EVB capabilities (%#x)\n", cmd->ifname, scap); + somethingChangedLocal(cmd->ifname, cmd->type); + + return cmd_success; +@@ -457,17 +478,15 @@ static int get_arg_rte(struct cmd *cmd, char *arg, UNUSED char *argvalue, + char *obuf, int obuf_len) + { + char s[EVB_BUF_SIZE]; +- struct evb_data *ed; ++ u8 rte; + cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); + + if (good_cmd != cmd_success) + return good_cmd; + +- ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; ++ rte = evb_conf_rte(cmd->ifname, cmd->type); + +- if (sprintf(s, "%i", ed->policy.rte) <= 0) ++ if (sprintf(s, "%i", rte) <= 0) + return cmd_invalid; + + snprintf(obuf, obuf_len, "%02x%s%04x%s", +@@ -491,24 +510,24 @@ static int _set_arg_rte(struct cmd *cmd, const char *argvalue, bool test) + return cmd_bad_params; + + ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (vdp_vsis(ed->ifname)) +- return cmd_failed; ++ if (ed) ++ if (vdp_vsis(ed->ifname)) ++ return cmd_failed; + if (test) + return cmd_success; + + snprintf(arg_path, sizeof(arg_path), "%s%08x.rte", TLVID_PREFIX, + cmd->tlvid); +- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, ++ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, + CONFIG_TYPE_STRING)){ +- LLDPAD_ERR("%s: error saving EVB rte (%d)\n", ed->ifname, ++ LLDPAD_ERR("%s: error saving EVB rte (%d)\n", cmd->ifname, + value); + return cmd_failed; + } + +- ed->policy.rte = value; +- LLDPAD_INFO("%s: changed EVB rte (%#x)\n", ed->ifname, value); ++ if (ed) ++ ed->policy.rte = value; ++ LLDPAD_INFO("%s: changed EVB rte (%#x)\n", cmd->ifname, value); + somethingChangedLocal(cmd->ifname, cmd->type); + + return cmd_success; +@@ -530,16 +549,15 @@ static int get_arg_vsis(struct cmd *cmd, char *arg, UNUSED char *argvalue, + char *obuf, int obuf_len) + { + char s[EVB_BUF_SIZE]; +- struct evb_data *ed; ++ u16 svsi; + cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); + + if (good_cmd != cmd_success) + return good_cmd; + +- ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (sprintf(s, "%04i", ed->policy.svsi) <= 0) ++ svsi = evb_conf_vsis(cmd->ifname, cmd->type); ++ ++ if (sprintf(s, "%04i", svsi) <= 0) + return cmd_invalid; + snprintf(obuf, obuf_len, "%02x%s%04x%s", + (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); +@@ -561,24 +579,24 @@ static int _set_arg_vsis(struct cmd *cmd, const char *argvalue, bool test) + return cmd_bad_params; + + ed = evb_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (vdp_vsis(ed->ifname)) +- return cmd_failed; ++ if (ed) ++ if (vdp_vsis(ed->ifname)) ++ return cmd_failed; + if (test) + return cmd_success; + + snprintf(arg_path, sizeof(arg_path), "%s%08x.vsis", TLVID_PREFIX, + cmd->tlvid); +- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, ++ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, + CONFIG_TYPE_STRING)){ +- LLDPAD_ERR("%s: error saving EVB vsi (%d)\n", ed->ifname, ++ LLDPAD_ERR("%s: error saving EVB vsi (%d)\n", cmd->ifname, + value); + return cmd_failed; + } + +- ed->policy.svsi = htons(value); +- LLDPAD_INFO("%s: changed EVB vsis (%#x)\n", ed->ifname, value); ++ if (ed) ++ ed->policy.svsi = htons(value); ++ LLDPAD_INFO("%s: changed EVB vsis (%#x)\n", cmd->ifname, value); + somethingChangedLocal(cmd->ifname, cmd->type); + + return cmd_success; +diff --git a/lldp_mand.c b/lldp_mand.c +index 943070f..b269d3f 100644 +--- a/lldp_mand.c ++++ b/lldp_mand.c +@@ -464,8 +464,9 @@ out_err: + static int mand_bld_tlv(struct mand_data *md, struct lldp_agent *agent) + { + int rc = EPERM; ++ int ifindex = get_ifidx(md->ifname); + +- if (!port_find_by_name(md->ifname)) { ++ if (!port_find_by_ifindex(ifindex)) { + rc = EEXIST; + goto out_err; + } +@@ -655,13 +656,13 @@ void mand_unregister(struct lldp_module *mod) + struct mand_data *md; + + nameidx = if_nameindex(); +- if (nameidx == NULL) { ++ if (!nameidx) { + LLDPAD_DBG("error calling if_nameindex()\n"); + return; + } + + for (p = nameidx; p->if_index != 0; p++) { +- port = port_find_by_name(p->if_name); ++ port = port_find_by_ifindex(p->if_index); + if (!port) + continue; + +diff --git a/lldp_mand_cmds.c b/lldp_mand_cmds.c +index aedb8dc..532337b 100644 +--- a/lldp_mand_cmds.c ++++ b/lldp_mand_cmds.c +@@ -78,17 +78,12 @@ static struct arg_handlers arg_handlers[] = { + static int get_mand_subtype(struct cmd *cmd, char *arg, UNUSED char *argvalue, + char *obuf, int obuf_len) + { +- struct mand_data *md; + int subtype; + char *string, arg_path[256]; + + if (cmd->cmd != cmd_gettlv) + return cmd_invalid; + +- md = mand_data(cmd->ifname, cmd->type); +- if (!md) +- return cmd_device_not_found; +- + switch (cmd->tlvid) { + case CHASSIS_ID_TLV: + snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", +@@ -183,8 +178,6 @@ static int _set_mand_subtype(struct cmd *cmd, char *arg, char *argvalue, + return cmd_invalid; + + md = mand_data(cmd->ifname, cmd->type); +- if (!md) +- return cmd_device_not_found; + + switch (cmd->tlvid) { + case CHASSIS_ID_TLV: +@@ -261,9 +254,11 @@ static int _set_mand_subtype(struct cmd *cmd, char *arg, char *argvalue, + if (test) + return cmd_success; + +- md->read_shm = 1; +- md->rebuild_chassis = 1; +- md->rebuild_portid = 1; ++ if (md) { ++ md->read_shm = 1; ++ md->rebuild_chassis = 1; ++ md->rebuild_portid = 1; ++ } + + snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, + cmd->tlvid, arg); +@@ -570,6 +565,10 @@ int get_tlvs(struct cmd *cmd, char *rbuf, int rlen) + u16 type, len; + int res; + ++ /* VDP 0.2 protocol for nearest customer bridge only */ ++ if (cmd->tlvid == (OUI_IEEE_8021Qbg << 8) ++ && cmd->type != NEAREST_CUSTOMER_BRIDGE) ++ return cmd_agent_not_supported; + if (cmd->ops & op_local) { + res = get_local_tlvs(cmd->ifname, cmd->type, &tlvs[0], &size); + if (res) +@@ -652,7 +651,6 @@ int mand_clif_cmd(UNUSED void *data, + char *rbuf, int rlen) + { + struct cmd cmd; +- struct port *port; + u8 len, version; + int ioff, roff; + int rstatus = cmd_invalid; +@@ -727,9 +725,8 @@ int mand_clif_cmd(UNUSED void *data, + (unsigned int)strlen(cmd.ifname), cmd.ifname); + roff = strlen(rbuf); + +- /* Confirm port is a lldpad managed port */ +- port = port_find_by_name(cmd.ifname); +- if (!port) { ++ /* Confirm port is a valid LLDP port */ ++ if (!get_ifidx(cmd.ifname) || !is_valid_lldp_device(cmd.ifname)) { + free(argvals); + free(args); + return cmd_device_not_found; +diff --git a/lldp_med.c b/lldp_med.c +index db83eaf..77ec20d 100644 +--- a/lldp_med.c ++++ b/lldp_med.c +@@ -686,39 +686,32 @@ out_err: + * @md: the med data struct + * + * Returns 0 for success or error code for failure +- * + */ +-static int med_bld_tlv(struct med_data *md, +- struct lldp_agent *agent) ++static int med_bld_tlv(struct med_data *md, struct lldp_agent *agent) + { +- int rc = EPERM; +- +- if (!port_find_by_name(md->ifname)) { +- rc = EEXIST; +- goto out_err; +- } ++ if (!port_find_by_ifindex(get_ifidx(md->ifname))) ++ return -EEXIST; + + /* no build if not enabled */ + if (!is_tlv_txenabled(md->ifname, agent->type, + TLVID_MED(LLDP_MED_RESERVED))) { + LLDPAD_DBG("%s:%s:LLDP-MED is not enabled\n", +- __func__, md->ifname); +- rc = 0; +- goto out_err; ++ __func__, md->ifname); ++ return 0; + } + + /* no build if enabled no devtype is given */ + if (!LLDP_MED_DEVTYPE_DEFINED(get_med_devtype(md->ifname, agent->type))) { + LLDPAD_DBG("%s:%s:LLDP-MED devtype is not defined\n", +- __func__, md->ifname); +- goto out_err; ++ __func__, md->ifname); ++ return -EPERM; + } + + /* MED Cap is always mandatory for MED */ + if (med_bld_medcaps_tlv(md, agent)) { + LLDPAD_DBG("%s:%s:MED Capabilities TLV is mandatory!\n", +- __func__, md->ifname); +- goto out_err; ++ __func__, md->ifname); ++ return -EPERM; + } + + /* MAC PHY TLV is mandatory for MED */ +@@ -726,8 +719,7 @@ static int med_bld_tlv(struct med_data *md, + TLVID_8023(LLDP_8023_MACPHY_CONFIG_STATUS))) { + LLDPAD_DBG("%s:%s MAC PHY Config is mandatory for MED\n", + __func__, md->ifname); +- rc = ENOTTY; +- goto out_err; ++ return -ENOTTY; + } + + /* Build optional and conditional ones based on device type: +@@ -757,32 +749,28 @@ static int med_bld_tlv(struct med_data *md, + * - Extended Power-via-MDI: mandatory only for + * 802.3.af PSE + * - Inventory: optional +- * + */ + if (med_bld_netpoli_tlv(md, agent)) { + LLDPAD_DBG("%s:%s:med_bld_netpoli_tlv() failed\n", +- __func__, md->ifname); +- goto out_err; ++ __func__, md->ifname); ++ return -EPERM; + } + if (med_bld_locid_tlv(md, agent)) { + LLDPAD_DBG("%s:%s:med_bld_locid_tlv() failed\n", +- __func__, md->ifname); +- goto out_err; ++ __func__, md->ifname); ++ return -EPERM; + } + if (med_bld_powvmdi_tlv(md, agent)) { + LLDPAD_DBG("%s:%s:med_bld_powvmdi_tlv() failed\n", +- __func__, md->ifname); +- goto out_err; ++ __func__, md->ifname); ++ return -EPERM; + } + if (med_bld_inventory_tlv(md, agent)) { + LLDPAD_DBG("%s:%s:med_bld_inventory_tlv() failed\n", +- __func__, md->ifname); +- goto out_err; ++ __func__, md->ifname); ++ return -EPERM; + } +- rc = 0; +- +-out_err: +- return rc; ++ return 0; + } + + /* +diff --git a/lldp_qbg_utils.c b/lldp_qbg_utils.c +deleted file mode 100644 +index 04491de..0000000 +--- a/lldp_qbg_utils.c ++++ /dev/null +@@ -1,95 +0,0 @@ +-/****************************************************************************** +- +- Implementation of ECP according to 802.1Qbg +- (c) Copyright IBM Corp. 2010, 2013 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-/* +- * This file contains common support utilities for the ECP protocols. +- */ +- +-#include +-#include +- +-#include "lldp.h" +-#include "lldp_mod.h" +-#include "messages.h" +-#include "lldp_qbg_utils.h" +- +-extern int loglvl; /* Global lldpad log level */ +-extern struct lldp_head lldp_head; +- +-/* +- * hexdump_frame - print raw evb/ecp/vdp frame +- */ +-void hexdump_frame(const char *ifname, char *txt, const unsigned char *buf, +- size_t len) +-{ +- size_t i; +- int left = 0; +- char buffer[ETH_FRAME_LEN * 3]; +- +- /* Only collect data when the loglvl ensures data printout */ +- if (LOG_DEBUG < loglvl) +- return; +- for (i = 0; i < len; i++) { +- int c; +- c = snprintf(buffer + left, sizeof buffer - left, "%02x%c", +- buf[i], !((i + 1) % 16) ? '\n' : ' '); +- if (c > 0 && (c < (int)sizeof buffer - left)) +- left += c; +- } +- LLDPAD_DBG("%s:%s %s\n%s\n", __func__, ifname, txt, buffer); +-} +- +-/* +- * Function to advertise changed variables to other modules. +- * +- * Parameters are interface name, target module id and data. +- * When sending the data, the module call back function contains the +- * module id of the sender. +- * +- * Return 0 when no addressee found or addressess found but addressee was +- * unable to handle data. +- */ +-int modules_notify(int id, int sender_id, char *ifname, void *data) +-{ +- struct lldp_module *mp = find_module_by_id(&lldp_head, id); +- int rc = 0; +- +- if (mp && mp->ops->lldp_mod_notify) +- rc = mp->ops->lldp_mod_notify(sender_id, ifname, data); +- LLDPAD_DBG("%s:%s target-id:%#x rc:%d\n", __func__, ifname, id, rc); +- return rc; +-} +- +-int vdp_uuid2str(const u8 *p, char *dst, size_t size) +-{ +- if (dst && size > VDP_UUID_STRLEN) { +- snprintf(dst, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x" +- "-%02x%02x-%02x%02x%02x%02x%02x%02x", +- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], +- p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); +- return 0; +- } +- return -1; +-} +diff --git a/lldp_rtnl.c b/lldp_rtnl.c +index 0c57e62..33b4d19 100644 +--- a/lldp_rtnl.c ++++ b/lldp_rtnl.c +@@ -46,45 +46,6 @@ + + #define NLMSG_SIZE 1024 + +-/* +- * Helper functions to construct a netlink message. +- * The functions assume the nlmsghdr.nlmsg_len is set correctly. +- */ +-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; +-} +- +-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; +-} +- +-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); +-} +- +-void mynla_put_u16(struct nlmsghdr *nlh, int type, __u16 data) +-{ +- mynla_put(nlh, type, sizeof data, &data); +-} +- +-void mynla_put_u32(struct nlmsghdr *nlh, int type, __u32 data) +-{ +- mynla_put(nlh, type, sizeof data, &data); +-} +- + typedef int rtnl_handler(struct nlmsghdr *nh, void *arg); + + /** +@@ -173,7 +134,7 @@ static ssize_t rtnl_send_linkmode(int s, int ifindex, + return send(s, &req, req.nh.nlmsg_len, 0); + } + +-static int rtnl_set_linkmode(int ifindex, const char *ifname, __u8 linkmode) ++int set_linkmode(int ifindex, const char *ifname, __u8 linkmode) + { + int s; + int rc; +@@ -301,11 +262,6 @@ int get_operstate(char *ifname) + return operstate; + } + +-int set_linkmode(const char *ifname, __u8 linkmode) +-{ +- return rtnl_set_linkmode(0, ifname, linkmode); +-} +- + int get_perm_hwaddr(const char *ifname, u8 *buf_perm, u8 *buf_san) + { + int s; +diff --git a/lldp_util.c b/lldp_util.c +index 4a1cc4a..754b0cd 100644 +--- a/lldp_util.c ++++ b/lldp_util.c +@@ -308,9 +308,17 @@ int get_src_mac_from_bond(struct port *bond_port, char *ifname, u8 *addr) + return 1; + } + ++/* ++ * Return true if the mac address is valid (non-zero and no hardware ++ * broadcast address) ++ */ + int is_valid_mac(const u8 *mac) + { +- return !!(mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5]); ++ if (0 == (mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5])) ++ return 0; ++ if (0xff == (mac[0] & mac[1] & mac[2] & mac[3] & mac[4] & mac[5])) ++ return 0; ++ return 1; + } + + int read_int(const char *path) +@@ -349,6 +357,25 @@ int get_ifflags(const char *ifname) + return flags; + } + ++int get_ifname(int ifindex, char *ifname) ++{ ++ int fd; ++ int rc; ++ struct ifreq ifr; ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ fd = get_ioctl_socket(); ++ if (fd < 0) ++ return -1; ++ ++ ifr.ifr_ifindex = ifindex; ++ rc = ioctl(fd, SIOCGIFNAME, &ifr); ++ if (rc >= 0) ++ memcpy(ifname, ifr.ifr_name, IFNAMSIZ); ++ ++ return rc; ++} ++ + int get_ifpflags(const char *ifname) + { + int fd; +@@ -1185,7 +1212,7 @@ int get_arg_val_list(char *ibuf, int ilen, int *ioff, + *ioff += arglen; + *(arglens+i) = arglen; + +- if (ilen - *ioff > 2 * (int)sizeof(argvalue_len)) { ++ if (ilen - *ioff >= 2 * (int)sizeof(argvalue_len)) { + hexstr2bin(ibuf+*ioff, (u8 *)&argvalue_len, + sizeof(argvalue_len)); + argvalue_len = ntohs(argvalue_len); +diff --git a/lldp_vdp.c b/lldp_vdp.c +deleted file mode 100644 +index 57133d1..0000000 +--- a/lldp_vdp.c ++++ /dev/null +@@ -1,1916 +0,0 @@ +-/****************************************************************************** +- +- Implementation of VDP according to IEEE 802.1Qbg +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Jens Osterkamp +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "lldp.h" +-#include "lldp_vdp.h" +-#include "lldp_vdpnl.h" +-#include "eloop.h" +-#include "lldp_evb.h" +-#include "messages.h" +-#include "config.h" +-#include "lldp_tlv.h" +-#include "lldp_vdp_cmds.h" +-#include "lldp_qbg_utils.h" +-#include "lldp_mand_clif.h" +- +-/* Define Module id. Must match with value in lldp_vdp_clif.c */ +-#define LLDP_MOD_VDP02 ((LLDP_MOD_VDP << 8) | LLDP_VDP_SUBTYPE) +- +-static const char * const vsi_responses[] = { +- [VDP_RESPONSE_SUCCESS] = "success", +- [VDP_RESPONSE_INVALID_FORMAT] = "invalid format", +- [VDP_RESPONSE_INSUFF_RESOURCES] = "insufficient resources", +- [VDP_RESPONSE_UNUSED_VTID] = "unused VTID", +- [VDP_RESPONSE_VTID_VIOLATION] = "VTID violation", +- [VDP_RESPONSE_VTID_VER_VIOLATION] = "VTID version violation", +- [VDP_RESPONSE_OUT_OF_SYNC] = "out of sync", +- [VDP_RESPONSE_UNKNOWN] = "unknown response", +- [VDP_RESPONSE_NO_RESPONSE] = "no response", +-}; +- +-const char * const vsi_states[] = { +- [VSI_UNASSOCIATED] = "VSI_UNASSOCIATED", +- [VSI_ASSOC_PROCESSING] = "VSI_ASSOC_PROCESSING", +- [VSI_ASSOCIATED] = "VSI_ASSOCIATED", +- [VSI_PREASSOC_PROCESSING] = "VSI_PREASSOC_PROCESSING", +- [VSI_PREASSOCIATED] = "VSI_PREASSOCIATED", +- [VSI_DEASSOC_PROCESSING] = "VSI_DEASSOC_PROCESSING", +- [VSI_EXIT] = "VSI_EXIT", +-}; +- +-int vdp_start_localchange_timer(struct vsi_profile *p); +-int vdp_remove_profile(struct vsi_profile *profile); +-int vdp_trigger(struct vsi_profile *profile); +- +-void vdp_trace_profile(struct vsi_profile *p) +-{ +- char instance[VDP_UUID_STRLEN + 2]; +- struct mac_vlan *mac_vlan; +- +- vdp_uuid2str(p->instance, instance, sizeof(instance)); +- +- LLDPAD_DBG("profile:%p mode:%d response:%d state:%d (%s) no_nlmsg:%d" +- " txmit:%i" +- " mgrid:%d id:%d(%#x) version:%d %s format:%d entries:%d\n", +- p, p->mode, p->response, p->state, vsi_states[p->state], +- p->no_nlmsg, p->txmit, +- p->mgrid, p->id, p->id, p->version, instance, p->format, +- p->entries); +- LIST_FOREACH(mac_vlan, &p->macvid_head, entry) { +- char macbuf[MAC_ADDR_STRLEN + 1]; +- +- mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); +- LLDPAD_DBG("profile:%p mac:%s vlan:%d qos:%d pid:%d seq:%d\n", +- p, macbuf, mac_vlan->vlan, mac_vlan->qos, +- mac_vlan->req_pid, mac_vlan->req_seq); +- } +-} +- +-struct vsi_profile *vdp_alloc_profile() +-{ +- struct vsi_profile *prof; +- +- prof = calloc(1, sizeof *prof); +- if (prof) +- LIST_INIT(&prof->macvid_head); +- return prof; +-} +- +-/* +- * vdp_remove_macvlan - remove all mac/vlan pairs in the profile +- * @profile: profile to remove +- * +- * Remove all allocated pairs on the profile. +- */ +-static void vdp_remove_macvlan(struct vsi_profile *profile) +-{ +- struct mac_vlan *p; +- +- while ((p = LIST_FIRST(&profile->macvid_head))) { +- LIST_REMOVE(p, entry); +- free(p); +- } +-} +- +-void vdp_delete_profile(struct vsi_profile *prof) +-{ +- vdp_remove_macvlan(prof); +- free(prof); +-} +- +-/* vdp_profile_equal - checks for equality of 2 profiles +- * @p1: profile 1 +- * @p2: profile 2 +- * +- * returns true if equal, false if not +- * +- * compares mgrid, id, version, instance 2 vsi profiles to find +- * out if they are equal. +- */ +-static bool vdp_profile_equal(struct vsi_profile *p1, struct vsi_profile *p2) +-{ +- if (p1->mgrid != p2->mgrid) +- return false; +- +- if (p1->id != p2->id) +- return false; +- +- if (p1->version != p2->version) +- return false; +- +- if (memcmp(p1->instance, p2->instance, 16)) +- return false; +- +- return true; +-} +- +-/* +- * vdp_find_profile - Find a profile in the list of profiles already allocated +- * +- * Returns pointer to already allocated profile in list, 0 if not. +- */ +- +-struct vsi_profile *vdp_find_profile(struct vdp_data *vd, +- struct vsi_profile *thisone) +-{ +- struct vsi_profile *p; +- +- LIST_FOREACH(p, &vd->profile_head, profile) { +- if (vdp_profile_equal(p, thisone)) +- return p; +- } +- return 0; +-} +- +-/* vdp_data - searches vdp_data in the list of modules for this port +- * @ifname: interface name to search for +- * +- * returns vdp_data on success, NULL on error +- * +- * searches the list of user_data for the VDP module user_data. +- */ +-struct vdp_data *vdp_data(char *ifname) +-{ +- struct vdp_user_data *ud; +- struct vdp_data *vd = NULL; +- +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP02); +- if (ud) { +- LIST_FOREACH(vd, &ud->head, entry) { +- if (!strncmp(ifname, vd->ifname, IFNAMSIZ)) +- return vd; +- } +- } +- return NULL; +-} +- +-/* vdp_free_tlv - free tlv in vdp_data +- * @vd: vdp_data +- * +- * no return value +- * +- * frees up tlv in vdp_data. used in vdp_free_data. +- */ +-static void vdp_free_tlv(struct vdp_data *vd) +-{ +- if (vd) { +- FREE_UNPKD_TLV(vd, vdp); +- } +-} +- +-/* vdp_free_data - frees up vdp data +- * @ud: user data structure +- * +- * no return value +- * +- * removes vd_structure from the user_data list. frees up tlv in vdp_data. +- * used in vdp_unregister. +- */ +-static void vdp_free_data(struct vdp_user_data *ud) +-{ +- struct vdp_data *vd; +- if (ud) { +- while (!LIST_EMPTY(&ud->head)) { +- vd = LIST_FIRST(&ud->head); +- LIST_REMOVE(vd, entry); +- vdp_free_tlv(vd); +- free(vd); +- } +- } +-} +- +-/* vdp_response2str - map response to string +- * @response: response received +- * +- * no return value +- * +- * maps VDP response received for a profile to human readable string for +- * printing. +- */ +-const char *vdp_response2str(int response) +-{ +- if ((response >= VDP_RESPONSE_SUCCESS) && +- (response <= VDP_RESPONSE_OUT_OF_SYNC)) +- return vsi_responses[response]; +- +- if (response == VDP_RESPONSE_NO_RESPONSE) +- return vsi_responses[VDP_RESPONSE_NO_RESPONSE]; +- +- return vsi_responses[VDP_RESPONSE_UNKNOWN]; +-} +- +-/* vdp_ack_profiles - clear ackReceived for all profiles with seqnr +- * @vd: vd for the interface +- * @seqnr: seqnr the ack has been received with +- * +- * no return value +- * +- * clear the ackReceived for all profiles which have been sent out with +- * the seqnr that we now have received the ecp ack for. +- */ +-void vdp_ack_profiles(struct vdp_data *vd, int seqnr) +-{ +- struct vsi_profile *p; +- +- LIST_FOREACH(p, &vd->profile_head, profile) { +- if (p->seqnr == seqnr) { +- p->ackReceived = false; +- p->txmit = true; +- } +- } +- +-} +- +-/* vdp_vsis - find out number of VSIs for this interface +- * @ifname: interfac name +- * +- * returns the number of VSIs +- * +- * walk through the list of VSIs and return the count. +- */ +-int vdp_vsis(char *ifname) +-{ +- struct vdp_data *vd; +- struct vsi_profile *p; +- int count = 0; +- +- vd = vdp_data(ifname); +- +- if (!vd) +- return 0; +- +- LIST_FOREACH(p, &vd->profile_head, profile) { +- count++; +- } +- +- return count; +-} +- +-/* vdp_vsis_pending - check for pending VSIs +- * @vd: vdp data for the interface +- * +- * returns the number of VSIs found +- * +- * walk through the list of VSIs and return the count. +- */ +-int vdp_vsis_pending(struct vdp_data *vd) +-{ +- struct vsi_profile *p; +- int count = 0; +- +- LIST_FOREACH(p, &vd->profile_head, profile) { +- if (p->localChange && (p->txmit == false)) +- count++; +- } +- +- return count; +-} +- +-/* vdp_somethingChangedLocal - set flag if profile has changed +- * @profile: profile to set the flag for +- * @flag: set the flag to true or false +- * +- * no return value +- * +- * set the localChange flag with a mode to indicate a profile has changed. +- * used next time when a ecpdu with profiles is sent out. +- */ +-void vdp_somethingChangedLocal(struct vsi_profile *profile, bool flag) +-{ +- LLDPAD_DBG("%s: setting profile->localChange to %s\n", +- __func__, (flag == true) ? "true" : "false"); +- +- profile->localChange = flag; +- +- if (flag == true) +- vdp_start_localchange_timer(profile); +-} +- +-/* vdp_keepaliveTimer_expired - checks for expired ack timer +- * @profile: profile to be checked +- * +- * returns true or false +- * +- * returns value of profile->keepaliveTimerExpired, true if ack timer has +- * expired, * false otherwise. +- */ +-static bool vdp_keepaliveTimer_expired(struct vsi_profile *profile) +-{ +- return (profile->keepaliveTimer == 0); +-} +- +-/* vdp_ackTimer_expired - checks for expired ack timer +- * @profile: profile to be checked +- * +- * returns true or false +- * +- * returns value of profile->ackTimerExpired, true if ack timer has expired, +- * false otherwise. +- */ +-static bool vdp_ackTimer_expired(struct vsi_profile *profile) +-{ +- return (profile->ackTimer == 0); +-} +- +-/* vdp_localchange_handler - triggers in case of vdp_ack or on vdp +- * localchange +- * @eloop_data: data structure of event loop +- * @user_ctx: user context, vdp_data here +- * +- * no return value +- * +- * called from vdp_somethingchangedlocal or vdp_ack_profiles when a change is +- * pending. Calls the VDP station state machine. This detour is taken +- * to not having to call the vdp code from the ecp state machine. Instead, we +- * return to the event loop, giving other code a chance to do work. +- */ +-void vdp_localchange_handler(UNUSED void *eloop_data, void *user_ctx) +-{ +- struct vsi_profile *p; +- +- p = (struct vsi_profile *) user_ctx; +- +- if ((p->ackReceived) || (p->localChange)) { +- LLDPAD_DBG("%s: p->localChange %i p->ackReceived %i\n", +- __func__, p->localChange, p->ackReceived); +- vdp_vsi_sm_station(p); +- } +-} +- +-/* +- * vdp_stop - cancel the VDP localchange timer +- * +- * returns 0 on success, -1 on error +- * +- * cancels the VPP localchange timer when a profile has been deleted. +- */ +-int vdp_stop_localchange_timer(struct vsi_profile *p) +-{ +- return eloop_cancel_timeout(vdp_localchange_handler, NULL, (void *) p); +-} +- +-/* vdp_start_localchange_timer - starts the VDP localchange timer +- * @vd: vdp_data for the interface +- * +- * returns 0 on success, -1 on error +- * +- * starts the VPP localchange timer when a localchange has been signaled from +- * the VDP state machine. +- */ +-int vdp_start_localchange_timer(struct vsi_profile *p) +-{ +- unsigned int usecs; +- +- usecs = VDP_LOCALCHANGE_TIMEOUT; +- +- return eloop_register_timeout(0, usecs, vdp_localchange_handler, NULL, +- (void *) p); +-} +- +-/* vdp_ack_timeout_handler - handles the ack timer expiry +- * @eloop_data: data structure of event loop +- * @user_ctx: user context, vdp_data here +- * +- * no return value +- * +- * called when the VDP ack timer for a profile has expired. +- * Calls the VDP station state machine for the profile. +- */ +-void vdp_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) +-{ +- struct vsi_profile *p = (struct vsi_profile *) user_ctx; +- +- if (p->ackTimer > 0) +- p->ackTimer -= VDP_ACK_TIMER_DEFAULT; +- +- if (vdp_ackTimer_expired(p)) { +- LLDPAD_DBG("%s: profile %#02x vdp_ackTimer_expired %i" +- " p->ackReceived %i\n", __func__, p->instance[15], +- vdp_ackTimer_expired(p), p->ackReceived); +- vdp_vsi_sm_station(p); +- } +-} +- +-/* vdp_start_ack_timer - starts the VDP profile ack timer +- * @profile: vsi_profile +- * +- * returns 0 on success, -1 on error +- * +- * starts the VDP profile ack timer when a profile has been handed to ecp for +- * transmission. +- */ +-static int vdp_start_ackTimer(struct vsi_profile *profile) +-{ +- unsigned int usecs; +- +- usecs = VDP_ACK_TIMER_DEFAULT; +- +- profile->ackTimer = VDP_ACK_TIMER_DEFAULT; +- +- LLDPAD_DBG("%s: %s starting ack timer for %#02x (%i)\n", +- __func__, profile->port->ifname, +- profile->instance[15], profile->ackTimer); +- +- return eloop_register_timeout(0, usecs, vdp_ack_timeout_handler, NULL, +- (void *)profile); +-} +- +-/* vdp_stop_ackTimer - stops the VDP profile ack timer +- * @vd: vdp_data for the interface +- * +- * returns the number of removed handlers +- * +- * stops the VDP tck imer. Used e.g. when the host interface goes down. +- */ +-static int vdp_stop_ackTimer(struct vsi_profile *profile) +-{ +- LLDPAD_DBG("%s: %s stopping ack timer for %#02x (%i)\n", __func__, +- profile->port->ifname, profile->instance[15], +- profile->ackTimer); +- +- return eloop_cancel_timeout(vdp_ack_timeout_handler, NULL, +- (void *)profile); +-} +- +-/* vdp_keepalive_timeout_handler - handles the keepalive timer expiry +- * @eloop_data: data structure of event loop +- * @user_ctx: user context, vdp_data here +- * +- * no return value +- * +- * called when the VDP keepalive timer for a profile has expired. +- * Calls the VDP station state machine for the profile. +- */ +-void vdp_keepalive_timeout_handler(UNUSED void *eloop_data, void *user_ctx) +-{ +- struct vsi_profile *p = (struct vsi_profile *) user_ctx; +- +- if (p->keepaliveTimer > 0) +- p->keepaliveTimer -= VDP_KEEPALIVE_TIMER_DEFAULT; +- +- if (vdp_keepaliveTimer_expired(p)) { +- LLDPAD_DBG("%s: profile %#02x vdp_keepaliveTimer_expired %i" +- " p->ackReceived %i p->ackReceived %i\n", __func__, +- p->instance[15], vdp_keepaliveTimer_expired(p), +- p->ackReceived, p->ackReceived); +- vdp_vsi_sm_station(p); +- } +-} +- +-/* vdp_start_keepalive_timer - starts the VDP profile keepalive timer +- * @vd: vdp_data for the interface +- * +- * returns 0 on success, -1 on error +- * +- * starts the VDP profile keepalive timer when a profile has been handed to +- * ecp for transmission. +- */ +-static int vdp_start_keepaliveTimer(struct vsi_profile *profile) +-{ +- unsigned int usecs; +- +- usecs = VDP_KEEPALIVE_TIMER_DEFAULT; +- +- profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; +- +- LLDPAD_DBG("%s: %s starting keepalive timer for %#02x (%i)\n", +- __func__, profile->port->ifname, profile->instance[15], +- profile->keepaliveTimer); +- +- return eloop_register_timeout(0, usecs, vdp_keepalive_timeout_handler, +- NULL, (void *) profile); +-} +- +-/* vdp_stop_keepalive_timer - stops the VDP profile keepalive timer +- * @vd: vdp_data for the interface +- * +- * returns the number of removed handlers +- * +- * stops the VDP tck imer. Used e.g. when the host interface goes down. +- */ +-static int vdp_stop_keepaliveTimer(struct vsi_profile *profile) +-{ +- profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_STOPPED; +- +- LLDPAD_DBG("%s: %s stopping keepalive timer for %#02x (%i)\n", +- __func__, profile->port->ifname, +- profile->instance[15], profile->keepaliveTimer); +- +- return eloop_cancel_timeout(vdp_keepalive_timeout_handler, NULL, +- (void *) profile); +-} +- +-static bool vdp_vsi_negative_response(struct vsi_profile *profile) +-{ +- if ((profile->response > 0) && (profile->response < 255)) +- return true; +- else +- return false; +-} +- +-/* vdp_vsi_change_station_state - changes the VDP station sm state +- * @profile: profile to process +- * @newstate: new state for the sm +- * +- * no return value +- * +- * actually changes the state of the profile +- */ +-void vdp_vsi_change_station_state(struct vsi_profile *profile, u8 newstate) +-{ +- switch(newstate) { +- case VSI_UNASSOCIATED: +- break; +- case VSI_ASSOC_PROCESSING: +- assert((profile->state == VSI_PREASSOCIATED) || +- (profile->state == VSI_ASSOCIATED) || +- (profile->state == VSI_UNASSOCIATED)); +- break; +- case VSI_ASSOCIATED: +- assert((profile->state == VSI_ASSOC_PROCESSING) || +- (profile->state == VSI_ASSOCIATED)); +- break; +- case VSI_PREASSOC_PROCESSING: +- assert((profile->state == VSI_PREASSOCIATED) || +- (profile->state == VSI_ASSOCIATED) || +- (profile->state == VSI_UNASSOCIATED)); +- break; +- case VSI_PREASSOCIATED: +- assert((profile->state == VSI_PREASSOC_PROCESSING) || +- (profile->state == VSI_PREASSOCIATED)); +- break; +- case VSI_DEASSOC_PROCESSING: +- assert((profile->state == VSI_PREASSOCIATED) || +- (profile->state == VSI_UNASSOCIATED) || +- (profile->state == VSI_ASSOCIATED)); +- break; +- case VSI_EXIT: +- assert((profile->state == VSI_ASSOC_PROCESSING) || +- (profile->state == VSI_PREASSOC_PROCESSING) || +- (profile->state == VSI_DEASSOC_PROCESSING) || +- (profile->state == VSI_PREASSOCIATED) || +- (profile->state == VSI_ASSOCIATED)); +- break; +- default: +- LLDPAD_ERR("ERROR: The VDP station State Machine is broken\n"); +- break; +- } +- +- LLDPAD_DBG("%s: %s state change %s -> %s\n", __func__, +- profile->port->ifname, vsi_states[profile->state], +- vsi_states[newstate]); +- +- profile->state = newstate; +-} +- +-/* vdp_vsi_set_station_state - sets the vdp sm station state +- * @profile: profile to process +- * +- * returns true or false +- * +- * switches the state machine to the next state depending on the input +- * variables. returns true or false depending on wether the state machine +- * can be run again with the new state or can stop at the current state. +- */ +-static bool vdp_vsi_set_station_state(struct vsi_profile *profile) +-{ +- switch(profile->state) { +- case VSI_UNASSOCIATED: +- if ((profile->mode == VDP_MODE_PREASSOCIATE) || +- (profile->mode == VDP_MODE_PREASSOCIATE_WITH_RR)) { +- vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); +- vdp_somethingChangedLocal(profile, true); +- return true; +- } else if (profile->mode == VDP_MODE_ASSOCIATE) { +- vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); +- vdp_somethingChangedLocal(profile, true); +- return true; +- } else if (profile->mode == VDP_MODE_DEASSOCIATE) { +- vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); +- vdp_somethingChangedLocal(profile, true); +- return true; +- } +- return false; +- case VSI_ASSOC_PROCESSING: +- if (profile->ackReceived) { +- if (profile->response == 0) +- vdp_vsi_change_station_state(profile, VSI_ASSOCIATED); +- else +- vdp_vsi_change_station_state(profile, VSI_EXIT); +- return true; +- } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) { +- vdp_vsi_change_station_state(profile, VSI_EXIT); +- return true; +- } +- return false; +- case VSI_ASSOCIATED: +- if (profile->mode == VDP_MODE_PREASSOCIATE) { +- vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); +- return true; +- } else if (profile->mode == VDP_MODE_DEASSOCIATE) { +- vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); +- return true; +- } else if (vdp_vsi_negative_response(profile)) { +- vdp_vsi_change_station_state(profile, VSI_EXIT); +- return true; +- } else if (vdp_keepaliveTimer_expired(profile)) { +- vdp_stop_keepaliveTimer(profile); +- vdp_somethingChangedLocal(profile, true); +- vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); +- return true; +- } +- return false; +- case VSI_PREASSOC_PROCESSING: +- LLDPAD_DBG("%s: profile->ackReceived %i, vdp_ackTimer %i\n", +- __func__, profile->ackReceived, profile->ackTimer); +- if (profile->ackReceived) { +- if (profile->response == 0) +- vdp_vsi_change_station_state(profile, VSI_PREASSOCIATED); +- else +- vdp_vsi_change_station_state(profile, VSI_EXIT); +- return true; +- } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) { +- vdp_vsi_change_station_state(profile, VSI_EXIT); +- return true; +- } +- return false; +- case VSI_PREASSOCIATED: +- if (profile->mode == VDP_MODE_ASSOCIATE) { +- vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); +- return true; +- } else if (profile->mode == VDP_MODE_DEASSOCIATE) { +- vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); +- return true; +- } else if (vdp_keepaliveTimer_expired(profile)) { +- vdp_stop_keepaliveTimer(profile); +- vdp_somethingChangedLocal(profile, true); +- vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); +- return true; +- } +- return false; +- case VSI_DEASSOC_PROCESSING: +- if ((profile->ackReceived) || vdp_ackTimer_expired(profile) || +- profile->remoteChange) { +- vdp_vsi_change_station_state(profile, VSI_EXIT); +- return true; +- } +- return false; +- case VSI_EXIT: +- return false; +- default: +- LLDPAD_ERR("%s: VSI state machine in invalid state %d\n", +- profile->port->ifname, profile->state); +- return false; +- } +-} +- +-/* vdp_vsi_sm_station - state machine for vdp station role +- * @profile: profile for which the state is processed +- * +- * no return value +- * +- * runs the state machine for the station role of VDP. +- */ +-void vdp_vsi_sm_station(struct vsi_profile *profile) +-{ +- struct vdp_data *vd = vdp_data(profile->port->ifname); +- int bye = 0; +- +- vdp_vsi_set_station_state(profile); +- do { +- LLDPAD_DBG("%s: %s station for %#02x - %s\n", +- __func__, profile->port->ifname, +- profile->instance[15], vsi_states[profile->state]); +- +- switch(profile->state) { +- case VSI_UNASSOCIATED: +- break; +- case VSI_ASSOC_PROCESSING: +- vdp_stop_keepaliveTimer(profile); +- profile->response = VDP_RESPONSE_NO_RESPONSE; +- if (profile->localChange) { +- ecp_somethingChangedLocal(vd, true); +- profile->ackReceived = false; +- vdp_start_ackTimer(profile); +- } +- break; +- case VSI_ASSOCIATED: +- profile->ackReceived = false; +- vdp_somethingChangedLocal(profile, false); +- vdp_stop_ackTimer(profile); +- vdp_start_keepaliveTimer(profile); +- break; +- case VSI_PREASSOC_PROCESSING: +- vdp_stop_keepaliveTimer(profile); +- profile->response = VDP_RESPONSE_NO_RESPONSE; +- if (profile->localChange) { +- profile->ackReceived = false; +- ecp_somethingChangedLocal(vd, true); +- vdp_start_ackTimer(profile); +- } +- break; +- case VSI_PREASSOCIATED: +- profile->ackReceived = false; +- vdp_somethingChangedLocal(profile, false); +- vdp_stop_ackTimer(profile); +- vdp_start_keepaliveTimer(profile); +- break; +- case VSI_DEASSOC_PROCESSING: +- profile->ackReceived = false; +- vdp_stop_keepaliveTimer(profile); +- profile->response = VDP_RESPONSE_NO_RESPONSE; +- if (profile->localChange) { +- profile->ackReceived = false; +- ecp_somethingChangedLocal(vd, true); +- vdp_start_ackTimer(profile); +- } +- break; +- case VSI_EXIT: +- if (profile->no_nlmsg && !profile->ackReceived && +- vdp_ackTimer_expired(profile)) +- bye = 1; +- vdp_stop_ackTimer(profile); +- vdp_stop_keepaliveTimer(profile); +- vdp_stop_localchange_timer(profile); +- if (bye) +- vdp_remove_profile(profile); +- else +- vdp_trigger(profile); +- break; +- default: +- LLDPAD_ERR("%s: ERROR VSI state machine in invalid state %d\n", +- vd->ifname, profile->state); +- } +- } while (vdp_vsi_set_station_state(profile) == true); +- +-} +- +-/* vdp_advance_sm - advance state machine after update from switch +- * +- * no return value +- */ +-void vdp_advance_sm(struct vdp_data *vd) +-{ +- struct vsi_profile *p; +- +- LIST_FOREACH(p, &vd->profile_head, profile) { +- LLDPAD_DBG("%s: %s station for %#02x - %s ackReceived %i\n", +- __func__, p->port->ifname, +- p->instance[15], vsi_states[p->state], +- p->ackReceived); +- if (p->ackReceived) { +- vdp_vsi_sm_station(p); +- p->ackReceived = false; +- } +- } +-} +- +-/* vdp_vsi_change_bridge_state - changes the VDP bridge sm state +- * @profile: profile to process +- * @newstate: new state for the sm +- * +- * no return value +- * +- * actually changes the state of the profile +- */ +-static void vdp_vsi_change_bridge_state(struct vsi_profile *profile, +- u8 newstate) +-{ +- switch(newstate) { +- case VSI_UNASSOCIATED: +- break; +- case VSI_ASSOC_PROCESSING: +- assert((profile->state == VSI_UNASSOCIATED) || +- (profile->state == VSI_PREASSOCIATED) || +- (profile->state == VSI_ASSOCIATED)); +- break; +- case VSI_ASSOCIATED: +- assert(profile->state == VSI_ASSOC_PROCESSING); +- break; +- case VSI_PREASSOC_PROCESSING: +- assert((profile->state == VSI_UNASSOCIATED) || +- (profile->state == VSI_PREASSOCIATED) || +- (profile->state == VSI_ASSOCIATED)); +- break; +- case VSI_PREASSOCIATED: +- assert(profile->state == VSI_PREASSOC_PROCESSING); +- break; +- case VSI_DEASSOC_PROCESSING: +- assert((profile->state == VSI_UNASSOCIATED) || +- (profile->state == VSI_PREASSOCIATED) || +- (profile->state == VSI_ASSOCIATED)); +- break; +- case VSI_EXIT: +- assert((profile->state == VSI_DEASSOC_PROCESSING) || +- (profile->state == VSI_PREASSOC_PROCESSING) || +- (profile->state == VSI_ASSOC_PROCESSING)); +- break; +- default: +- LLDPAD_ERR("ERROR: The VDP bridge State Machine is broken\n"); +- break; +- } +- profile->state = newstate; +-} +- +-/* vdp_vsi_set_bridge_state - sets the vdp sm bridge state +- * @profile: profile to process +- * +- * returns true or false +- * +- * switches the state machine to the next state depending on the input +- * variables. returns true or false depending on wether the state machine +- * can be run again with the new state or can stop at the current state. +- */ +-static bool vdp_vsi_set_bridge_state(struct vsi_profile *profile) +-{ +- switch(profile->state) { +- case VSI_UNASSOCIATED: +- if ((profile->mode == VDP_MODE_DEASSOCIATE)) /* || (INACTIVE)) */ { +- vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); +- return true; +- } else if (profile->mode == VDP_MODE_ASSOCIATE) { +- vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); +- return true; +- } else if (profile->mode == VDP_MODE_PREASSOCIATE) { +- vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); +- return true; +- } +- return false; +- case VSI_ASSOC_PROCESSING: +- /* TODO: handle error case +- if (!vsiError) || +- (vsiError && vsiState == Assoc) { +- */ +- if (profile->mode == VDP_MODE_ASSOCIATE) { +- vdp_vsi_change_bridge_state(profile, VSI_ASSOCIATED); +- return true; +- } +- return false; +- case VSI_ASSOCIATED: +- if (profile->mode == VDP_MODE_ASSOCIATE) /* || ( INACTIVE )*/ { +- vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); +- return true; +- } else if (profile->mode == VDP_MODE_PREASSOCIATE) { +- vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); +- return true; +- } else if (profile->mode == VDP_MODE_ASSOCIATE) { +- vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); +- return true; +- } +- return false; +- case VSI_PREASSOC_PROCESSING: +- if (profile->response != VDP_RESPONSE_SUCCESS) { +- vdp_vsi_change_bridge_state(profile, VSI_EXIT); +- return true; +- } +- vdp_vsi_change_bridge_state(profile, VSI_PREASSOCIATED); +- return false; +- case VSI_PREASSOCIATED: +- if (profile->mode == VDP_MODE_ASSOCIATE) { +- vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); +- return true; +- } else if (profile->mode == VDP_MODE_DEASSOCIATE ) { +- vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); +- return true; +- } else if (profile->mode == VDP_MODE_PREASSOCIATE ) { +- vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); +- return true; +- } +- return false; +- case VSI_DEASSOC_PROCESSING: +- vdp_vsi_change_bridge_state(profile, VSI_EXIT); +- return false; +- case VSI_EXIT: +- return false; +- default: +- LLDPAD_ERR("%s: ERROR VSI state machine (bridge) in invalid state %d\n", +- profile->port->ifname, profile->state); +- return false; +- } +-} +- +-/* vdp_vsi_sm_bridge - state machine for vdp bridge role +- * @profile: profile for which the state is processed +- * +- * no return value +- * +- * runs the state machine for the bridge role of VDP. +- */ +-static void vdp_vsi_sm_bridge(struct vsi_profile *profile) +-{ +- struct vdp_data *vd = vdp_data(profile->port->ifname); +- +- vdp_vsi_set_bridge_state(profile); +- do { +- LLDPAD_DBG("%s: %s bridge - %s\n", __func__, +- profile->port->ifname, vsi_states[profile->state]); +- switch(profile->state) { +- case VSI_UNASSOCIATED: +- break; +- case VSI_ASSOC_PROCESSING: +- /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate); +- * if (vsiError) +- * txTLV(Assoc NACK) +- * else +- * txTLV(Assoc ACK) +- */ +- break; +- case VSI_ASSOCIATED: +- break; +- case VSI_PREASSOC_PROCESSING: +- /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate); +- * if (vsiError) +- * txTLV(PreAssoc NACK) +- * else +- * txTLV(PreAssoc ACK) +- */ +- /* for now, we always succeed */ +- profile->response = VDP_RESPONSE_SUCCESS; +- ecp_rx_send_ack_frame(vd); +- break; +- case VSI_PREASSOCIATED: +- LLDPAD_DBG("%s: %s\n", __func__, profile->port->ifname); +- break; +- case VSI_DEASSOC_PROCESSING: +- /* TODO: txTLV(DeAssoc ACK) */ +- break; +- case VSI_EXIT: +- vdp_remove_profile(profile); +- break; +- default: +- LLDPAD_ERR("%s: ERROR VSI state machine in invalid state %d\n", +- vd->ifname, profile->state); +- } +- } while (vdp_vsi_set_bridge_state(profile) == true); +- +-} +- +-/* +- * vdp_validate_tlv - validates vsi tlvs +- * @vdp: decoded vsi tlv +- * +- * Returns 0 on success, 1 on error +- * +- * checks the contents of an already decoded vsi tlv for inconsistencies +- */ +-static int vdp_validate_tlv(struct tlv_info_vdp *vdp, struct unpacked_tlv *tlv) +-{ +- int pairs = (tlv->length - sizeof *vdp) / sizeof(struct mac_vlan_p); +- +- if (ntoh24(vdp->oui) != OUI_IEEE_8021Qbg) { +- LLDPAD_DBG("vdp->oui %#06x\n", ntoh24(vdp->oui)); +- goto out_err; +- } +- +- if (vdp->sub != LLDP_VDP_SUBTYPE) { +- LLDPAD_DBG("vdp->sub %#02x\n", vdp->sub); +- goto out_err; +- } +- +- if (vdp->mode > VDP_MODE_DEASSOCIATE) { +- LLDPAD_DBG("unknown mode %#02x in vsi tlv\n", vdp->mode); +- goto out_err; +- } +- +- if (vdp->response > VDP_RESPONSE_OUT_OF_SYNC) { +- LLDPAD_DBG("unknown response %#02x\n", vdp->response); +- goto out_err; +- } +- +- if (vdp->format != VDP_FILTER_INFO_FORMAT_MACVID) { +- LLDPAD_DBG("unknown format %#02x in vsi tlv\n", vdp->format); +- goto out_err; +- } +- +- if (ntohs(vdp->entries) < 1) { +- LLDPAD_DBG("invalid # of entries %#02x in vsi tlv\n", +- ntohs(vdp->entries)); +- goto out_err; +- } +- +- /* Check for number of entries of MAC,VLAN pairs */ +- if (ntohs(vdp->entries) != pairs) { +- LLDPAD_DBG("mismatching # of entries %#x/%#x in vsi tlv\n", +- ntohs(vdp->entries), pairs); +- goto out_err; +- } +- return 0; +- +-out_err: +- return 1; +-} +- +-/* +- * Create a VSI profile structure from switch response. +- */ +-static void make_profile(struct vsi_profile *new, struct tlv_info_vdp *vdp, +- struct unpacked_tlv *tlv) +-{ +- int i; +- u8 *pos = tlv->info + sizeof *vdp; +- +- new->mode = vdp->mode; +- new->response = vdp->response; +- new->mgrid = vdp->mgrid; +- new->id = ntoh24(vdp->id); +- new->version = vdp->version; +- memcpy(&new->instance, &vdp->instance, sizeof new->instance); +- new->format = vdp->format; +- new->entries = ntohs(vdp->entries); +- LLDPAD_DBG("%s: MAC/VLAN filter info format %u, # of entries %u\n", +- __func__, new->format, new->entries); +- +- /* Add MAC,VLAN to list */ +- for (i = 0; i < new->entries; ++i) { +- struct mac_vlan *mac_vlan = calloc(1, sizeof(struct mac_vlan)); +- u16 vlan; +- char macbuf[MAC_ADDR_STRLEN + 1]; +- +- if (!mac_vlan) { +- new->entries = i; +- return; +- } +- memcpy(&mac_vlan->mac, pos, ETH_ALEN); +- pos += ETH_ALEN; +- mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); +- memcpy(&vlan, pos, 2); +- pos += 2; +- mac_vlan->vlan = ntohs(vlan); +- LLDPAD_DBG("%s: mac %s vlan %d\n", __func__, macbuf, +- mac_vlan->vlan); +- LIST_INSERT_HEAD(&new->macvid_head, mac_vlan, entry); +- } +-} +- +-/* +- * vdp_indicate - receive VSI TLVs from ECP +- * @port: the port on which the tlv was received +- * @tlv: the unpacked tlv to receive +- * +- * Returns 0 on success +- * +- * receives a vsi tlv and creates a profile. Take appropriate action +- * depending on the role of the (receive) port +- */ +-int vdp_indicate(struct vdp_data *vd, struct unpacked_tlv *tlv) +-{ +- struct tlv_info_vdp vdp; +- struct vsi_profile *p, *profile; +- struct port *port = port_find_by_name(vd->ifname); +- +- LLDPAD_DBG("%s: indicating vdp of length %u (%zu) for %s\n", +- __func__, tlv->length, sizeof(struct tlv_info_vdp), +- vd->ifname); +- +- if (!port) { +- LLDPAD_ERR("%s: port not found for %s\n", __func__, +- vd->ifname); +- goto out_err; +- } +- +- memset(&vdp, 0, sizeof vdp); +- /* copy only vdp header w/o list of mac/vlan/groupid pairs */ +- memcpy(&vdp, tlv->info, sizeof vdp); +- +- if (vdp_validate_tlv(&vdp, tlv)) { +- LLDPAD_ERR("%s: invalid TLV received\n", __func__); +- goto out_err; +- } +- +- profile = vdp_alloc_profile(); +- +- if (!profile) { +- LLDPAD_ERR("%s: unable to allocate profile\n", __func__); +- goto out_err; +- } +- make_profile(profile, &vdp, tlv); +- +- profile->port = port; +- +- if (vd->role == VDP_ROLE_STATION) { +- /* do we have the profile already ? */ +- p = vdp_find_profile(vd, profile); +- +- if (p) { +- LLDPAD_DBG("%s: station profile found localChange %i " +- "ackReceived %i no_nlmsg:%d\n", +- __func__, p->localChange, p->ackReceived, +- p->no_nlmsg); +- +- if (profile->mode == VDP_MODE_DEASSOCIATE && +- (p->response == VDP_RESPONSE_NO_RESPONSE || +- p->response == VDP_RESPONSE_SUCCESS) && +- p->mode == VDP_MODE_PREASSOCIATE) { +- LLDPAD_DBG("%s: ignore dis-associate request " +- "in pre-association\n", __func__); +- vdp_delete_profile(profile); +- return 0; +- } +- +- p->ackReceived = true; +- p->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; +- if (profile->mode != p->mode) { +- p->mode = profile->mode; +- p->remoteChange = true; +- if (profile->mode == VDP_MODE_DEASSOCIATE) +- p->no_nlmsg = 0; +- } else +- p->remoteChange = false; +- p->response = profile->response; +- LLDPAD_DBG("%s: remoteChange %i no_nlmsg %d mode %d\n", +- __func__, p->remoteChange, p->no_nlmsg, +- p->mode); +- if (vdp_vsi_negative_response(p)) +- p->mode = VDP_MODE_DEASSOCIATE; +- +- LLDPAD_DBG("%s: profile response: %s (%i) " +- "for profile %#02x at state %s\n", +- __func__, +- vdp_response2str(p->response), +- p->response, p->instance[15], +- vsi_states[p->state]); +- } else { +- LLDPAD_DBG("%s: station profile not found\n", __func__); +- } +- vdp_delete_profile(profile); +- } +- +- if (vd->role == VDP_ROLE_BRIDGE) { +- /* do we have the profile already ? */ +- p = vdp_find_profile(vd, profile); +- +- if (p) { +- LLDPAD_DBG("%s: bridge profile found\n", __func__); +- vdp_delete_profile(profile); +- } else { +- LLDPAD_DBG("%s: bridge profile not found\n", __func__); +- /* put it in the list */ +- profile->state = VSI_UNASSOCIATED; +- LIST_INSERT_HEAD(&vd->profile_head, profile, profile); +- } +- +- vdp_vsi_sm_bridge(profile); +- } +- +- return 0; +- +-out_err: +- return 1; +- +-} +- +-/* +- * vdp_bld_vsi_tlv - build the VDP VSI TLV +- * @vd: vdp_data structure for this port +- * @profile: profile the vsi tlv is created from +- * +- * Returns 0 on success, ENOMEM otherwise +- * +- * creates a vdp structure from an existing profile +- */ +-static int vdp_bld_vsi_tlv(struct vdp_data *vd, struct vsi_profile *profile) +-{ +- struct mac_vlan *mv; +- struct mac_vlan_p *mv_p; +- struct tlv_info_vdp *vdp; +- int rc = 0; +- struct unpacked_tlv *tlv = NULL; +- int size = sizeof(struct tlv_info_vdp) + +- profile->entries * sizeof(struct mac_vlan_p); +- +- vdp = malloc(size); +- +- if (!vdp) { +- LLDPAD_DBG("%s: unable to allocate memory for VDP TLV\n", +- __func__); +- rc = ENOMEM; +- goto out_err; +- } +- +- memset(vdp, 0, size); +- +- hton24(vdp->oui, OUI_IEEE_8021Qbg); +- vdp->sub = LLDP_VDP_SUBTYPE; +- vdp->mode = profile->mode; +- vdp->response = 0; +- vdp->mgrid = profile->mgrid; +- hton24(vdp->id, profile->id); +- vdp->version = profile->version; +- memcpy(&vdp->instance, &profile->instance, 16); +- vdp->format = VDP_FILTER_INFO_FORMAT_MACVID; +- vdp->entries = htons(profile->entries); +- +- mv_p = (struct mac_vlan_p *)(vdp + 1); +- +- LIST_FOREACH(mv, &profile->macvid_head, entry) { +- memcpy(mv_p->mac, mv->mac, MAC_ADDR_LEN); +- mv_p->vlan = htons(mv->vlan); +- mv_p++; +- } +- +- tlv = create_tlv(); +- if (!tlv) { +- rc = ENOMEM; +- goto out_free; +- } +- +- tlv->type = ORG_SPECIFIC_TLV; +- tlv->length = size; +- tlv->info = (u8 *)malloc(tlv->length); +- if(!tlv->info) { +- free(tlv); +- tlv = NULL; +- rc = ENOMEM; +- goto out_free; +- } +- +- FREE_UNPKD_TLV(vd, vdp); +- +- memcpy(tlv->info, vdp, tlv->length); +- +- vd->vdp = tlv; +- +-out_free: +- free(vdp); +- +-out_err: +- return rc; +- +-} +- +-/* vdp_bld_tlv - builds a tlv from a profile +- * @vd: vdp_data structure for this port +- * @profile: profile the vsi tlv is created from +- * +- * returns 0 on success, != 0 on error +- * +- * wrapper function around vdp_bld_vsi_tlv. adds some checks and calls +- * vdp_bld_vsi_tlv. +-*/ +- +-static int vdp_bld_tlv(struct vdp_data *vd, struct vsi_profile *profile) +-{ +- int rc = 0; +- +- if (!port_find_by_name(vd->ifname)) { +- rc = EEXIST; +- goto out_err; +- } +- +- if (vdp_bld_vsi_tlv(vd, profile)) { +- LLDPAD_ERR("%s: %s vdp_bld_vsi_tlv() failed\n", +- __func__, vd->ifname); +- rc = EINVAL; +- goto out_err; +- } +- +-out_err: +- return rc; +-} +- +-/* vdp_gettlv - get the tlv for a profile +- * @port: the port on which the tlv was received +- * @profile: profile the vsi tlv is created from +- * +- * returns 0 on success +- * +- * this is the interface function called from ecp_build_ECPDU. It returns the +- * packed tlv for a profile. +- */ +-struct packed_tlv *vdp_gettlv(struct vdp_data *vd, struct vsi_profile *profile) +-{ +- int size; +- struct packed_tlv *ptlv = NULL; +- +- /* frees the unpacked_tlv in vdp_data +- * also done in vdp_bld_vsi_tlv */ +- vdp_free_tlv(vd); +- +- if (vdp_bld_tlv(vd, profile)) { +- LLDPAD_ERR("%s: %s vdp_bld_tlv failed\n", +- __func__, vd->ifname); +- goto out_err; +- } +- +- size = TLVSIZE(vd->vdp); +- +- if (!size) { +- LLDPAD_ERR("%s: size %i of unpacked_tlv not correct\n", +- __func__, size); +- goto out_err; +- } +- +- ptlv = create_ptlv(); +- if (!ptlv) +- goto out_err; +- +- ptlv->tlv = malloc(size); +- if (!ptlv->tlv) +- goto out_free; +- +- ptlv->size = 0; +- PACK_TLV_AFTER(vd->vdp, ptlv, size, out_free); +- +- return ptlv; +- +-out_free: +- ptlv = free_pkd_tlv(ptlv); +-out_err: +- LLDPAD_ERR("%s: %s failed\n", __func__, vd->ifname); +- return NULL; +-} +- +-/* vdp_macvlan_equal - checks for equality of 2 mac/vlan pairs +- * @mv1: mac/vlan pair 1 +- * @mv2: mac/vlan pair 2 +- * +- * returns true if equal, false if not +- * +- * compares mac address and vlan if they are equal. +- */ +-bool vdp_macvlan_equal(struct mac_vlan *mv1, struct mac_vlan *mv2) +-{ +- if (memcmp(mv1->mac, mv2->mac, MAC_ADDR_LEN)) +- return false; +- +- if (mv1->vlan != mv2->vlan) +- return false; +- +- return true; +-} +- +-/* +- * Check if the current profile already has this entry. If so take over +- * PID and other fields. If not add this MAC,VLAN to our list. +- * +- * Returns 1 it the entry already exist, 0 if not. +- */ +-static int have_macvlan(struct vsi_profile *p1, struct mac_vlan *new) +-{ +- struct mac_vlan *mv1; +- +- LIST_FOREACH(mv1, &p1->macvid_head, entry) +- if (vdp_macvlan_equal(mv1, new) == true) { +- mv1->req_pid = new->req_pid; +- mv1->req_seq = new->req_seq; +- mv1->qos = new->qos; +- return 1; +- } +- LIST_INSERT_HEAD(&p1->macvid_head, new, entry); +- p1->entries++; +- return 0; +-} +- +-/* vdp_takeover_macvlans - take over macvlan pairs from p2 into p1 +- * @p1: profile 1 +- * @p2: profile 2 +- * +- * returns number of mac/vlan pairs taken over +- * +- * loops over all mac/vlan pairs in profile 2 and looks for them in profile 1. +- * If the mac/vlan pair does not yet exist in profile 1, it adds the new pair to +- * the list in profile 1. +- */ +-void vdp_takeover_macvlans(struct vsi_profile *p1, struct vsi_profile *p2) +-{ +- struct mac_vlan *mv2; +- int count = 0; +- +- LLDPAD_DBG("%s: taking over mac/vlan pairs\n", __func__); +- +- while ((mv2 = LIST_FIRST(&p2->macvid_head))) { +- LIST_REMOVE(mv2, entry); +- p2->entries--; +- if (have_macvlan(p1, mv2)) +- free(mv2); +- else +- count++; +- } +- +- LLDPAD_DBG("%s: %u mac/vlan pairs taken over\n", __func__, count); +-} +- +-/* vdp_add_profile - adds a profile to a per port list +- * @profile: profile to add +- * +- * returns the profile that has been found or added, NULL otherwise. +- * +- * main interface function which adds a profile to a list kept on a per-port +- * basis. Checks if the profile is already in the list, adds it if necessary. +- */ +-struct vsi_profile *vdp_add_profile(struct vdp_data *vd, +- struct vsi_profile *profile) +-{ +- struct vsi_profile *p; +- +- LLDPAD_DBG("%s: adding vdp profile for %s\n", __func__, +- profile->port->ifname); +- vdp_trace_profile(profile); +- +- /* +- * Search this profile. If found check, +- * if the MAC/VLAN pair already exists. If not, add it. +- */ +- p = vdp_find_profile(vd, profile); +- if (p) { +- LLDPAD_DBG("%s: profile already exists\n", __func__); +- +- vdp_takeover_macvlans(p, profile); +- +- if (p->mode != profile->mode) { +- LLDPAD_DBG("%s: new mode %i\n", +- __func__, profile->mode); +- p->mode = profile->mode; +- p->response = VDP_RESPONSE_NO_RESPONSE; +- } +- profile = p; +- } else { +- +- profile->response = VDP_RESPONSE_NO_RESPONSE; +- +- LIST_INSERT_HEAD(&vd->profile_head, profile, profile); +- } +- +- vdp_somethingChangedLocal(profile, true); +- +- return profile; +-} +- +-/* vdp_remove_profile - remove a profile from a per port list +- * @profile: profile to remove +- * +- * returns 0 if removal was successful, -1 if removal failed +- * +- * function used in the state machines to remove a profile from a list kept on +- * a per-port basis. Checks if the profile is in the list, removes it if there. +- */ +-int vdp_remove_profile(struct vsi_profile *profile) +-{ +- struct vsi_profile *p; +- struct vdp_data *vd; +- +- LLDPAD_DBG("%s: removing vdp profile on %s\n", __func__, +- profile->port->ifname); +- vdp_trace_profile(profile); +- +- vd = vdp_data(profile->port->ifname); +- if (!vd) { +- LLDPAD_ERR("%s: could not find vdp_data for %s\n", __func__, +- profile->port->ifname); +- return -1; +- } +- /* Check if profile exists. If yes, remove it. */ +- p = vdp_find_profile(vd, profile); +- if (p) { +- LIST_REMOVE(p, profile); +- vdp_delete_profile(p); +- return 0; +- } +- return -1; /* Not found */ +-} +- +-/* vdp_ifdown - tear down vdp structures for a interface +- * @ifname: name of the interface +- * +- * no return value +- * +- * interface function to lldpad. tears down vdp specific structures if +- * interface "ifname" goes down. +- */ +-void vdp_ifdown(char *ifname, UNUSED struct lldp_agent *agent) +-{ +- struct vdp_data *vd; +- struct vsi_profile *p; +- +- LLDPAD_DBG("%s: called on interface %s\n", __func__, ifname); +- +- vd = vdp_data(ifname); +- if (!vd) +- goto out_err; +- +- if (ecp_deinit(ifname)) +- goto out_err; +- +- LIST_FOREACH(p, &vd->profile_head, profile) { +- if (p->ackTimer > 0) +- vdp_stop_ackTimer(p); +- if (p->keepaliveTimer > 0) +- vdp_stop_keepaliveTimer(p); +- } +- +- LLDPAD_INFO("%s: %s vdp data removed\n", __func__, ifname); +- return; +-out_err: +- LLDPAD_INFO("%s: %s vdp data remove failed\n", __func__, ifname); +- +- return; +-} +- +-/* vdp_ifup - build up vdp structures for a interface +- * @ifname: name of the interface +- * +- * no return value +- * +- * interface function to lldpad. builds up vdp specific structures if +- * interface "ifname" goes up. +- */ +-void vdp_ifup(char *ifname, struct lldp_agent *agent) +-{ +- char *role; +- char config_path[16]; +- struct vdp_data *vd; +- struct vdp_user_data *ud; +- struct vsi_profile *p; +- int enabletx = false; +- +- LLDPAD_DBG("%s: %s agent:%d start VDP\n", +- __func__, ifname, agent->type); +- +- snprintf(config_path, sizeof(config_path), "%s.%s", +- VDP_PREFIX, ARG_TLVTXENABLE); +- +- if (get_config_setting(ifname, agent->type, config_path, +- (void *)&enabletx, CONFIG_TYPE_BOOL)) +- enabletx = false; +- +- if (enabletx == false) { +- LLDPAD_DBG("%s: %s not enabled for VDP\n", __func__, ifname); +- return; +- } +- +- vd = vdp_data(ifname); +- if (vd) { +- vd->enabletx = enabletx; +- +- LLDPAD_WARN("%s: %s vdp data already exists\n", +- __func__, ifname); +- goto out_start_again; +- } +- +- /* not found, alloc/init per-port module data */ +- vd = (struct vdp_data *) calloc(1, sizeof(struct vdp_data)); +- if (!vd) { +- LLDPAD_ERR("%s: %s malloc %zu failed\n", +- __func__, ifname, sizeof(*vd)); +- goto out_err; +- } +- strncpy(vd->ifname, ifname, IFNAMSIZ); +- +- vd->role = VDP_ROLE_STATION; +- vd->enabletx = enabletx; +- +- if (!get_cfg(ifname, NEAREST_BRIDGE, "vdp.role", (void *)&role, +- CONFIG_TYPE_STRING)) { +- if (!strcasecmp(role, VAL_BRIDGE)) { +- vd->role = VDP_ROLE_BRIDGE; +- } +- } +- +- LLDPAD_DBG("%s: configured for %s mode\n", ifname, +- (vd->role ==VDP_ROLE_BRIDGE) ? "bridge" : "station"); +- +- LIST_INIT(&vd->profile_head); +- +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP02); +- LIST_INSERT_HEAD(&ud->head, vd, entry); +- +-out_start_again: +- if (ecp_init(ifname)) { +- LLDPAD_ERR("%s: %s unable to init ecp\n", __func__, ifname); +- vdp_ifdown(ifname, agent); +- goto out_err; +- } +- +- vd->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; +- vd->ackTimer = VDP_ACK_TIMER_DEFAULT; +- +- LLDPAD_DBG("%s: %s starting vdp timer (%i)\n", __func__, +- vd->ifname, vd->nroftimers); +- +- LIST_FOREACH(p, &vd->profile_head, profile) { +- if (p->ackTimer > 0) { +- vdp_somethingChangedLocal(p, true); +- vdp_start_ackTimer(p); +- } +- if (p->keepaliveTimer > 0) +- vdp_start_keepaliveTimer(p); +- } +- +- LLDPAD_DBG("%s: %s agent:%d vdp added\n", __func__, ifname, +- agent->type); +- return; +- +-out_err: +- LLDPAD_ERR("%s: %s agent:%d vdp adding failed\n", +- __func__, ifname, agent->type); +-} +- +-static int vdp_client_cmd(UNUSED void *data, UNUSED struct sockaddr_un *from, +- UNUSED socklen_t fromlen, char *ibuf, int ilen, +- char *rbuf, int rlen) +-{ +- return vdp_clif_cmd(ibuf, ilen, rbuf, rlen); +-} +- +-static const struct lldp_mod_ops vdp_ops = { +- .lldp_mod_register = vdp_register, +- .lldp_mod_unregister = vdp_unregister, +- .get_arg_handler = vdp_get_arg_handlers, +- .client_cmd = vdp_client_cmd +-}; +- +-/* vdp_register - register vdp module to lldpad +- * @none +- * +- * returns lldp_module struct on success, NULL on error +- * +- * allocates a module structure with vdp module information and returns it +- * to lldpad. +- */ +-struct lldp_module *vdp_register(void) +-{ +- struct lldp_module *mod; +- struct vdp_user_data *ud; +- +- mod = malloc(sizeof(*mod)); +- if (!mod) { +- LLDPAD_ERR("%s: failed to start - vdp data\n", __func__); +- return NULL; +- } +- ud = malloc(sizeof(struct vdp_user_data)); +- if (!ud) { +- free(mod); +- LLDPAD_ERR("%s: failed to start - vdp user data\n", __func__); +- return NULL; +- } +- LIST_INIT(&ud->head); +- mod->id = LLDP_MOD_VDP02; +- mod->ops = &vdp_ops; +- mod->data = ud; +- LLDPAD_DBG("%s: done\n", __func__); +- return mod; +-} +- +-/* vdp_unregister - unregister vdp module from lldpad +- * @none +- * +- * no return value +- * +- * frees vdp module structure. +- */ +-void vdp_unregister(struct lldp_module *mod) +-{ +- if (mod->data) { +- vdp_free_data((struct vdp_user_data *) mod->data); +- free(mod->data); +- } +- free(mod); +- LLDPAD_DBG("%s: done\n", __func__); +-} +- +-void vdp_update(char *ifname, u8 ccap) +-{ +- struct vdp_data *vdp = vdp_data(ifname); +- +- if (vdp) { +- vdp->vdpbit_on = ccap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP; +- LLDPAD_DBG("%s:%s vdpbit_on %d\n", __func__, ifname, +- vdp->vdpbit_on); +- } +-} +- +-/* +- * Handle a VSI request from buddy. +- */ +-int vdp_request(struct vdpnl_vsi *vsi) +-{ +- struct vdp_data *vd; +- struct vsi_profile *profile, *p; +- struct port *port = port_find_by_name(vsi->ifname); +- struct mac_vlan *mac_vlan; +- int ret = 0; +- +- vd = vdp_data(vsi->ifname); +- if (!vd) { +- LLDPAD_ERR("%s: %s has not yet been configured\n", __func__, +- vsi->ifname); +- return -ENXIO; +- } +- if (!vd->vdpbit_on) { +- LLDPAD_ERR("%s: %s has VDP disabled\n", __func__, vsi->ifname); +- return -ENXIO; +- } +- +- if (!port) { +- LLDPAD_ERR("%s: %s can not find port\n", __func__, vsi->ifname); +- return -ENODEV; +- } +- /* If the link is down, reject request */ +- if (!port->portEnabled && vsi->request != VDP_MODE_DEASSOCIATE) { +- LLDPAD_WARN("%s: %s not enabled, unable to associate\n", +- __func__, vsi->ifname); +- return -ENXIO; +- } +- +- profile = vdp_alloc_profile(); +- if (!profile) +- return -ENOMEM; +- mac_vlan = calloc(1, sizeof(struct mac_vlan)); +- if (!mac_vlan) { +- ret = -ENOMEM; +- goto out_err; +- } +- +- profile->port = port; +- memcpy(&mac_vlan->mac, vsi->maclist->mac, sizeof mac_vlan->mac); +- mac_vlan->vlan = vsi->maclist->vlan; +- mac_vlan->qos = vsi->maclist->qos; +- mac_vlan->req_pid = vsi->req_pid; +- mac_vlan->req_seq = vsi->req_seq; +- LIST_INSERT_HEAD(&profile->macvid_head, mac_vlan, entry); +- profile->entries = 1; +- +- profile->mgrid = vsi->vsi_mgrid; +- profile->id = vsi->vsi_typeid; +- profile->version = vsi->vsi_typeversion; +- profile->mode = vsi->request; +- profile->response = vsi->response; +- memcpy(profile->instance, vsi->vsi_uuid, sizeof vsi->vsi_uuid); +- p = vdp_add_profile(vd, profile); +- p->no_nlmsg = 1; +- p->txmit = false; +- vdp_trace_profile(p); +- if (p != profile) +- goto out_err; +- return ret; +- +-out_err: +- vdp_delete_profile(profile); +- return ret; +-} +- +-/* +- * Query a VSI request from buddy and report its progress. Use the interface +- * name to determine the VSI profile list. Return one entry in parameter 'vsi' +- * use the structure members response and vsi_uuid. +- * Returns +- * 1 valid VSI data returned +- * 0 end of queue (no VSI data returned) +- * <0 errno +- */ +-int vdp_status(int number, struct vdpnl_vsi *vsi) +-{ +- struct vdp_data *vd; +- struct vsi_profile *p; +- int i = 0, ret = 0; +- +- vd = vdp_data(vsi->ifname); +- if (!vd) { +- LLDPAD_ERR("%s: %s has not yet been configured\n", __func__, +- vsi->ifname); +- return -ENODEV; +- } +- /* Interate to queue element number */ +- LIST_FOREACH(p, &vd->profile_head, profile) { +- if (++i == number) { +- ret = 1; +- break; +- } +- } +- if (ret) { +- vdp_trace_profile(p); +- vsi->response = p->response; +- memcpy(vsi->vsi_uuid, p->instance, sizeof vsi->vsi_uuid); +- if (p->response != VDP_RESPONSE_NO_RESPONSE +- && p->state == VSI_EXIT) +- vdp_remove_profile(p); +- } +- LLDPAD_DBG("%s: entry:%d more:%d\n", __func__, number, ret); +- return ret; +-} +- +-/* +- * Copy MAC-VLAN list from profile to vdpnl structure. +- */ +-static void copy_maclist(struct vsi_profile *p, struct vdpnl_mac *macp) +-{ +- struct mac_vlan *mv1; +- +- LIST_FOREACH(mv1, &p->macvid_head, entry) { +- macp->vlan = mv1->vlan; +- macp->qos = mv1->qos; +- memcpy(macp->mac, mv1->mac, sizeof macp->mac); +- ++macp; +- } +-} +- +-/* +- * Prepare data for a netlink message to originator of VSI. +- * Forward a notification from switch. +- */ +-int vdp_trigger(struct vsi_profile *profile) +-{ +- struct vdpnl_vsi vsi; +- struct vdp_data *vd; +- struct mac_vlan *macp = 0; +- int rc = -EINVAL; +- struct vdpnl_mac maclist[profile->entries]; +- +- vsi.macsz = profile->entries; +- vsi.maclist = maclist; +- LLDPAD_DBG("%s: no_nlmsg:%d\n", __func__, profile->no_nlmsg); +- vdp_trace_profile(profile); +- if (profile->no_nlmsg) +- return 0; +- if (LIST_EMPTY(&profile->macvid_head)) +- return 0; +- macp = LIST_FIRST(&profile->macvid_head); +- if (!macp->req_pid) +- return 0; +- sleep(1); /* Delay message notification */ +- if (!profile->port || !profile->port->ifname) { +- LLDPAD_ERR("%s: no ifname found for profile %p:\n", __func__, +- profile); +- goto error_exit; +- } +- memcpy(vsi.ifname, profile->port->ifname, sizeof vsi.ifname); +- vd = vdp_data(vsi.ifname); +- if (!vd) { +- LLDPAD_ERR("%s: %s could not find vdp_data\n", __func__, +- vsi.ifname); +- goto error_exit; +- } +- vsi.ifindex = if_nametoindex(vsi.ifname); +- if (vsi.ifindex == 0) { +- LLDPAD_ERR("%s: %s could not find index for ifname\n", +- __func__, vsi.ifname); +- goto error_exit; +- } +- vsi.macsz = profile->entries; +- copy_maclist(profile, vsi.maclist); +- vsi.req_pid = macp->req_pid; +- vsi.req_seq = macp->req_seq; +- vsi.vsi_mgrid = profile->mgrid; +- vsi.vsi_typeid = profile->id; +- vsi.vsi_typeversion = profile->version; +- memcpy(vsi.vsi_uuid, profile->instance, sizeof vsi.vsi_uuid); +- vsi.request = VDP_MODE_DEASSOCIATE; +- rc = vdpnl_send(&vsi); +-error_exit: +- vdp_remove_profile(profile); +- return rc; +-} +diff --git a/lldp_vdp_clif.c b/lldp_vdp_clif.c +deleted file mode 100644 +index 6fd1e8e..0000000 +--- a/lldp_vdp_clif.c ++++ /dev/null +@@ -1,193 +0,0 @@ +-/******************************************************************************* +- +- Implementation of VDP according to IEEE 802.1Qbg +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Jens Osterkamp +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-*******************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include "lldp_mod.h" +-#include "clif_msgs.h" +-#include "lldp.h" +-#include "lldp_vdp.h" +-#include "lldp_vdp_cmds.h" +-#include "lldp_vdp_clif.h" +-#include "lldp_mand_clif.h" +- +-static const char *mode_state(int mode) +-{ +- switch (mode) { +- case VDP_MODE_PREASSOCIATE_WITH_RR: +- return "Preassociated with RR"; +- case VDP_MODE_DEASSOCIATE: +- return "Disassociated"; +- case VDP_MODE_ASSOCIATE: +- return "Associated"; +- case VDP_MODE_PREASSOCIATE: +- return "Preassociated"; +- default: return "unknown"; +- } +-} +- +-/* +- * Print a complete VDP TLV. Data string constructed in function +- * vdp_clif_profile(). +- */ +-static void vdp_show_tlv(UNUSED u16 len, char *info) +-{ +- int rc, role, enabletx, vdpbit, mode, response, mgrid, id, idver; +- unsigned int x[16]; +- +- rc = sscanf(info, "%02x%02x%02x%02x%02x%02x%06x%02x", +- &role, &enabletx, &vdpbit, &mode, &response, &mgrid, +- &id, &idver); +- if (rc != 3 && rc != 8) +- return; +- printf("Role:%s\n", role ? VAL_BRIDGE : VAL_STATION); +- printf("\tEnabled:%s\n", enabletx ? VAL_YES : VAL_NO); +- printf("\tVDP Bit:%s\n", vdpbit ? VAL_YES : VAL_NO); +- if (rc == 3) /* No active VSI profile */ +- return; +- printf("\tMode:%d (%s)\n", mode, mode_state(mode)); +- printf("\tMgrid:%d\n", mgrid); +- printf("\tTypeid:%d\n", id); +- printf("\tTypeidversion:%d\n", idver); +- rc = sscanf(info + 20, "%02x%02x%02x%02x%02x%02x%02x%02x" +- "%02x%02x%02x%02x%02x%02x%02x%02x", +- &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], +- &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], +- &x[15]); +- if (rc != 16) +- return; +- printf("\tUUID:%02x%02x%02x%02x-%02x%02x-%02x%02x" +- "-%02x%02x-%02x%02x%02x%02x%02x%02x\n", x[0], x[1], x[2], x[3], +- x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], +- x[14], x[15]); +- mode = 52; +- rc = sscanf(info + mode, "%02x%04x", &role, &vdpbit); +- if (rc != 2) +- return; +- printf("\tFilter Format:%d\n", role); +- printf("\tEntries:%d\n", vdpbit); +- mode += 6; +- while (--vdpbit >= 0) { +- rc = sscanf(info + mode, "%02x%02x%02x%02x%02x%02x%04x", +- &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6]); +- if (rc != 7) +- return; +- printf("\t\tMAC:%02x:%02x:%02x:%02x:%02x:%02x\tVlanid:%d\n", +- x[0], x[1], x[2], x[3], x[4], x[5], x[6]); +- mode += 16; +- } +-} +- +-static struct type_name_info vdp_tlv_names[] = { +- { +- .type = ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE, +- .name = "VDP draft 0.2 protocol configuration", +- .key = "vdp", +- .print_info = vdp_show_tlv +- }, +- { +- .type = INVALID_TLVID +- } +-}; +- +-static int vdp_print_help() +-{ +- struct type_name_info *tn = &vdp_tlv_names[0]; +- +- while (tn->type != INVALID_TLVID) { +- if (tn->key && strlen(tn->key) && tn->name) { +- printf(" %s", tn->key); +- if (strlen(tn->key)+3 < 8) +- printf("\t"); +- printf("\t: %s\n", tn->name); +- } +- tn++; +- } +- return 0; +-} +- +-static u32 vdp_lookup_tlv_name(char *tlvid_str) +-{ +- struct type_name_info *tn = &vdp_tlv_names[0]; +- +- while (tn->type != INVALID_TLVID) { +- if (!strcasecmp(tn->key, tlvid_str)) +- return tn->type; +- tn++; +- } +- return INVALID_TLVID; +-} +- +-static void vdp_cli_unregister(struct lldp_module *mod) +-{ +- free(mod); +-} +- +-/* return 1: if it printed the TLV +- * 0: if it did not +- */ +-static int vdp_print_tlv(u32 tlvid, u16 len, char *info) +-{ +- struct type_name_info *tn = &vdp_tlv_names[0]; +- +- while (tn->type != INVALID_TLVID) { +- if (tlvid == tn->type) { +- printf("%s\n", tn->name); +- if (tn->print_info) { +- printf("\t"); +- tn->print_info(len-4, info); +- } +- return 1; +- } +- tn++; +- } +- return 0; +-} +- +-static const struct lldp_mod_ops vdp_ops_clif = { +- .lldp_mod_register = vdp_cli_register, +- .lldp_mod_unregister = vdp_cli_unregister, +- .print_tlv = vdp_print_tlv, +- .lookup_tlv_name = vdp_lookup_tlv_name, +- .print_help = vdp_print_help, +-}; +- +-struct lldp_module *vdp_cli_register(void) +-{ +- struct lldp_module *mod; +- +- mod = malloc(sizeof(*mod)); +- if (!mod) { +- fprintf(stderr, "failed to malloc module data\n"); +- return NULL; +- } +- mod->id = (LLDP_MOD_VDP << 8) | LLDP_VDP_SUBTYPE; +- mod->ops = &vdp_ops_clif; +- return mod; +-} +diff --git a/lldp_vdp_cmds.c b/lldp_vdp_cmds.c +deleted file mode 100644 +index ec9c49c..0000000 +--- a/lldp_vdp_cmds.c ++++ /dev/null +@@ -1,668 +0,0 @@ +-/****************************************************************************** +- +- Implementation of VDP according to IEEE 802.1Qbg +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Jens Osterkamp +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include "lldpad.h" +-#include "ctrl_iface.h" +-#include "lldp.h" +-#include "lldp_vdp.h" +-#include "lldp_mand_clif.h" +-#include "lldp_vdp_cmds.h" +-#include "lldp_qbg_utils.h" +-#include "lldp/ports.h" +-#include "lldp_tlv.h" +-#include "messages.h" +-#include "libconfig.h" +-#include "config.h" +-#include "clif_msgs.h" +-#include "lldpad_status.h" +-#include "lldp/states.h" +- +-static char *check_and_update(size_t *total, size_t *length, char *s, int c) +-{ +- if (c < 0) +- return NULL; +- *total += c; +- if ((unsigned)c >= *length) +- return NULL; +- *length -= c; +- return s + c; +-} +- +-static char *print_mode(char *s, size_t length, struct vsi_profile *p) +-{ +- int c; +- size_t total = 0; +- char *r = s; +- struct mac_vlan *mac_vlan; +- char instance[VDP_UUID_STRLEN + 2]; +- +- vdp_uuid2str(p->instance, instance, sizeof(instance)); +- c = snprintf(s, length, "%d,%d,%d,%d,%s,%d", +- p->state, p->mgrid, p->id, p->version, instance, +- p->format); +- s = check_and_update(&total, &length, s, c); +- if (!s) +- return r; +- +- LIST_FOREACH(mac_vlan, &p->macvid_head, entry) { +- char macbuf[MAC_ADDR_STRLEN + 1]; +- +- mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); +- c = snprintf(s, length, ",%s,%d", macbuf, mac_vlan->vlan); +- s = check_and_update(&total, &length, s, c); +- if (!s) +- return r; +- } +- return s; +-} +- +-static int +-get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- int value; +- char *s; +- char arg_path[VDP_BUF_SIZE]; +- +- if (cmd->cmd != cmd_gettlv) +- return cmd_invalid; +- +- switch (cmd->tlvid) { +- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: +- snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); +- +- if (get_cfg(cmd->ifname, cmd->type, arg_path, &value, +- CONFIG_TYPE_BOOL)) +- value = false; +- break; +- case INVALID_TLVID: +- return cmd_invalid; +- default: +- return cmd_not_applicable; +- } +- +- if (value) +- s = VAL_YES; +- else +- s = VAL_NO; +- +- snprintf(obuf, obuf_len, "%02zx%s%04zx%s", +- strlen(arg), arg, strlen(s), s); +- +- return cmd_success; +-} +- +-static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, +- bool test) +-{ +- int value, err; +- char arg_path[VDP_BUF_SIZE]; +- +- if (cmd->cmd != cmd_settlv) +- return cmd_invalid; +- +- switch (cmd->tlvid) { +- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: +- break; +- case INVALID_TLVID: +- return cmd_invalid; +- default: +- return cmd_not_applicable; +- } +- +- if (!strcasecmp(argvalue, VAL_YES)) +- value = 1; +- else if (!strcasecmp(argvalue, VAL_NO)) +- value = 0; +- else +- return cmd_invalid; +- +- if (test) +- return cmd_success; +- +- snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); +- +- err = set_cfg(cmd->ifname, cmd->type, arg_path, +- &value, CONFIG_TYPE_BOOL); +- if (err) +- return cmd_failed; +- +- return cmd_success; +- +-} +- +-static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return _set_arg_tlvtxenable(cmd, arg, argvalue, false); +-} +- +-static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return _set_arg_tlvtxenable(cmd, arg, argvalue, true); +-} +- +-static int get_arg_mode(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- struct vsi_profile *np; +- struct vdp_data *vd; +- char mode_str[VDP_BUF_SIZE], *t = mode_str; +- int filled = 0; +- +- if (cmd->cmd != cmd_gettlv) +- return cmd_invalid; +- +- switch (cmd->tlvid) { +- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: +- break; +- case INVALID_TLVID: +- return cmd_invalid; +- default: +- return cmd_not_applicable; +- } +- +- vd = vdp_data(cmd->ifname); +- if (!vd) { +- LLDPAD_ERR("%s: vdp_data for %s not found !\n", +- __func__, cmd->ifname); +- return cmd_device_not_found; +- } +- +- memset(mode_str, 0, sizeof mode_str); +- LIST_FOREACH(np, &vd->profile_head, profile) { +- t = print_mode(t, sizeof(mode_str) - filled, np); +- filled = t - mode_str; +- } +- +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int)strlen(arg), arg, (unsigned int)strlen(mode_str), +- mode_str); +- return cmd_success; +-} +- +-static void str2instance(struct vsi_profile *profile, char *buffer) +-{ +- unsigned int i, j = 0; +- +- for (i = 0; i <= strlen(buffer); i++) { +- if (buffer[i] == '-') +- continue; +- +- if (sscanf(&buffer[i], "%02hhx", &profile->instance[j]) == 1) { +- i++; +- j++; +- } +- } +-} +- +-static void vdp_fill_profile(struct vsi_profile *profile, char *buffer, +- int field) +-{ +- LLDPAD_DBG("%s: parsed %s\n", __func__, buffer); +- +- switch(field) { +- case MODE: +- profile->mode = atoi(buffer); +- break; +- case MGRID: +- profile->mgrid = atoi(buffer); +- break; +- case TYPEID: +- profile->id = atoi(buffer); +- break; +- case TYPEIDVERSION: +- profile->version = atoi(buffer); +- break; +- case INSTANCEID: +- str2instance(profile, buffer); +- break; +- case FORMAT: +- profile->format = atoi(buffer); +- break; +- default: +- LLDPAD_ERR("Unknown field in buffer !\n"); +- break; +- } +-} +- +-static struct vsi_profile *vdp_parse_mode_line(char *argvalue) +-{ +- int field; +- char *cmdstring, *parsed; +- struct vsi_profile *profile; +- +- profile = vdp_alloc_profile(); +- if (!profile) +- return NULL; +- +- cmdstring = strdup(argvalue); +- if (!cmdstring) +- goto out_free; +- +- field = 0; +- +- parsed = strtok(cmdstring, ","); +- +- while (parsed != NULL) { +- vdp_fill_profile(profile, parsed, field); +- field++; +- if (field > FORMAT) +- break; +- parsed = strtok(NULL, ","); +- } +- +- if ((field <= FORMAT) || (parsed == NULL)) +- goto out_free; +- +- parsed = strtok(NULL, ","); +- +- while (parsed != NULL) { +- struct mac_vlan *mac_vlan; +- +- mac_vlan = calloc(1, sizeof(struct mac_vlan)); +- if (mac_vlan == NULL) +- goto out_free; +- +- if (str2mac(parsed, &mac_vlan->mac[0], MAC_ADDR_LEN)) { +- free(mac_vlan); +- goto out_free; +- } +- +- parsed = strtok(NULL, ","); +- if (parsed == NULL) { +- free(mac_vlan); +- goto out_free; +- } +- +- mac_vlan->vlan = atoi(parsed); +- LIST_INSERT_HEAD(&profile->macvid_head, mac_vlan, entry); +- profile->entries++; +- parsed = strtok(NULL, ","); +- } +- +- free(cmdstring); +- return profile; +- +-out_free: +- free(cmdstring); +- vdp_delete_profile(profile); +- return NULL; +-} +- +-static int _set_arg_mode(struct cmd *cmd, char *argvalue, bool test) +-{ +- struct vsi_profile *profile, *p; +- struct vdp_data *vd; +- +- if (cmd->cmd != cmd_settlv) +- return cmd_invalid; +- +- switch (cmd->tlvid) { +- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: +- break; +- case INVALID_TLVID: +- return cmd_invalid; +- default: +- return cmd_not_applicable; +- } +- +- profile = vdp_parse_mode_line(argvalue); +- if (profile == NULL) +- return cmd_failed; +- +- profile->port = port_find_by_name(cmd->ifname); +- +- if (!profile->port) { +- vdp_delete_profile(profile); +- return cmd_device_not_found; +- } +- +- vd = vdp_data(cmd->ifname); +- if (!vd) { +- vdp_delete_profile(profile); +- return cmd_device_not_found; +- } +- +- if (test) { +- vdp_delete_profile(profile); +- return cmd_success; +- } +- +- p = vdp_add_profile(vd, profile); +- if (profile != p) +- vdp_delete_profile(profile); +- +- return cmd_success; +-} +- +-static int set_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return _set_arg_mode(cmd, argvalue, false); +-} +- +-static int test_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return _set_arg_mode(cmd, argvalue, true); +-} +- +-static int get_arg_role(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- struct vdp_data *vd; +- +- if (cmd->cmd != cmd_gettlv) +- return cmd_invalid; +- +- switch (cmd->tlvid) { +- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: +- vd = vdp_data(cmd->ifname); +- +- if (!vd) { +- LLDPAD_ERR("%s: could not find vdp_data for %s\n", +- __FILE__, cmd->ifname); +- return cmd_device_not_found; +- } +- +- if (vd->role == VDP_ROLE_STATION) +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int) strlen(arg), arg, +- (unsigned int) strlen(VAL_STATION), +- VAL_STATION); +- else if (vd->role == VDP_ROLE_BRIDGE) +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int) strlen(arg), arg, +- (unsigned int) strlen(VAL_BRIDGE), VAL_BRIDGE); +- else +- return cmd_failed; +- break; +- case INVALID_TLVID: +- return cmd_invalid; +- default: +- return cmd_not_applicable; +- } +- +- return cmd_success; +-} +- +-static int _set_arg_role(struct cmd *cmd, char *arg, char *argvalue, bool test) +-{ +- struct vdp_data *vd; +- char arg_path[VDP_BUF_SIZE]; +- +- if (cmd->cmd != cmd_settlv) +- return cmd_invalid; +- +- switch (cmd->tlvid) { +- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: +- break; +- case INVALID_TLVID: +- return cmd_invalid; +- default: +- return cmd_not_applicable; +- } +- +- vd = vdp_data(cmd->ifname); +- +- if (!vd) { +- LLDPAD_ERR("%s: could not find vdp_data for %s\n", +- __FILE__, cmd->ifname); +- return cmd_device_not_found; +- } +- +- if (!strcasecmp(argvalue, VAL_BRIDGE)) { +- if (!test) +- vd->role = VDP_ROLE_BRIDGE; +- } else if (!strcasecmp(argvalue, VAL_STATION)) { +- if (!test) +- vd->role = VDP_ROLE_STATION; +- } else { +- return cmd_invalid; +- } +- +- if (test) +- return cmd_success; +- +- snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); +- +- const char *p = &argvalue[0]; +- if (set_cfg(cmd->ifname, cmd->type, arg_path, &p, CONFIG_TYPE_STRING)) +- return cmd_failed; +- +- return cmd_success; +-} +- +-static int set_arg_role(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return _set_arg_role(cmd, arg, argvalue, false); +-} +- +-static int test_arg_role(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return _set_arg_role(cmd, arg, argvalue, true); +-} +- +-static struct arg_handlers arg_handlers[] = { +- { +- .arg = ARG_VDP_MODE, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_mode, +- .handle_set = set_arg_mode, +- .handle_test = test_arg_mode +- }, +- { +- .arg = ARG_VDP_ROLE, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_role, +- .handle_set = set_arg_role, +- .handle_test = test_arg_role +- }, +- { +- .arg = ARG_TLVTXENABLE, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_tlvtxenable, +- .handle_set = set_arg_tlvtxenable, +- .handle_test = test_arg_tlvtxenable +- }, +- { +- .arg = 0 +- } +-}; +- +-struct arg_handlers *vdp_get_arg_handlers() +-{ +- return &arg_handlers[0]; +-} +- +-/* +- * Interface to build information for lldptool -V vdp +- */ +-struct tlv_info_vdp_nopp { /* VSI information without profile data */ +- u8 oui[3]; /* OUI */ +- u8 sub; /* Subtype */ +- u8 role; /* Role: station or bridge */ +- u8 enabletx; +- u8 vdpbit_on; +-} __attribute__ ((__packed__)); +- +-/* +- * Flatten a profile stored as TLV and append it. Skip the first 4 bytes. +- * They contain the OUI already stored. +- * Returns the number of bytes added to the buffer. +- */ +-static int add_profile(unsigned char *pdu, size_t pdusz, struct vdp_data *vdp) +-{ +- size_t size = 0; +- +- if (!vdp->vdp) +- return size; +- size = (unsigned)TLVSIZE(vdp->vdp) - 4; +- if (pdusz >= size) +- memcpy(pdu, vdp->vdp->info + 4, size); +- else { +- LLDPAD_ERR("%s: %s buffer size too small (need %d bytes)\n", +- __func__, vdp->ifname, TLVSIZE(vdp->vdp)); +- return -1; +- } +- return size; +-} +- +-/* +- * Create unpacked VDP tlv for VSI profile when active. +- */ +-static int make_vdp_tlv(unsigned char *pdu, size_t pdusz, struct vdp_data *vdp) +-{ +- struct unpacked_tlv *tlv = (struct unpacked_tlv *)pdu; +- struct tlv_info_vdp_nopp *vdpno; +- size_t pduoff; +- int rc; +- +- tlv->info = (unsigned char *)(tlv + 1); +- vdpno = (struct tlv_info_vdp_nopp *)tlv->info; +- tlv->type = ORG_SPECIFIC_TLV; +- tlv->length = sizeof(struct tlv_info_vdp_nopp); +- hton24(vdpno->oui, LLDP_MOD_VDP); +- vdpno->sub = LLDP_VDP_SUBTYPE; +- vdpno->role = vdp->role; +- vdpno->enabletx = vdp->enabletx; +- vdpno->vdpbit_on = vdp->vdpbit_on; +- pduoff = sizeof(*tlv) + tlv->length; +- pdusz -= pduoff; +- rc = add_profile(pdu + pduoff, pdusz - pduoff, vdp); +- if (rc > 0) { +- tlv->length += rc; +- rc = 0; +- } +- return rc; +-} +- +-/* +- * Flatten a VDP TLV into a byte stream. +- */ +-static int vdp_clif_profile(char *ifname, char *rbuf, size_t rlen) +-{ +- unsigned char pdu[VDP_BUF_SIZE]; /* Buffer for unpacked TLV */ +- int i, c, rstatus = cmd_success; +- size_t sum = 0; +- struct vdp_data *vd; +- struct unpacked_tlv *tlv = (struct unpacked_tlv *)pdu; +- struct packed_tlv *ptlv; +- +- LLDPAD_DBG("%s: %s rlen:%zu\n", __func__, ifname, rlen); +- vd = vdp_data(ifname); +- if (!vd) +- return cmd_device_not_found; +- +- if (make_vdp_tlv(pdu, sizeof pdu, vd)) +- return cmd_failed; +- +- /* Convert to packed TLV */ +- ptlv = pack_tlv(tlv); +- if (!ptlv) +- return cmd_failed; +- for (i = 0; i < TLVSIZE(tlv); ++i) { +- c = snprintf(rbuf, rlen, "%02x", ptlv->tlv[i]); +- rbuf = check_and_update(&sum, &rlen, rbuf, c); +- if (!rbuf) { +- rstatus = cmd_failed; +- break; +- } +- } +- free_pkd_tlv(ptlv); +- return rstatus; +-} +- +-/* +- * Module function to extract all VSI profile data on a given interface. It +- * is invoked via 'lldptool -t -i ethx -g ncb -V vdp' without any configuration +- * options. +- * This function does not support arguments and its values. They are handled +- * using the lldp_mand_cmds.c interfaces. +- */ +-int vdp_clif_cmd(char *ibuf, UNUSED int ilen, char *rbuf, int rlen) +-{ +- struct cmd cmd; +- u8 len, version; +- int c, ioff; +- size_t roff = 0, outlen = rlen; +- char *here; +- int rstatus = cmd_invalid; +- +- /* Pull out the command elements of the command message */ +- hexstr2bin(ibuf + MSG_VER, (u8 *)&version, sizeof(u8)); +- version >>= 4; +- hexstr2bin(ibuf + CMD_CODE, (u8 *)&cmd.cmd, sizeof(cmd.cmd)); +- hexstr2bin(ibuf + CMD_OPS, (u8 *)&cmd.ops, sizeof(cmd.ops)); +- cmd.ops = ntohl(cmd.ops); +- hexstr2bin(ibuf + CMD_IF_LEN, &len, sizeof(len)); +- ioff = CMD_IF; +- if (len < sizeof(cmd.ifname)) +- memcpy(cmd.ifname, ibuf + CMD_IF, len); +- else +- return cmd_failed; +- cmd.ifname[len] = '\0'; +- ioff += len; +- +- memset(rbuf, 0, rlen); +- c = snprintf(rbuf, rlen, "%c%1x%02x%08x%02x%s", +- CMD_REQUEST, CLIF_MSG_VERSION, cmd.cmd, cmd.ops, +- (unsigned int)strlen(cmd.ifname), cmd.ifname); +- here = check_and_update(&roff, &outlen, rbuf, c); +- if (!here) +- return cmd_failed; +- +- if (version == CLIF_MSG_VERSION) { +- hexstr2bin(ibuf+ioff, &cmd.type, sizeof(cmd.type)); +- ioff += 2 * sizeof(cmd.type); +- } else /* Command valid only for nearest customer bridge */ +- goto out; +- +- if (cmd.cmd == cmd_gettlv) { +- hexstr2bin(ibuf+ioff, (u8 *)&cmd.tlvid, sizeof(cmd.tlvid)); +- cmd.tlvid = ntohl(cmd.tlvid); +- ioff += 2 * sizeof(cmd.tlvid); +- } else +- goto out; +- +- c = snprintf(here, outlen, "%08x", cmd.tlvid); +- here = check_and_update(&roff, &outlen, here, c); +- if (!here) +- return cmd_failed; +- rstatus = vdp_clif_profile(cmd.ifname, here, outlen); +-out: +- return rstatus; +-} +diff --git a/lldpad.c b/lldpad.c +index d29a53d..406dcd5 100644 +--- a/lldpad.c ++++ b/lldpad.c +@@ -52,9 +52,9 @@ + #include "lldp_8023.h" + #include "lldp_evb.h" + #include "lldp_evb22.h" +-#include "lldp_ecp22.h" +-#include "lldp_vdp.h" +-#include "lldp_vdp22.h" ++#include "qbg_ecp22.h" ++#include "qbg_vdp.h" ++#include "qbg_vdp22.h" + #include "lldp_8021qaz.h" + #include "config.h" + #include "lldpad_shm.h" +@@ -83,6 +83,7 @@ struct lldp_module *(*register_tlv_table[])(void) = { + char *cfg_file_name = NULL; + bool daemonize = 0; + int loglvl = LOG_WARNING; ++int omit_tstamp; + + static const char *lldpad_version = + "lldpad v" VERSION_STR "\n" +@@ -124,16 +125,17 @@ static void usage(void) + { + fprintf(stderr, + "\n" +- "usage: lldpad [-hdkspv] [-f configfile]" ++ "usage: lldpad [-hdksptv] [-f configfile] [-V level]" + "\n" + "options:\n" + " -h show this usage\n" +- " -f use configfile instead of default\n" + " -d run daemon in the background\n" + " -k terminate current running lldpad\n" + " -s remove lldpad state records\n" + " -p Do not create PID file\n" ++ " -t omit timestamps in log messages\n" + " -v show version\n" ++ " -f use configfile instead of default\n" + " -V set syslog level\n"); + + exit(1); +@@ -153,15 +155,13 @@ void send_event(int level, u32 moduleid, char *msg) + ctrl_iface_send(cd, level, moduleid, msg, strlen(msg)); + } + +-static void remove_all_adapters() ++static void remove_all_adapters(void) + { +- struct port *port, *p; ++ struct port *port, *next; + +- port = porthead; +- while (port != NULL) { +- p = port; +- port = port->next; +- remove_port(p->ifname); ++ for (port = porthead; port; port = next) { ++ next = port->next; ++ remove_port(port->ifname); + } + + return; +@@ -231,9 +231,10 @@ int main(int argc, char *argv[]) + int pid_file = 1; + pid_t pid; + int cnt; ++ int rc = 1; + + for (;;) { +- c = getopt(argc, argv, "dhkvspf:V:"); ++ c = getopt(argc, argv, "hdksptvf:V:"); + if (c < 0) + break; + switch (c) { +@@ -256,6 +257,9 @@ int main(int argc, char *argv[]) + case 'p': + pid_file = 0; + break; ++ case 't': ++ omit_tstamp = 1; ++ break; + case 'v': + print_v = 1; + break; +@@ -330,29 +334,6 @@ int main(int argc, char *argv[]) + exit (0); + } + +- if (pid_file) { +- fd = open(PID_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); +- if (fd < 0) { +- LLDPAD_ERR("error opening lldpad lock file"); +- exit(1); +- } +- +- if (flock(fd, LOCK_EX | LOCK_NB) < 0) { +- if (errno == EWOULDBLOCK) { +- fprintf(stderr, "lldpad is already running\n"); +- if (read(fd, buf, sizeof(buf)) > 0) { +- fprintf(stderr, "pid of existing" +- "lldpad is %s\n", buf); +- } +- LLDPAD_ERR("lldpad already running"); +- } else { +- perror("error locking lldpad lock file"); +- LLDPAD_ERR("error locking lldpad lock file"); +- } +- exit(1); +- } +- } +- + lldpad_oom_adjust(); + + /* initialize lldpad user data */ +@@ -379,23 +360,30 @@ int main(int argc, char *argv[]) + exit(1); + } + ++ /* From this point on we know we're the only instance */ + if (daemonize && daemon(1, 0)) { + LLDPAD_ERR("error daemonizing lldpad"); +- goto out; ++ exit(1); + } + + if (pid_file) { ++ fd = open(PID_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); ++ if (fd < 0) { ++ LLDPAD_ERR("error opening lldpad pid file"); ++ exit(1); ++ } ++ + if (lseek(fd, 0, SEEK_SET) < 0) { +- LLDPAD_ERR("error seeking lldpad lock file\n"); +- exit(1); ++ LLDPAD_ERR("error seeking lldpad pid file\n"); ++ goto out_fail; + } + + memset(buf, 0, sizeof(buf)); + sprintf(buf, "%u\n", getpid()); + if (write(fd, buf, sizeof(buf)) < 0) +- perror("error writing to lldpad lock file"); ++ perror("error writing to lldpad pid file"); + if (fsync(fd) < 0) +- perror("error syncing lldpad lock file"); ++ perror("error syncing lldpad pid file"); + + close(fd); + } +@@ -403,23 +391,17 @@ int main(int argc, char *argv[]) + pid = lldpad_shm_getpid(); + if (pid < 0) { + LLDPAD_ERR("error getting shm pid"); +- if (pid_file) +- unlink(PID_FILE); +- exit(1); ++ goto out_fail; + } else if (pid == PID_NOT_SET) { + if (!lldpad_shm_setpid(getpid())) { + perror("lldpad_shm_setpid failed"); + LLDPAD_ERR("lldpad_shm_setpid failed\n"); +- if (pid_file) +- unlink(PID_FILE); +- exit (1); ++ goto out_fail; + } + } else if (pid != DONT_KILL_PID) { + if (!kill(pid, 0)) { + LLDPAD_ERR("lldpad already running"); +- if (pid_file) +- unlink(PID_FILE); +- exit(1); ++ goto out_fail; + } + /* pid in shm no longer has a process, go ahead + * and let this lldpad instance execute. +@@ -427,55 +409,51 @@ int main(int argc, char *argv[]) + if (!lldpad_shm_setpid(getpid())) { + perror("lldpad_shm_setpid failed"); + LLDPAD_ERR("error overwriting shm pid"); +- if (pid_file) +- unlink(PID_FILE); +- exit (1); ++ goto out_fail; + } + } + + openlog("lldpad", LOG_CONS | LOG_PID, LOG_DAEMON); + setlogmask(LOG_UPTO(loglvl)); + +- if (check_cfg_file()) +- exit(1); +- + /* setup event netlink interface for user space processes. + * This needs to be setup first to ensure it gets lldpads + * pid as netlink address. + */ + if (event_iface_init_user_space() < 0) { +- LLDPAD_ERR("lldpad failed to start - failed to register user space event interface\n"); +- exit(1); ++ LLDPAD_ERR("lldpad failed to start - " ++ "failed to register user space event interface\n"); ++ closelog(); ++ goto out_fail; + } + + init_modules(); + + eloop_register_signal_terminate(eloop_terminate, NULL); +- eloop_register_signal_reconfig(lldpad_reconfig, NULL); ++ eloop_register_signal_reconfig(lldpad_reconfig, NULL); + + /* setup LLDP agent */ + if (!start_lldp_agents()) { + LLDPAD_ERR("failed to initialize LLDP agent\n"); +- exit(1); ++ goto out; + } + + /* setup event RT netlink interface */ + if (event_iface_init() < 0) { + LLDPAD_ERR("failed to register event interface\n"); +- exit(1); ++ goto out; + } + + /* Find available interfaces and add adapters */ + init_ports(); + + if (ctrl_iface_register(clifd) < 0) { +- if (!daemonize) +- fprintf(stderr, "failed to register control interface\n"); + LLDPAD_ERR("lldpad failed to start - " + "failed to register control interface\n"); + goto out; + } + ++ rc = 0; + eloop_run(); + + clean_lldp_agents(); +@@ -485,12 +463,13 @@ int main(int argc, char *argv[]) + event_iface_deinit(); + stop_lldp_agents(); + out: ++ eloop_destroy(); ++ if (!eloop_terminated()) ++ rc = 1; + destroy_cfg(); + closelog(); ++out_fail: + if (pid_file) + unlink(PID_FILE); +- eloop_destroy(); +- if (eloop_terminated()) +- exit(0); +- exit(1); ++ exit(rc); + } +diff --git a/lldpad.service b/lldpad.service +index 8cc4aed..2cee1de 100644 +--- a/lldpad.service ++++ b/lldpad.service +@@ -4,7 +4,9 @@ After=syslog.target network.target + + [Service] + Type=simple +-ExecStart=/usr/sbin/lldpad ++ExecStart=/usr/sbin/lldpad -t ++ExecReload=/bin/kill -HUP $MAINPID + + [Install] + WantedBy=multi-user.target ++Also=lldpad.socket +diff --git a/lldpad.socket b/lldpad.socket +new file mode 100644 +index 0000000..24f3eb6 +--- /dev/null ++++ b/lldpad.socket +@@ -0,0 +1,6 @@ ++[Socket] ++ListenDatagram=@/com/intel/lldpad ++PassCredentials=true ++ ++[Install] ++WantedBy=sockets.target +diff --git a/lldpad_shm.c b/lldpad_shm.c +index bbd001f..4afcf73 100644 +--- a/lldpad_shm.c ++++ b/lldpad_shm.c +@@ -253,8 +253,8 @@ int lldpad_shm_get_dcbx(const char *device_name) + for (i = 0; i < num_entries; i++) { + if (strcmp(shmaddr->ent[i].ifname, device_name) == 0) { + switch (shmaddr->ent[i].dcbx_mode) { +- case dcbx_subtype1: +- case dcbx_subtype2: ++ case DCBX_SUBTYPE1: ++ case DCBX_SUBTYPE2: + rval = shmaddr->ent[i].dcbx_mode; + break; + default: +@@ -303,8 +303,8 @@ int lldpad_shm_set_dcbx(const char *device_name, int dcbx_mode) + if (num_entries > MAX_LLDPAD_SHM_ENTRIES) + goto done; + +- if ((dcbx_mode != dcbx_subtype0) && (dcbx_mode != dcbx_subtype1) && +- (dcbx_mode != dcbx_subtype2)) ++ if ((dcbx_mode != DCBX_SUBTYPE0) && (dcbx_mode != DCBX_SUBTYPE1) && ++ (dcbx_mode != DCBX_SUBTYPE2)) + goto done; + + /* search for existing entry */ +diff --git a/lldptool.c b/lldptool.c +index e1ff11f..1b229c1 100644 +--- a/lldptool.c ++++ b/lldptool.c +@@ -48,7 +48,7 @@ + #include "lldp_dcbx_clif.h" + #include "lldp_evb22_clif.h" + #include "lldp_evb_clif.h" +-#include "lldp_vdp_clif.h" ++#include "qbg_vdp_clif.h" + #include "lldp_8021qaz_clif.h" + #include "lldp_orgspec_clif.h" + #include "lldp_cisco_clif.h" +@@ -497,12 +497,15 @@ static int request(struct clif *clif, int argc, char *argv[]) + break; + case 'g': + if (!strcasecmp(optarg, "nearestbridge") || ++ !strcasecmp(optarg, "nearest_bridge") || + !strcasecmp(optarg, "nb")) + command.type = NEAREST_BRIDGE; + else if (!strcasecmp(optarg, "nearestcustomerbridge") || ++ !strcasecmp(optarg, "nearest_customer_bridge") || + !strcasecmp(optarg, "ncb")) + command.type = NEAREST_CUSTOMER_BRIDGE; +- else if (!strcasecmp(optarg, "nearestnontmprbridge") || ++ else if (!strcasecmp(optarg, "nearestnontpmrbridge") || ++ !strcasecmp(optarg, "nearest_nontpmr_bridge") || + !strcasecmp(optarg, "nntpmrb")) + command.type = NEAREST_NONTPMR_BRIDGE; + else { +diff --git a/lldptool_cmds.c b/lldptool_cmds.c +index 17b4d8b..daef8c8 100644 +--- a/lldptool_cmds.c ++++ b/lldptool_cmds.c +@@ -349,6 +349,9 @@ static char *print_status(cmd_status status) + case cmd_no_access: + str = "Access denied"; + break; ++ case cmd_agent_not_supported: ++ str = "TLV does not support agent type"; ++ break; + default: + str = "Unknown status"; + break; +@@ -462,12 +465,10 @@ static void print_tlvs(struct cmd *cmd, char *ibuf) + + printed = 0; + LIST_FOREACH(np, &lldp_head, lldp) { +- if (np->ops->print_tlv) +- if (np->ops->print_tlv(tlvid, tlv_len, +- ibuf+offset)) { ++ if (np->ops->print_tlv(tlvid, tlv_len, ibuf+offset)) { + printed = 1; + break; +- } ++ } + } + + if (!printed) { +diff --git a/log.c b/log.c +index e66e9c2..63b942b 100644 +--- a/log.c ++++ b/log.c +@@ -59,7 +59,7 @@ void log_message(int level, const char *format, ...) + if (daemonize) + vsyslog(level, format, vb); + else if (loglvl >= level) { +- if (!bypass_time) ++ if (!omit_tstamp && !bypass_time) + showtime(); + vprintf(format, vb); + bypass_time = strchr(format, '\n') == 0; +diff --git a/parse_cli.l b/parse_cli.l +index 529c563..3717aff 100644 +--- a/parse_cli.l ++++ b/parse_cli.l +@@ -226,19 +226,19 @@ gp { if (!cmd) { + BEGIN(cmddone); + } + +-cee { dcbx_version = dcbx_subtype2; ++cee { dcbx_version = DCBX_SUBTYPE2; + BEGIN(cmddone); + } + +-cin { dcbx_version = dcbx_subtype1; ++cin { dcbx_version = DCBX_SUBTYPE1; + BEGIN(cmddone); + } + +-force-cee { dcbx_version = dcbx_force_subtype2; ++force-cee { dcbx_version = DCBX_FORCE_SUBTYPE2; + BEGIN(cmddone); + } + +-force-cin { dcbx_version = dcbx_force_subtype1; ++force-cin { dcbx_version = DCBX_FORCE_SUBTYPE1; + BEGIN(cmddone); + } + +diff --git a/qbg/ecp.c b/qbg/ecp.c +new file mode 100644 +index 0000000..c81eb19 +--- /dev/null ++++ b/qbg/ecp.c +@@ -0,0 +1,1093 @@ ++/****************************************************************************** ++ ++ Implementation of ECP according to 802.1Qbg ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Jens Osterkamp ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "eloop.h" ++#include "lldp.h" ++#include "lldp_evb.h" ++#include "qbg_utils.h" ++#include "qbg_vdp.h" ++#include "messages.h" ++#include "config.h" ++#include "lldp/l2_packet.h" ++ ++#include "lldp_tlv.h" ++ ++static void ecp_tx_run_sm(struct vdp_data *); ++static void ecp_rx_run_sm(struct vdp_data *); ++ ++/* ecp_localchange_handler - triggers the processing of a local change ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here ++ * ++ * no return value ++ * ++ * called from ecp_somethingchangedlocal when a change is pending. Calls ++ * the ECP tx station state machine. A oneshot handler. This detour is taken ++ * to not having to call the ecp code from the vdp state machine. Instead, we ++ * return to the event loop, giving other code a chance to do work. ++ */ ++static void ecp_localchange_handler(UNUSED void *eloop_data, void *user_ctx) ++{ ++ struct vdp_data *vd; ++ ++ vd = (struct vdp_data *) user_ctx; ++ if (vd->ecp.tx.localChange) { ++ LLDPAD_DBG("%s:%s ecp.tx.localChange %i\n", ++ __func__, vd->ecp.ifname, vd->ecp.tx.localChange); ++ ecp_tx_run_sm(vd); ++ } ++} ++ ++/* ecp_start_localchange_timer - starts the ECP localchange timer ++ * @vd: vdp_data for the interface ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the ECP localchange timer when a localchange has been signaled from ++ * the VDP state machine. ++ */ ++static int ecp_start_localchange_timer(struct vdp_data *vd) ++{ ++ return eloop_register_timeout(0, ECP_LOCALCHANGE_TIMEOUT, ++ ecp_localchange_handler, ++ NULL, (void *) vd); ++} ++ ++/* ecp_stop_localchange_timer - stop the ECP localchange timer ++ * @vd: vdp_data for the interface ++ * ++ * returns the number of removed handlers ++ * ++ * stops the ECP localchange timer. Used e.g. when the host interface goes down. ++ */ ++static int ecp_stop_localchange_timer(struct vdp_data *vd) ++{ ++ LLDPAD_DBG("%s:%s stopping ecp localchange timer\n", __func__, ++ vd->ecp.ifname); ++ return eloop_cancel_timeout(ecp_localchange_handler, NULL, (void *) vd); ++} ++ ++/* ecp_ackTimer_expired - checks for expired ack timer ++ * @vd: vdp_data for interface ++ * ++ * returns true or false ++ * ++ * returns true if ack timer has expired, false otherwise. ++ */ ++static bool ecp_ackTimer_expired(struct vdp_data *vd) ++{ ++ return (vd->ecp.ackTimer == 0); ++} ++ ++/* ecp_ack_timeout_handler - handles the ack timer expiry ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here ++ * ++ * no return value ++ * ++ * called when the ECP timer has expired. Calls the ECP station state machine. ++ */ ++static void ecp_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) ++{ ++ struct vdp_data *vd; ++ ++ vd = (struct vdp_data *) user_ctx; ++ if (vd->ecp.ackTimer > 0) ++ vd->ecp.ackTimer -= ECP_ACK_TIMER_DEFAULT; ++ ++ if (ecp_ackTimer_expired(vd) == true) { ++ LLDPAD_DBG("%s:%s ecp_ackTimer_expired (%i)\n", ++ __func__, vd->ecp.ifname, vd->ecp.ackTimer); ++ ecp_tx_run_sm(vd); ++ } else { ++ LLDPAD_DBG("%s:%s BUG! handler called but" ++ "vdp->ecp.ackTimer not expired (%i)\n", ++ __func__, vd->ecp.ifname, vd->ecp.ackTimer); ++ } ++} ++ ++/* ecp_start_ack_timer - starts the ECP ack timer ++ * @vd: vdp_data for the interface ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the ECP ack timer when a frame has been sent out. ++ */ ++static int ecp_start_ack_timer(struct vdp_data *vd) ++{ ++ return eloop_register_timeout(0, ECP_ACK_TIMER_DEFAULT, ++ ecp_ack_timeout_handler, ++ NULL, (void *) vd); ++} ++ ++/* ecp_stop_ack_timer - stop the ECP ack timer ++ * @vd: vdp_data for the interface ++ * ++ * returns the number of removed handlers ++ * ++ * stops the ECP ack timer. Used e.g. when the host interface goes down. ++ */ ++static int ecp_stop_ack_timer(struct vdp_data *vd) ++{ ++ LLDPAD_DBG("%s:%s stopping ecp ack timer\n", __func__, vd->ecp.ifname); ++ return eloop_cancel_timeout(ecp_ack_timeout_handler, NULL, (void *) vd); ++} ++ ++/* ecp_tx_stop_ackTimer - stop the ECP ack timer ++ * @vd: currently used port ++ * ++ * returns the number of removed handlers ++ * ++ * stops the ECP ack timer. used when a ack frame for the port has been ++ * received. ++ */ ++static void ecp_tx_stop_ackTimer(struct vdp_data *vd) ++{ ++ vd->ecp.ackTimer = ECP_ACK_TIMER_STOPPED; ++ LLDPAD_DBG("%s:%s stopped ecp ack timer\n", __func__, vd->ecp.ifname); ++ ecp_stop_ack_timer(vd); ++} ++ ++int ecp_deinit(char *ifname) ++{ ++ struct vdp_data *vd; ++ ++ LLDPAD_DBG("%s:%s stopping ECP\n", __func__, ifname); ++ vd = vdp_data(ifname); ++ if (!vd) { ++ LLDPAD_ERR("%s:%s unable to find vd\n", __func__, ifname); ++ return -1; ++ } ++ ++ ecp_stop_ack_timer(vd); ++ ecp_stop_localchange_timer(vd); ++ ecp_tx_stop_ackTimer(vd); ++ return 0; ++} ++ ++static const char *ecp_tx_states[] = { ++ "ECP_TX_INIT_TRANSMIT", ++ "ECP_TX_TRANSMIT_ECPDU", ++ "ECP_TX_WAIT_FOR_ACK", ++ "ECP_TX_REQUEST_PDU" ++}; ++ ++/* ecp_somethingChangedLocal - set flag if port has changed ++ * @vd: port to set the flag for ++ * @mode: mode to set the flag to ++ * ++ * no return value ++ * ++ * set the localChange flag with a mode to indicate a port has changed. ++ * used to signal an ecpdu needs to be sent out. ++ */ ++ ++void ecp_somethingChangedLocal(struct vdp_data *vd, bool flag) ++{ ++ if (!vd) ++ return; ++ ++ LLDPAD_DBG("%s:%s vd->ecp.tx.localChange to %s\n", __func__, ++ vd->ecp.ifname, (flag == true) ? "true" : "false"); ++ vd->ecp.tx.localChange = flag; ++ ecp_start_localchange_timer(vd); ++} ++ ++/* ++ * Append some data at the end of the transmit data buffer. Make sure the ++ * End TLV always fits into the buffer. ++ */ ++static u8 end_tlv[2] = { 0x0, 0x0 }; /* END TLV */ ++ ++static int ecp_append(u8 *buffer, u32 *pos, void *data, u32 len) ++{ ++ if (*pos + len > ETH_FRAME_LEN - sizeof end_tlv) ++ return 0; ++ memcpy(buffer + *pos, data, len); ++ *pos += len; ++ return 1; ++} ++ ++/* ecp_build_ECPDU - create an ecp protocol data unit ++ * @vd: currently used port ++ * ++ * returns true on success, false on failure ++ * ++ * creates the frame header with the ports mac address, the ecp header with REQ ++ * plus a list of packed TLVs created from the profiles on this ++ * port. ++ */ ++static bool ecp_build_ECPDU(struct vdp_data *vd) ++{ ++ struct l2_ethhdr eth; ++ struct ecp_hdr ecp_hdr; ++ u8 own_addr[ETH_ALEN]; ++ u32 fb_offset = 0; ++ struct packed_tlv *ptlv = NULL; ++ struct vsi_profile *p; ++ int rc; ++ ++ /* TODO: use LLDP group MAC addresses to support ++ * S-channels/multichannel ++ */ ++ memcpy(eth.h_dest, nearest_bridge, ETH_ALEN); ++ l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr); ++ memcpy(eth.h_source, &own_addr, ETH_ALEN); ++ eth.h_proto = htons(ETH_P_ECP); ++ memset(vd->ecp.tx.frame, 0, sizeof vd->ecp.tx.frame); ++ ecp_append(vd->ecp.tx.frame, &fb_offset, (void *)ð, sizeof eth); ++ ++ ecp_hdr.oui[0] = 0x0; ++ ecp_hdr.oui[1] = 0x1b; ++ ecp_hdr.oui[2] = 0x3f; ++ ecp_hdr.pad1 = 0x0; ++ ecp_hdr.subtype = ECP_SUBTYPE; ++ ecp_hdr.mode = ECP_REQUEST; ++ ++ vd->ecp.lastSequence++; ++ ecp_hdr.seqnr = htons(vd->ecp.lastSequence); ++ ecp_append(vd->ecp.tx.frame, &fb_offset, (void *)&ecp_hdr, ++ sizeof ecp_hdr); ++ ++ /* create packed_tlvs for all profiles on this interface */ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ ++ if (!p->localChange) { ++ LLDPAD_DBG("%s:%s skipping unchanged profile\n", ++ __func__, vd->ecp.ifname); ++ continue; ++ } ++ ++ ptlv = vdp_gettlv(vd, p); ++ ++ if (!ptlv) { ++ LLDPAD_DBG("%s:%s ptlv not created\n", __func__, ++ vd->ecp.ifname); ++ continue; ++ } ++ ++ rc = ecp_append(vd->ecp.tx.frame, &fb_offset, ptlv->tlv, ++ ptlv->size); ++ ptlv = free_pkd_tlv(ptlv); ++ if (rc) ++ p->seqnr = vd->ecp.lastSequence; ++ else ++ break; ++ } ++ ecp_append(vd->ecp.tx.frame, &fb_offset, end_tlv, sizeof end_tlv); ++ vd->ecp.tx.frame_len = MAX(fb_offset, (unsigned)ETH_ZLEN); ++ return true; ++} ++ ++/* ecp_tx_Initialize - initializes the ecp tx state machine ++ * @vd: currently used port ++ * ++ * no return value ++ * ++ * initializes some variables for the ecp tx state machine. ++ */ ++static void ecp_tx_Initialize(struct vdp_data *vd) ++{ ++ memset(vd->ecp.tx.frame, 0, sizeof vd->ecp.tx.frame); ++ ecp_somethingChangedLocal(vd, true); ++ vd->ecp.lastSequence = ECP_SEQUENCE_NR_START; ++ vd->ecp.stats.statsFramesOutTotal = 0; ++ vd->ecp.ackTimer = ECP_ACK_TIMER_STOPPED; ++ vd->ecp.retries = 0; ++} ++ ++/* ecp_txFrame - transmit ecp frame ++ * @vd: currently used port ++ * ++ * returns the number of characters sent on success, -1 on failure ++ * ++ * sends out the frame stored in the frame structure using l2_packet_send. ++ */ ++static u8 ecp_txFrame(struct vdp_data *vd) ++{ ++ int status = 0; ++ ++ status = l2_packet_send(vd->ecp.l2, (u8 *)&nearest_bridge, ++ htons(ETH_P_ECP), vd->ecp.tx.frame, vd->ecp.tx.frame_len); ++ vd->ecp.stats.statsFramesOutTotal++; ++ vd->ecp.tx.frame_len = 0; ++ return status; ++} ++ ++/* ecp_tx_create_frame - create ecp frame ++ * @vd: currently used port ++ * ++ * no return value ++ */ ++static void ecp_tx_create_frame(struct vdp_data *vd) ++{ ++ /* send REQs */ ++ if (vd->ecp.tx.localChange) { ++ int ret; ++ ++ LLDPAD_DBG("%s:%s sending REQs\n", __func__, vd->ecp.ifname); ++ ret = ecp_build_ECPDU(vd); ++ ++ /* ECPDU construction succesful, send out frame */ ++ if (ret == true) { ++ hexdump_frame(vd->ecp.ifname, "frame-out", ++ vd->ecp.tx.frame, vd->ecp.tx.frame_len); ++ ecp_txFrame(vd); ++ } ++ } ++ ++ ecp_somethingChangedLocal(vd, false); ++} ++ ++/* ecp_tx_start_ackTimer - starts the ECP ack timer ++ * @vd: vdp_data to process ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the ack timer when a frame has been sent out. ++ */ ++static void ecp_tx_start_ackTimer(struct vdp_data *vd) ++{ ++ vd->ecp.ackTimer = ECP_ACK_TIMER_DEFAULT; ++ LLDPAD_DBG("%s-%s: starting ecp ack timer\n", __func__, vd->ifname); ++ ecp_start_ack_timer(vd); ++} ++ ++/* ecp_tx_change_state - changes the ecp tx sm state ++ * @vd: currently used port ++ * @newstate: new state for the sm ++ * ++ * no return value ++ * ++ * checks state transistion for consistency and finally changes the state of ++ * the profile. ++ */ ++static void ecp_tx_change_state(struct vdp_data *vd, u8 newstate) ++{ ++ switch(newstate) { ++ case ECP_TX_INIT_TRANSMIT: ++ break; ++ case ECP_TX_TRANSMIT_ECPDU: ++ assert((vd->ecp.tx.state == ECP_TX_INIT_TRANSMIT) || ++ (vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK) || ++ (vd->ecp.tx.state == ECP_TX_REQUEST_PDU)); ++ break; ++ case ECP_TX_WAIT_FOR_ACK: ++ assert(vd->ecp.tx.state == ECP_TX_TRANSMIT_ECPDU); ++ break; ++ case ECP_TX_REQUEST_PDU: ++ assert(vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK); ++ break; ++ default: ++ LLDPAD_ERR("%s: LLDP TX state machine invalid state %d\n", ++ vd->ifname, newstate); ++ } ++ LLDPAD_DBG("%s-%s: state change %s -> %s\n", __func__, ++ vd->ifname, ecp_tx_states[vd->ecp.tx.state], ++ ecp_tx_states[newstate]); ++ vd->ecp.tx.state = newstate; ++ return; ++} ++ ++/* ecp_set_tx_state - sets the ecp tx sm state ++ * @vd: currently used port ++ * ++ * returns true or false ++ * ++ * switches the state machine to the next state depending on the input ++ * variables. returns true or false depending on wether the state machine ++ * can be run again with the new state or can stop at the current state. ++ */ ++static bool ecp_set_tx_state(struct vdp_data *vd) ++{ ++ struct port *port = port_find_by_ifindex(get_ifidx(vd->ifname)); ++ ++ if (!port) { ++ LLDPAD_ERR("%s: port not found\n", __func__); ++ return 0; ++ } ++ ++ if (!port->portEnabled && port->prevPortEnabled) { ++ LLDPAD_ERR("set_tx_state: port was disabled\n"); ++ ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT); ++ } ++ port->prevPortEnabled = port->portEnabled; ++ ++ switch (vd->ecp.tx.state) { ++ case ECP_TX_INIT_TRANSMIT: ++ if (port->portEnabled && vd->enabletx && ++ vd->ecp.tx.localChange) { ++ ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); ++ return true; ++ } ++ return false; ++ case ECP_TX_TRANSMIT_ECPDU: ++ if (!vd->enabletx) { ++ ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT); ++ return true; ++ } ++ ecp_tx_change_state(vd, ECP_TX_WAIT_FOR_ACK); ++ return false; ++ case ECP_TX_WAIT_FOR_ACK: ++ if (ecp_ackTimer_expired(vd)) { ++ vd->ecp.retries++; ++ if (vd->ecp.retries < ECP_MAX_RETRIES) { ++ ecp_somethingChangedLocal(vd, true); ++ ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); ++ return true; ++ } ++ if (vd->ecp.retries == ECP_MAX_RETRIES) { ++ LLDPAD_DBG("%s-%s: retries expired\n", ++ __func__, vd->ifname); ++ ecp_tx_stop_ackTimer(vd); ++ ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU); ++ return true; ++ } ++ } ++ if (vd->ecp.ackReceived && ++ vd->ecp.seqECPDU == vd->ecp.lastSequence) { ++ vd->ecp.ackReceived = false; ++ if (vdp_vsis_pending(vd)) { ++ LLDPAD_DBG("%s-%s: still work pending\n", ++ __func__, vd->ifname); ++ ecp_somethingChangedLocal(vd, true); ++ } ++ ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU); ++ return true; ++ } ++ return false; ++ case ECP_TX_REQUEST_PDU: ++ if (vd->ecp.tx.localChange) { ++ ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); ++ return true; ++ } ++ return false; ++ default: ++ LLDPAD_ERR("%s: LLDP TX state machine in invalid state %d\n", ++ vd->ifname, vd->ecp.tx.state); ++ return false; ++ } ++} ++ ++/* ecp_tx_run_sm - state machine for ecp tx ++ * @vd: currently used vdp_data ++ * ++ * no return value ++ * ++ * runs the state machine for ecp tx. ++ */ ++void ecp_tx_run_sm(struct vdp_data *vd) ++{ ++ do { ++ LLDPAD_DBG("%s-%s: ecp_tx - %s\n", __func__, ++ vd->ifname, ecp_tx_states[vd->ecp.tx.state]); ++ ++ switch(vd->ecp.tx.state) { ++ case ECP_TX_INIT_TRANSMIT: ++ ecp_tx_Initialize(vd); ++ break; ++ case ECP_TX_TRANSMIT_ECPDU: ++ ecp_tx_create_frame(vd); ++ ecp_tx_start_ackTimer(vd); ++ ecp_somethingChangedLocal(vd, false); ++ break; ++ case ECP_TX_WAIT_FOR_ACK: ++ if (vd->ecp.ackReceived) { ++ LLDPAD_DBG("%s-%s: ECP_TX_WAIT_FOR_ACK " ++ "ackReceived seqECPDU %#x " ++ "lastSequence %#x\n", __func__, ++ vd->ifname, vd->ecp.seqECPDU, ++ vd->ecp.lastSequence); ++ ecp_somethingChangedLocal(vd, false); ++ ecp_tx_stop_ackTimer(vd); ++ } ++ break; ++ case ECP_TX_REQUEST_PDU: ++ vd->ecp.retries = 0; ++ LLDPAD_DBG("%s-%s: ECP_TX_REQUEST_PDU lastSeq %#x\n", ++ __func__, vd->ifname, vd->ecp.lastSequence); ++ break; ++ default: ++ LLDPAD_ERR("%s: LLDP TX state machine in invalid state %d\n", ++ vd->ifname, vd->ecp.tx.state); ++ } ++ } while (ecp_set_tx_state(vd) == true); ++} ++ ++static const char *ecp_rx_states[] = { ++ "ECP_RX_IDLE", ++ "ECP_RX_INIT_RECEIVE", ++ "ECP_RX_RECEIVE_WAIT", ++ "ECP_RX_RECEIVE_ECPDU", ++ "ECP_RX_SEND_ACK", ++ "ECP_RX_RESEND_ACK", ++}; ++ ++/* ecp_rx_Initialize - initializes the ecp rx state machine ++ * @vd: vd for the state machine ++ * ++ * no return value ++ * ++ * initialize some variables, get rid of old frame if necessary ++ */ ++static void ecp_rx_Initialize(struct vdp_data *vd) ++{ ++ vd->ecp.rx.rcvFrame = false; ++ vd->ecp.ackReceived = false; ++ vd->ecp.rx.frame_len = 0; ++} ++ ++/* ecp_rx_SendAckFrame - send ack frame ++ * @vd: port used by ecp ++ * ++ * currently always returns 0 ++ * ++ * copies current received frame over to frame out, fills in address of this ++ * port and set mode field to ACK. used by ecp_rx_send_ack_frame. ++ */ ++static int ecp_rx_SendAckFrame(struct vdp_data *vd) ++{ ++ u16 tlv_offset = 0; ++ struct ecp_hdr *ecp_hdr; ++ struct l2_ethhdr *hdr; ++ u8 own_addr[ETH_ALEN]; ++ ++ LLDPAD_DBG("%s:%s acking frame\n", __func__, vd->ecp.ifname); ++ /* copy over to transmit buffer */ ++ memcpy(vd->ecp.tx.frame, vd->ecp.rx.frame, vd->ecp.rx.frame_len); ++ vd->ecp.tx.frame_len = vd->ecp.rx.frame_len; ++ ++ /* use my own addr to send ACK */ ++ hdr = (struct l2_ethhdr *)vd->ecp.tx.frame; ++ l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr); ++ memcpy(hdr->h_source, &own_addr, ETH_ALEN); ++ ++ tlv_offset = sizeof(struct l2_ethhdr); ++ ecp_hdr = (struct ecp_hdr *)&vd->ecp.tx.frame[tlv_offset]; ++ ecp_hdr->mode = ECP_ACK; ++ ++ tlv_offset = sizeof(struct l2_ethhdr) + sizeof(struct ecp_hdr); ++ LLDPAD_DBG("%s:%s zeroing out rest of ack frame from %i to %i\n", ++ __func__, vd->ecp.ifname, tlv_offset, vd->ecp.rx.frame_len); ++ memset(&vd->ecp.tx.frame[tlv_offset], 0, ++ vd->ecp.rx.frame_len - tlv_offset); ++ return 0; ++} ++ ++/* ecp_rx_send_ack_frame - send out ack frame for received frame ++ * @vd: vd for the state machine ++ * ++ * no return value ++ * ++ * creates an ack frame for a just received frame, prints the about to be ++ * sent frame and finally transmits it. ++ */ ++void ecp_rx_send_ack_frame(struct vdp_data *vd) ++{ ++ ecp_rx_SendAckFrame(vd); ++ hexdump_frame(vd->ecp.ifname, "frame-ack", vd->ecp.tx.frame, ++ vd->ecp.tx.frame_len); ++ ecp_txFrame(vd); ++} ++ ++/* ecp_rx_ReceiveFrame - receive ecp frame ++ * @ctx: rx callback context, struct vd * in this case ++ * @ifindex: index of interface ++ * @buf: buffer which contains the frame just received ++ * @len: size of buffer (frame) ++ * ++ * no return value ++ * ++ * creates a local copy of the buffer and checks the header. keeps some ++ * statistics about ecp frames. Checks if it is a request or an ack frame ++ * and branches to ecp rx or ecp tx state machine. ++ */ ++static void ecp_rx_ReceiveFrame(void *ctx, UNUSED int ifindex, const u8 *buf, ++ size_t len) ++{ ++ struct vdp_data *vd; ++ struct port *port; ++ u8 frame_error = 0; ++ u16 tlv_offset; ++ struct l2_ethhdr *hdr; ++ struct l2_ethhdr example_hdr,*ex; ++ struct ecp_hdr *ecp_hdr; ++ ++ if (!ctx) { ++ LLDPAD_WARN("%s: no ctx - can't process frame\n", __func__); ++ return; ++ } ++ ++ vd = (struct vdp_data *)ctx; ++ port = port_find_by_ifindex(get_ifidx(vd->ifname)); ++ if (!port) ++ return; ++ ++ LLDPAD_DBG("%s:%s received packet with size %i\n", __func__, ++ vd->ecp.ifname, (int)len); ++ if (vd->enabletx == false) ++ return; ++ ++ if (vd->ecp.rx.frame_len == len && ++ (memcmp(buf, vd->ecp.rx.frame, len) == 0)) { ++ vd->ecp.stats.statsFramesInTotal++; ++ return; ++ } ++ ++ memset(vd->ecp.rx.frame, 0, len); ++ memcpy(vd->ecp.rx.frame, buf, len); ++ ++ vd->ecp.rx.frame_len = (u16)len; ++ ex = &example_hdr; ++ memcpy(ex->h_dest, nearest_bridge, ETH_ALEN); ++ ex->h_proto = htons(ETH_P_ECP); ++ hdr = (struct l2_ethhdr *)vd->ecp.rx.frame; ++ ++ if ((memcmp(hdr->h_dest, ex->h_dest, ETH_ALEN) != 0)) { ++ LLDPAD_ERR("%s:%s ERROR multicast address error in incoming frame." ++ " Dropping frame.\n", __func__, vd->ecp.ifname); ++ frame_error++; ++ return; ++ } ++ ++ if (hdr->h_proto != example_hdr.h_proto) { ++ LLDPAD_ERR("%s:%s ERROR ethertype %#x not ECP ethertype", ++ __func__, vd->ecp.ifname, htons(hdr->h_proto)); ++ frame_error++; ++ return; ++ } ++ ++ if (!frame_error) { ++ vd->ecp.stats.statsFramesInTotal++; ++ vd->ecp.rx.rcvFrame = true; ++ } ++ ++ tlv_offset = sizeof(struct l2_ethhdr); ++ ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; ++ vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr); ++ hexdump_frame(vd->ecp.ifname, "frame-in", vd->ecp.rx.frame, ++ vd->ecp.rx.frame_len); ++ ++ switch(ecp_hdr->mode) { ++ case ECP_REQUEST: ++ LLDPAD_DBG("%s:%s received REQ frame\n", __func__, ++ vd->ecp.ifname); ++ vd->ecp.ackReceived = false; ++ ecp_rx_run_sm(vd); ++ break; ++ case ECP_ACK: ++ LLDPAD_DBG("%s:%s received ACK frame\n", __func__, ++ vd->ecp.ifname); ++ vd->ecp.ackReceived = true; ++ vdp_ack_profiles(vd, vd->ecp.seqECPDU); ++ ecp_tx_run_sm(vd); ++ vd->ecp.ackReceived = false; ++ break; ++ default: ++ LLDPAD_ERR("%s:%s ERROR: unknown mode %i\n", __func__, ++ vd->ecp.ifname, ecp_hdr->mode); ++ return; ++ } ++ ++} ++ ++/* ecp_rx_change_state - changes the ecp rx sm state ++ * @vd: currently used port ++ * @newstate: new state for the sm ++ * ++ * no return value ++ * ++ * checks state transistion for consistency and finally changes the state of ++ * the profile. ++ */ ++static void ecp_rx_change_state(struct vdp_data *vd, u8 newstate) ++{ ++ switch(newstate) { ++ case ECP_RX_IDLE: ++ break; ++ case ECP_RX_INIT_RECEIVE: ++ break; ++ case ECP_RX_RECEIVE_WAIT: ++ assert((vd->ecp.rx.state == ECP_RX_INIT_RECEIVE) || ++ (vd->ecp.rx.state == ECP_RX_IDLE) || ++ (vd->ecp.rx.state == ECP_RX_SEND_ACK) || ++ (vd->ecp.rx.state == ECP_RX_RESEND_ACK)); ++ break; ++ case ECP_RX_RECEIVE_ECPDU: ++ assert(vd->ecp.rx.state == ECP_RX_RECEIVE_WAIT); ++ break; ++ case ECP_RX_SEND_ACK: ++ assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU); ++ break; ++ case ECP_RX_RESEND_ACK: ++ assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU); ++ break; ++ default: ++ LLDPAD_ERR("%s:%s LLDP RX state machine invalid state %d\n", ++ __func__, vd->ecp.ifname, newstate); ++ } ++ ++ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, ++ vd->ecp.ifname, ecp_rx_states[vd->ecp.rx.state], ++ ecp_rx_states[newstate]); ++ ++ vd->ecp.rx.state = newstate; ++} ++ ++/* ecp_init - initialize ecp module ++ * @ifname: interface for which the module is initialized ++ * ++ * returns 0 on success, -1 on error ++ * ++ * finds the port to the interface name, sets up the receive handle for ++ * incoming ecp frames and initializes the ecp rx and tx state machines. ++ * should usually be called when a successful exchange of EVB TLVs has been ++ * made and ECP and VDP protocols are supported by both sides. ++ */ ++int ecp_init(char *ifname) ++{ ++ struct vdp_data *vd; ++ ++ LLDPAD_DBG("%s:%s starting ECP\n", __func__, ifname); ++ vd = vdp_data(ifname); ++ if (!vd) { ++ LLDPAD_ERR("%s:%s unable to find vd\n", __func__, ifname); ++ return -1; ++ } ++ ++ if (!vd->ecp.l2) ++ vd->ecp.l2 = l2_packet_init(vd->ifname, NULL, ETH_P_ECP, ++ ecp_rx_ReceiveFrame, vd, 1); ++ ++ if (!vd->ecp.l2) { ++ LLDPAD_ERR("%s:%s failed to access layer 2 access ETH_P_ECP\n", ++ __func__, ifname); ++ return -1; ++ } ++ strncpy(vd->ecp.ifname, ifname, sizeof vd->ecp.ifname); ++ ecp_rx_change_state(vd, ECP_RX_IDLE); ++ ecp_rx_run_sm(vd); ++ ecp_somethingChangedLocal(vd, true); ++ return 0; ++} ++ ++/* ecp_rx_validate_frame - validates received frame ++ * @vd: vdp_data used by ecp ++ * ++ * no return value ++ * ++ * checks wether received frame has correct subtype and mode ++ */ ++ ++static void ecp_rx_validate_frame(struct vdp_data *vd) ++{ ++ u16 tlv_offset = 0; ++ struct ecp_hdr *ecp_hdr; ++ ++ LLDPAD_DBG("%s:%s validating frame\n", __func__, vd->ecp.ifname); ++ tlv_offset = sizeof(struct l2_ethhdr); ++ ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; ++ LLDPAD_DBG("%s:%s ecp packet with subtype %#x mode %#x seq %#04x\n", ++ __func__, vd->ecp.ifname, ecp_hdr->subtype, ecp_hdr->mode, ++ ntohs(ecp_hdr->seqnr)); ++ ++ if (ecp_hdr->subtype != ECP_SUBTYPE) { ++ LLDPAD_ERR("%s:%s ERROR: unknown subtype\n", __func__, ++ vd->ecp.ifname); ++ return; ++ } ++ ++ if ((ecp_hdr->oui[0] != 0x0) || (ecp_hdr->oui[1] != 0x1b) || ++ (ecp_hdr->oui[2] != 0x3f)) { ++ LLDPAD_ERR("%s:%s ERROR: incorrect OUI 0x%02x%02x%02x\n", ++ __func__, vd->ecp.ifname, ecp_hdr->oui[0], ++ ecp_hdr->oui[1], ecp_hdr->oui[2]); ++ return; ++ } ++ ++ switch(ecp_hdr->mode) { ++ case ECP_REQUEST: ++ break; ++ case ECP_ACK: ++ break; ++ default: ++ LLDPAD_ERR("%s:%s ERROR: unknown mode %i\n", __func__, ++ vd->ecp.ifname, ecp_hdr->mode); ++ return; ++ } ++ ++ /* FIXME: also done in ecp_rx_ReceiveFrame, ++ * are both necessary ? */ ++ vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr); ++} ++ ++/* ecp_rx_ProcessFrame - process received ecp frames ++ * @vd: currently used port ++ * ++ * no return value ++ * ++ * walks through the packed vsi tlvs in an ecp frame, extracts them ++ * and passes them to the VDP ULP with vdp_indicate. ++ */ ++static void ecp_rx_ProcessFrame(struct vdp_data *vd) ++{ ++ u16 tlv_cnt = 0; ++ u8 tlv_type = 0; ++ u16 tlv_length = 0; ++ u16 tlv_offset = 0; ++ u16 *tlv_head_ptr = NULL; ++ u8 frame_error = 0; ++ bool tlv_stored = false; ++ struct ecp_hdr *ecp_hdr; ++ int vdp_called; ++ ++ LLDPAD_DBG("%s:%s processing frame\n", __func__, vd->ecp.ifname); ++ tlv_offset = sizeof(struct l2_ethhdr); ++ ++ ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; ++ LLDPAD_DBG("%s:%s ecp packet with subtype %#x mode %#x seq %#04x\n", ++ __func__, vd->ifname, ecp_hdr->subtype, ++ ecp_hdr->mode, ntohs(ecp_hdr->seqnr)); ++ if (ecp_hdr->mode == ECP_ACK) ++ return; ++ ++ /* processing of VSI_TLVs starts here */ ++ tlv_offset += sizeof(struct ecp_hdr); ++ vdp_called = 0; ++ do { ++ tlv_cnt++; ++ ++ if (tlv_offset > vd->ecp.rx.frame_len) { ++ LLDPAD_ERR("%s:%s ERROR: Frame overrun! tlv_offset %i" ++ " frame_len %i cnt %i\n", __func__, ++ vd->ecp.ifname, tlv_offset, ++ vd->ecp.rx.frame_len, tlv_cnt); ++ frame_error++; ++ goto out; ++ } ++ ++ if (tlv_offset + 2 > vd->ecp.rx.frame_len) { ++ LLDPAD_DBG("%s:%s tlv EOF problem size=%d offset=%d\n", ++ __func__, vd->ecp.ifname, ++ vd->ecp.rx.frame_len, tlv_offset); ++ frame_error++; ++ goto out; ++ } ++ ++ tlv_head_ptr = (u16 *)&vd->ecp.rx.frame[tlv_offset]; ++ tlv_length = htons(*tlv_head_ptr) & 0x01FF; ++ tlv_type = (u8)(htons(*tlv_head_ptr) >> 9); ++ ++ u16 tmp_offset = tlv_offset + tlv_length; ++ if (tmp_offset > vd->ecp.rx.frame_len) { ++ LLDPAD_ERR("%s:%s ERROR: Frame overflow: offset=%d " ++ "rx.size=%d\n", __func__, vd->ecp.ifname, ++ tmp_offset, vd->ecp.rx.frame_len); ++ frame_error++; ++ goto out; ++ } ++ ++ u8 *info = (u8 *)&vd->ecp.rx.frame[tlv_offset + ++ sizeof(*tlv_head_ptr)]; ++ ++ struct unpacked_tlv *tlv = create_tlv(); ++ ++ if (!tlv) { ++ LLDPAD_DBG("%s:%s failed malloc for incoming TLV\n", ++ __func__, vd->ecp.ifname); ++ goto out; ++ } ++ ++ if ((tlv_length == 0) && (tlv->type != TYPE_0)) { ++ LLDPAD_DBG("%s:%s tlv_length == 0\n", __func__, ++ vd->ecp.ifname); ++ free_unpkd_tlv(tlv); ++ goto out; ++ } ++ ++ tlv->type = tlv_type; ++ tlv->length = tlv_length; ++ tlv->info = (u8 *)malloc(tlv_length); ++ if (tlv->info) { ++ memset(tlv->info,0, tlv_length); ++ memcpy(tlv->info, info, tlv_length); ++ } else { ++ LLDPAD_DBG("%s:%s failed malloc for incoming TLV info\n", ++ __func__, vd->ecp.ifname); ++ free_unpkd_tlv(tlv); ++ goto out; ++ } ++ ++ /* Validate the TLV */ ++ tlv_offset += sizeof(*tlv_head_ptr) + tlv_length; ++ ++ if (tlv->type == TYPE_127) { /* private TLV */ ++ /* give VSI TLV to VDP */ ++ if (!vdp_indicate(vd, tlv)) { ++ tlv_stored = true; ++ ++vdp_called; ++ } else { ++ /* TODO ++ * put it in a list and try again later until ++ * timer and retries have expired ++ */ ++ tlv_stored = false; ++ } ++ } ++ ++ if ((tlv->type != TYPE_0) && !tlv_stored) { ++ LLDPAD_DBG("%s:%s TLV (%u) was not stored (%p)\n", ++ __func__, vd->ecp.ifname, tlv->type, tlv); ++ tlv = free_unpkd_tlv(tlv); ++ vd->ecp.stats.statsTLVsUnrecognizedTotal++; ++ } ++ tlv = NULL; ++ tlv_stored = false; ++ } while (tlv_offset < vd->ecp.rx.frame_len); ++out: ++ if (frame_error) { ++ vd->ecp.stats.statsFramesDiscardedTotal++; ++ vd->ecp.stats.statsFramesInErrorsTotal++; ++ } ++ if (vdp_called) ++ vdp_advance_sm(vd); ++} ++ ++/* ecp_set_rx_state - sets the ecp rx sm state ++ * @vd: currently used port ++ * ++ * returns true or false ++ * ++ * switches the state machine to the next state depending on the input ++ * variables. returns true or false depending on wether the state machine ++ * can be run again with the new state or can stop at the current state. ++ */ ++static bool ecp_set_rx_state(struct vdp_data *vd) ++{ ++ struct port *port = port_find_by_ifindex(get_ifidx(vd->ifname)); ++ ++ if (!port) ++ return false; ++ ++ if (port->portEnabled == false) ++ ecp_rx_change_state(vd, ECP_RX_IDLE); ++ ++ switch(vd->ecp.rx.state) { ++ case ECP_RX_IDLE: ++ if (port->portEnabled == true) { ++ ecp_rx_change_state(vd, ECP_RX_INIT_RECEIVE); ++ return true; ++ } ++ return false; ++ case ECP_RX_INIT_RECEIVE: ++ if (vd->enabletx == true) { ++ ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT); ++ return true; ++ } ++ return false; ++ case ECP_RX_RECEIVE_WAIT: ++ if (vd->enabletx == false) { ++ ecp_rx_change_state(vd, ECP_RX_IDLE); ++ return true; ++ } ++ if (vd->ecp.rx.rcvFrame == true) { ++ ecp_rx_change_state(vd, ECP_RX_RECEIVE_ECPDU); ++ return true; ++ } ++ return false; ++ case ECP_RX_RECEIVE_ECPDU: ++ if (vd->ecp.seqECPDU == vd->ecp.lastSequence) { ++ LLDPAD_DBG("%s:%s seqECPDU %x, lastSequence %x\n", ++ __func__, vd->ecp.ifname, vd->ecp.seqECPDU, ++ vd->ecp.lastSequence); ++ ecp_rx_change_state(vd, ECP_RX_RESEND_ACK); ++ return true; ++ } ++ if (vd->ecp.seqECPDU != vd->ecp.lastSequence) { ++ ecp_rx_change_state(vd, ECP_RX_RESEND_ACK); ++ return true; ++ } ++ return false; ++ case ECP_RX_SEND_ACK: ++ case ECP_RX_RESEND_ACK: ++ ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT); ++ return false; ++ default: ++ LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", ++ __func__, vd->ecp.ifname, vd->ecp.rx.state); ++ return false; ++ } ++} ++ ++/* ecp_rx_run_sm - state machine for ecp rx ++ * @vd: currently used port ++ * ++ * no return value ++ * ++ * runs the state machine for ecp rx. ++ */ ++static void ecp_rx_run_sm(struct vdp_data *vd) ++{ ++ ecp_set_rx_state(vd); ++ do { ++ LLDPAD_DBG("%s:%s ecp_rx - %s\n", __func__, vd->ecp.ifname, ++ ecp_rx_states[vd->ecp.tx.state]); ++ ++ switch(vd->ecp.rx.state) { ++ case ECP_RX_IDLE: ++ break; ++ case ECP_RX_INIT_RECEIVE: ++ ecp_rx_Initialize(vd); ++ break; ++ case ECP_RX_RECEIVE_WAIT: ++ break; ++ case ECP_RX_RECEIVE_ECPDU: ++ vd->ecp.rx.rcvFrame = false; ++ ecp_rx_validate_frame(vd); ++ break; ++ case ECP_RX_SEND_ACK: ++ ecp_rx_ProcessFrame(vd); ++ break; ++ case ECP_RX_RESEND_ACK: ++ ecp_rx_ProcessFrame(vd); ++ if (!vd->ecp.ackReceived) { ++ ecp_rx_send_ack_frame(vd); ++ } ++ break; ++ default: ++ LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", ++ __func__, vd->ecp.ifname, vd->ecp.rx.state); ++ } ++ } while (ecp_set_rx_state(vd) == true); ++} +diff --git a/qbg/ecp22.c b/qbg/ecp22.c +new file mode 100644 +index 0000000..4640701 +--- /dev/null ++++ b/qbg/ecp22.c +@@ -0,0 +1,1055 @@ ++/****************************************************************************** ++ ++ Implementation of ECP according to 802.1Qbg ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Jens Osterkamp ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++#include "eloop.h" ++#include "qbg_ecp22.h" ++#include "messages.h" ++#include "qbg_utils.h" ++#include "lldp/l2_packet.h" ++#include "lldp_tlv.h" ++ ++#define ECP22_MAX_RETRIES_DEFAULT (3) /* Default # of max retries */ ++#define ECP22_ACK_TIMER_STOPPED (-1) ++/* ++ * Defaults to 2ms wait time for acknowledgement packet reception. ++ */ ++#define ECP22_ACK_TIMER_DEFAULT (8) ++ ++static void ecp22_tx_run_sm(struct ecp22 *); ++ ++static const char *const ecp22_rx_states[] = { /* Receive states verbatim */ ++ "ECP22_RX_BEGIN", ++ "ECP22_RX_WAIT", ++ "ECP22_RX_WAIT2", ++ "ECP22_RX_FIRST", ++ "ECP22_RX_REC_ECPDU", ++ "ECP22_RX_NEW_ECPDU", ++ "ECP22_RX_SEND_ACK" ++}; ++ ++static const char *const ecp22_tx_states[] = { /* Transmit states verbatim */ ++ "ECP22_TX_BEGIN", ++ "ECP22_TX_INIT", ++ "ECP22_TX_TXMIT_ECPDU", ++ "ECP22_TX_WAIT_FORREQ", ++ "ECP22_TX_WAIT_ONDATA", ++ "ECP22_TX_ERROR" ++}; ++ ++/* ++ * Increment sequence number. Do not return zero as sequence number. ++ */ ++static unsigned short inc_seqno(unsigned short x) ++{ ++ ++x; ++ if (!x) /* Wrapped */ ++ ++x; ++ return x; ++} ++ ++/* ++ * Find the ecp data associated with an interface. ++ * Return pointer or NULL if not found. ++ */ ++static struct ecp22 *find_ecpdata(char *ifname, struct ecp22_user_data *eud) ++{ ++ struct ecp22 *ecp = 0; ++ ++ if (eud) { ++ LIST_FOREACH(ecp, &eud->head, node) ++ if (!strncmp(ifname, ecp->ifname, IFNAMSIZ)) ++ break; ++ } ++ return ecp; ++} ++ ++/* ++ * ecp22_txframe - transmit ecp frame ++ * @ecp: pointer to currently used ecp data structure ++ * ++ * returns the number of characters sent on success, -1 on failure ++ * ++ * sends out the frame stored in the frame structure using l2_packet_send. ++ */ ++static int ecp22_txframe(struct ecp22 *ecp, char *txt, unsigned char *dst, ++ unsigned char *ack, size_t len) ++{ ++ hexdump_frame(ecp->ifname, txt, ack, len); ++ return l2_packet_send(ecp->l2, dst, htons(ETH_P_ECP22), ack, len); ++} ++ ++static void ecp22_append(u8 *buffer, u32 *pos, void *data, u32 len) ++{ ++ if (*pos + len > ETH_FRAME_LEN) ++ return; ++ memcpy(buffer + *pos, data, len); ++ *pos += len; ++} ++ ++/* ++ * Return a payload node to the freelist. ++ */ ++void ecp22_putnode(struct ecp22_freelist *list, struct ecp22_payload_node *elm) ++{ ++ elm->ptlv = free_pkd_tlv(elm->ptlv); ++ if (list->freecnt > ecp22_maxpayload) ++ free(elm); ++ else { ++ ++list->freecnt; ++ LIST_INSERT_HEAD(&list->head, elm, node); ++ } ++} ++ ++/* ++ * ecp22_build_ecpdu - create an ecp protocol data unit ++ * @ecp: pointer to currently used ecp data structure ++ * ++ * returns true on success, false on failure ++ * ++ * creates the frame header with the ports mac address, the ecp header with REQ ++ * plus a packed TLVs created taken from the send queue. ++ */ ++static bool ecp22_build_ecpdu(struct ecp22 *ecp) ++{ ++ struct l2_ethhdr eth; ++ struct ecp22_hdr ecph; ++ u32 fb_offset = 0; ++ struct packed_tlv *ptlv; ++ struct ecp22_payload_node *p = LIST_FIRST(&ecp->inuse.head); ++ ++ if (!p) ++ return false; ++ ecp->tx.ecpdu_received = true; /* Txmit buffer in use */ ++ memcpy(eth.h_dest, p->mac, ETH_ALEN); ++ l2_packet_get_own_src_addr(ecp->l2, eth.h_source); ++ eth.h_proto = htons(ETH_P_ECP22); ++ memset(ecp->tx.frame, 0, sizeof ecp->tx.frame); ++ ecp22_append(ecp->tx.frame, &fb_offset, (void *)ð, sizeof eth); ++ ++ ecp22_hdr_set_version(&ecph, 1); ++ ecp22_hdr_set_op(&ecph, ECP22_REQUEST); ++ ecp22_hdr_set_subtype(&ecph, ECP22_VDP); ++ ecph.ver_op_sub = htons(ecph.ver_op_sub); ++ ecph.seqno = htons(ecp->tx.seqno); ++ ecp22_append(ecp->tx.frame, &fb_offset, (void *)&ecph, sizeof ecph); ++ ++ ptlv = p->ptlv; ++ ecp22_append(ecp->tx.frame, &fb_offset, ptlv->tlv, ptlv->size); ++ ecp->tx.frame_len = MAX(fb_offset, (unsigned)ETH_ZLEN); ++ LIST_REMOVE(p, node); ++ ecp22_putnode(&ecp->isfree, p); ++ LLDPAD_DBG("%s:%s seqno %#hx frame_len %#hx\n", __func__, ++ ecp->ifname, ecp->tx.seqno, ecp->tx.frame_len); ++ return true; ++} ++ ++/* ++ * Execute transmit state transmitECPDU. ++ */ ++static void ecp22_es_waitforreq(struct ecp22 *ecp) ++{ ++ ecp->tx.retries = 0; ++ ecp->tx.ack_received = false; ++ ecp->tx.ecpdu_received = false; ++ ecp->tx.seqno = inc_seqno(ecp->tx.seqno); ++ LLDPAD_DBG("%s:%s seqno %#hx\n", __func__, ecp->ifname, ecp->tx.seqno); ++} ++ ++/* ++ * Execute transmit state countErrors. ++ */ ++static void ecp22_es_counterror(struct ecp22 *ecp) ++{ ++ ++ecp->tx.errors; ++ LLDPAD_DBG("%s:%s errors %lu\n", __func__, ecp->ifname, ++ ecp->tx.errors); ++} ++ ++/* ++ * Execute transmit state initTransmit. ++ */ ++static void ecp22_es_inittransmit(struct ecp22 *ecp) ++{ ++ ecp->tx.errors = 0; ++ ecp->tx.seqno = 0; ++} ++ ++/* ++ * Return RTE value in milliseconds. ++ */ ++static int rtevalue(unsigned char rte) ++{ ++ return (1 << rte) * 10; ++} ++ ++/* ++ * ecp22_ack_timeout_handler - handles the ack timer expiry ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here ++ * ++ * no return value ++ * ++ * called when the ECP timer has expired. Calls the ECP station state machine. ++ */ ++static void ecp22_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) ++{ ++ struct ecp22 *ecp = (struct ecp22 *)user_ctx; ++ ++ LLDPAD_DBG("%s:%s retries:%d\n", __func__, ++ ecp->ifname, ecp->tx.retries); ++ ecp22_tx_run_sm(ecp); ++} ++ ++/* ++ * ecp22_tx_start_acktimer - starts the ECP ack timer ++ * @ecp: pointer to currently used ecp data structure ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the ack timer when a frame has been sent out. ++ */ ++static void ecp22_tx_start_acktimer(struct ecp22 *ecp) ++{ ++ unsigned long ack_sec = rtevalue(ecp->max_rte) / 1000000; ++ unsigned long ack_usec = rtevalue(ecp->max_rte) % 1000000; ++ ++ LLDPAD_DBG("%s:%s [%ld.%06ld]\n", __func__, ecp->ifname, ack_sec, ++ ack_usec); ++ eloop_register_timeout(ack_sec, ack_usec, ecp22_ack_timeout_handler, ++ 0, (void *)ecp); ++} ++ ++/* ++ * ecp22_tx_change_state - changes the ecp tx sm state ++ * @ecp: pointer to currently used ecp data structure ++ * @newstate: new state for the sm ++ * ++ * no return value ++ * ++ * checks state transistion for consistency and finally changes the state of ++ * the profile. ++ */ ++static void ecp22_tx_change_state(struct ecp22 *ecp, unsigned char newstate) ++{ ++ switch (newstate) { ++ case ECP22_TX_BEGIN: ++ break; ++ case ECP22_TX_INIT: ++ assert(ecp->tx.state == ECP22_TX_BEGIN); ++ break; ++ case ECP22_TX_WAIT_FORREQ: ++ assert(ecp->tx.state == ECP22_TX_INIT || ++ ecp->tx.state == ECP22_TX_ERROR || ++ ecp->tx.state == ECP22_TX_TXMIT_ECPDU); ++ break; ++ case ECP22_TX_WAIT_ONDATA: ++ assert(ecp->tx.state == ECP22_TX_WAIT_FORREQ); ++ break; ++ case ECP22_TX_TXMIT_ECPDU: ++ assert(ecp->tx.state == ECP22_TX_WAIT_ONDATA); ++ break; ++ case ECP22_TX_ERROR: ++ assert(ecp->tx.state == ECP22_TX_TXMIT_ECPDU); ++ break; ++ default: ++ LLDPAD_ERR("%s: ECP TX state machine invalid state %d\n", ++ ecp->ifname, newstate); ++ } ++ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, ++ ecp->ifname, ecp22_tx_states[ecp->tx.state], ++ ecp22_tx_states[newstate]); ++ ecp->tx.state = newstate; ++} ++ ++/* ++ * Send the payload data. ++ */ ++static int ecp22_es_txmit(struct ecp22 *ecp) ++{ ++ int rc = 0; ++ ++ ++ecp->tx.retries; ++ ecp22_txframe(ecp, "ecp-out", ecp->tx.frame, ecp->tx.frame, ++ ecp->tx.frame_len); ++ ecp22_tx_start_acktimer(ecp); ++ return rc; ++} ++ ++/* ++ * ecp22_set_tx_state - sets the ecp tx state machine state ++ * @ecp: pointer to currently used ecp data structure ++ * ++ * returns true or false ++ * ++ * switches the state machine to the next state depending on the input ++ * variables. returns true or false depending on wether the state machine ++ * can be run again with the new state or can stop at the current state. ++ */ ++static bool ecp22_set_tx_state(struct ecp22 *ecp) ++{ ++ struct port *port = port_find_by_ifindex(get_ifidx(ecp->ifname)); ++ ++ if (!port) { ++ LLDPAD_ERR("%s:%s port not found\n", __func__, ecp->ifname); ++ return false; ++ } ++ if (!port->portEnabled && port->prevPortEnabled) { ++ LLDPAD_ERR("%s:%s port was disabled\n", __func__, ecp->ifname); ++ ecp22_tx_change_state(ecp, ECP22_TX_BEGIN); ++ } ++ port->prevPortEnabled = port->portEnabled; ++ ++ switch (ecp->tx.state) { ++ case ECP22_TX_BEGIN: ++ ecp22_tx_change_state(ecp, ECP22_TX_INIT); ++ return true; ++ case ECP22_TX_INIT: ++ ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); ++ return true; ++ case ECP22_TX_WAIT_FORREQ: ++ ecp22_tx_change_state(ecp, ECP22_TX_WAIT_ONDATA); ++ return true; ++ case ECP22_TX_WAIT_ONDATA: ++ if (LIST_FIRST(&ecp->inuse.head)) { /* Data to send */ ++ ecp22_build_ecpdu(ecp); ++ ecp22_tx_change_state(ecp, ECP22_TX_TXMIT_ECPDU); ++ return true; ++ } ++ return false; ++ case ECP22_TX_TXMIT_ECPDU: ++ if (ecp->tx.ack_received) { ++ ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); ++ return true; ++ } ++ if (ecp->tx.retries > ecp->max_retries) { ++ ecp22_tx_change_state(ecp, ECP22_TX_ERROR); ++ return true; ++ } ++ return false; ++ case ECP22_TX_ERROR: ++ ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); ++ return true; ++ default: ++ LLDPAD_ERR("%s: ECP TX state machine in invalid state %d\n", ++ ecp->ifname, ecp->tx.state); ++ return false; ++ } ++} ++ ++/* ++ * ecp22_tx_run_sm - state machine for ecp transmit ++ * @ecp: pointer to currently used ecp data structure ++ * ++ * no return value ++ */ ++static void ecp22_tx_run_sm(struct ecp22 *ecp) ++{ ++ ecp22_set_tx_state(ecp); ++ do { ++ LLDPAD_DBG("%s:%s state %s\n", __func__, ++ ecp->ifname, ecp22_tx_states[ecp->tx.state]); ++ ++ switch (ecp->tx.state) { ++ case ECP22_TX_BEGIN: ++ break; ++ case ECP22_TX_INIT: ++ ecp22_es_inittransmit(ecp); ++ break; ++ case ECP22_TX_WAIT_FORREQ: ++ ecp22_es_waitforreq(ecp); ++ break; ++ case ECP22_TX_WAIT_ONDATA: ++ break; ++ case ECP22_TX_TXMIT_ECPDU: ++ ecp22_es_txmit(ecp); ++ break; ++ case ECP22_TX_ERROR: ++ ecp22_es_counterror(ecp); ++ break; ++ } ++ } while (ecp22_set_tx_state(ecp) == true); ++} ++ ++/* ++ * ecp22_rx_change_state - changes the ecp rx sm state ++ * @ecp: pointer to currently used ecp data structure ++ * @newstate: new state for the sm ++ * ++ * no return value ++ * ++ * checks state transistion for consistency and finally changes the state of ++ * the ecp receive buffer. ++ */ ++static void ecp22_rx_change_state(struct ecp22 *ecp, u8 newstate) ++{ ++ switch (newstate) { ++ case ECP22_RX_BEGIN: ++ break; ++ case ECP22_RX_WAIT: ++ assert(ecp->rx.state == ECP22_RX_BEGIN); ++ break; ++ case ECP22_RX_FIRST: ++ assert(ecp->rx.state == ECP22_RX_WAIT); ++ break; ++ case ECP22_RX_REC_ECPDU: ++ assert((ecp->rx.state == ECP22_RX_FIRST) || ++ (ecp->rx.state == ECP22_RX_WAIT2)); ++ break; ++ case ECP22_RX_NEW_ECPDU: ++ assert(ecp->rx.state == ECP22_RX_REC_ECPDU); ++ break; ++ case ECP22_RX_SEND_ACK: ++ assert((ecp->rx.state == ECP22_RX_REC_ECPDU) || ++ (ecp->rx.state == ECP22_RX_NEW_ECPDU)); ++ break; ++ case ECP22_RX_WAIT2: ++ assert(ecp->rx.state == ECP22_RX_SEND_ACK); ++ break; ++ default: ++ LLDPAD_ERR("%s:%s LLDP RX state machine invalid state %d\n", ++ __func__, ecp->ifname, newstate); ++ } ++ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, ++ ecp->ifname, ecp22_rx_states[ecp->rx.state], ++ ecp22_rx_states[newstate]); ++ ecp->rx.state = newstate; ++} ++ ++/* ++ * Execute action in state sendack. Construct and send an acknowledgement ++ * for the received ECP packet. ++ */ ++static void ecp22_es_send_ack(struct ecp22 *ecp) ++{ ++ unsigned char ack_frame[ETH_HLEN + sizeof(struct ecp22_hdr)]; ++ struct ethhdr *ethdst = (struct ethhdr *)ack_frame; ++ struct ecp22_hdr *ecpdst = (struct ecp22_hdr *)&ack_frame[ETH_HLEN]; ++ struct ethhdr *ethsrc = (struct ethhdr *)ecp->rx.frame; ++ struct ecp22_hdr *ecpsrc = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; ++ struct ecp22_hdr ack; ++ ++ LLDPAD_DBG("%s:%s state %s seqno %#hx\n", __func__, ecp->ifname, ++ ecp22_rx_states[ecp->rx.state], ecp->rx.seqno); ++ memcpy(ethdst->h_dest, nearest_customer_bridge, ETH_ALEN); ++ l2_packet_get_own_src_addr(ecp->l2, (u8 *)ðdst->h_source); ++ ethdst->h_proto = ethsrc->h_proto; ++ /* Set ECP header */ ++ ack.ver_op_sub = ntohs(ecpsrc->ver_op_sub); ++ ecp22_hdr_set_op(&ack, ECP22_ACK); ++ ecpdst->ver_op_sub = htons(ack.ver_op_sub); ++ ecpdst->seqno = htons(ecp->rx.seqno); ++ ecp22_txframe(ecp, "ecp-ack", ethsrc->h_source, ack_frame, ++ sizeof ack_frame); ++} ++ ++ ++/* ++ * Notify upper layer protocol function of ECP payload data just received. ++ */ ++static void ecp22_to_ulp(unsigned short ulp, struct ecp22 *ecp) ++{ ++ size_t offset = ETH_HLEN + sizeof(struct ecp22_hdr); ++ struct qbg22_imm to_ulp; ++ ++ to_ulp.data_type = ECP22_TO_ULP; ++ to_ulp.u.c.len = ecp->rx.frame_len - offset; ++ to_ulp.u.c.data = &ecp->rx.frame[offset]; ++ if (ulp == ECP22_VDP) ++ modules_notify(LLDP_MOD_VDP22, LLDP_MOD_ECP22, ecp->ifname, ++ &to_ulp); ++ else ++ LLDPAD_INFO("%s:%s ECP subtype %d not yet implemented\n", ++ __func__, ecp->ifname, ulp); ++} ++ ++/* ++ * Execute action in state newECPDU. ++ * Notify upper layer protocol of new data. ++ */ ++static void ecp22_es_new_ecpdu(struct ecp22 *ecp) ++{ ++ struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; ++ struct ecp22_hdr ecphdr; ++ unsigned short ulp; ++ ++ ecphdr.ver_op_sub = ntohs(hdr->ver_op_sub); ++ ulp = ecp22_hdr_read_subtype(&ecphdr); ++ LLDPAD_DBG("%s:%s state %s notify ULP %d seqno %#hx\n", __func__, ++ ecp->ifname, ecp22_rx_states[ecp->rx.state], ++ ulp, ecp->rx.seqno); ++ ecp->rx.last_seqno = ecp->rx.seqno; ++ ecp22_to_ulp(ulp, ecp); ++} ++ ++/* ++ * Execute action in state receiveECPDU. ++ */ ++static void ecp22_es_rec_ecpdu(struct ecp22 *ecp) ++{ ++ struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; ++ ++ ecp->rx.seqno = ntohs(hdr->seqno); ++ LLDPAD_DBG("%s:%s state %s seqno %#hx\n", __func__, ecp->ifname, ++ ecp22_rx_states[ecp->rx.state], ecp->rx.seqno); ++} ++ ++/* ++ * Execute action in state receiveFirst. ++ */ ++static void ecp22_es_first(struct ecp22 *ecp) ++{ ++ struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; ++ ++ LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, ++ ecp22_rx_states[ecp->rx.state]); ++ ecp->rx.last_seqno = ntohs(hdr->seqno) - 1; ++} ++ ++/* ++ * Execute action in state receiveWait. ++ */ ++static void ecp22_es_wait(struct ecp22 *ecp) ++{ ++ LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, ++ ecp22_rx_states[ecp->rx.state]); ++ ecp->rx.ecpdu_received = false; ++} ++ ++/* ++ * ecp22_set_rx_state - sets the ecp receive state machine state ++ * @ecp: pointer to currently used ecp data structure ++ * ++ * returns true or false ++ * ++ * switches the state machine to the next state depending on the input ++ * variables. Returns true or false depending on wether the state machine ++ * can be run again with the new state or can stop at the current state. ++ */ ++static bool ecp22_set_rx_state(struct ecp22 *ecp) ++{ ++ struct port *port = port_find_by_ifindex(get_ifidx(ecp->ifname)); ++ ++ if (!port) ++ return false; ++ ++ LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, ++ ecp22_rx_states[ecp->rx.state]); ++ if (!port->portEnabled) ++ ecp22_rx_change_state(ecp, ECP22_RX_BEGIN); ++ switch (ecp->rx.state) { ++ case ECP22_RX_BEGIN: ++ ecp22_rx_change_state(ecp, ECP22_RX_WAIT); ++ return false; ++ case ECP22_RX_WAIT: ++ if (ecp->rx.ecpdu_received) { ++ ecp22_rx_change_state(ecp, ECP22_RX_FIRST); ++ return true; ++ } ++ return false; ++ case ECP22_RX_WAIT2: ++ if (ecp->rx.ecpdu_received) { ++ ecp22_rx_change_state(ecp, ECP22_RX_REC_ECPDU); ++ return true; ++ } ++ return false; ++ case ECP22_RX_FIRST: ++ ecp22_rx_change_state(ecp, ECP22_RX_REC_ECPDU); ++ return true; ++ case ECP22_RX_REC_ECPDU: ++ if (ecp->rx.seqno == ecp->rx.last_seqno) ++ ecp22_rx_change_state(ecp, ECP22_RX_SEND_ACK); ++ else ++ ecp22_rx_change_state(ecp, ECP22_RX_NEW_ECPDU); ++ return true; ++ case ECP22_RX_NEW_ECPDU: ++ ecp22_rx_change_state(ecp, ECP22_RX_SEND_ACK); ++ return true; ++ case ECP22_RX_SEND_ACK: ++ ecp22_rx_change_state(ecp, ECP22_RX_WAIT2); ++ return true; ++ default: ++ LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", ++ __func__, ecp->ifname, ecp->rx.state); ++ return false; ++ } ++} ++ ++/* ++ * ecp22_rx_run_sm - state machine for ecp receive protocol ++ * @ecp: pointer to currently used ecp data structure ++ * ++ * no return value ++ * ++ * runs the state machine for ecp22 receive function. ++ */ ++static void ecp22_rx_run_sm(struct ecp22 *ecp) ++{ ++ ecp22_set_rx_state(ecp); ++ do { ++ switch (ecp->rx.state) { ++ case ECP22_RX_WAIT: ++ case ECP22_RX_WAIT2: ++ ecp22_es_wait(ecp); ++ break; ++ case ECP22_RX_FIRST: ++ ecp22_es_first(ecp); ++ break; ++ case ECP22_RX_REC_ECPDU: ++ ecp22_es_rec_ecpdu(ecp); ++ break; ++ case ECP22_RX_NEW_ECPDU: ++ ecp22_es_new_ecpdu(ecp); ++ break; ++ case ECP22_RX_SEND_ACK: ++ ecp22_es_send_ack(ecp); ++ break; ++ default: ++ LLDPAD_DBG("%s:%s ECP RX state machine in invalid " ++ "state %d\n", __func__, ecp->ifname, ++ ecp->rx.state); ++ } ++ } while (ecp22_set_rx_state(ecp) == true); ++} ++ ++/* ++ * Received an aknowledgement frame. ++ * Check if we have a transmit pending and the ack'ed packet number matches ++ * the send packet. ++ */ ++static void ecp22_recack_frame(struct ecp22 *ecp, unsigned short seqno) ++{ ++ LLDPAD_DBG("%s:%s txmit:%d seqno %#hx ack-seqno %#hx\n", __func__, ++ ecp->ifname, ecp->tx.ecpdu_received, ecp->tx.seqno, seqno); ++ if (ecp->tx.ecpdu_received) { ++ if (ecp->tx.seqno == seqno) ++ ecp->tx.ack_received = true; ++ } ++} ++ ++/* ++ * ecp22_rx_receiveframe - receive am ecp frame ++ * @ctx: rx callback context, struct ecp * in this case ++ * @ifindex: index of interface ++ * @buf: buffer which contains the frame just received ++ * @len: size of buffer (frame) ++ * ++ * no return value ++ * ++ * creates a local copy of the buffer and checks the header. keeps some ++ * statistics about ecp frames. Checks if it is a request or an ack frame and ++ * branches to ecp rx or ecp tx state machine. ++ */ ++static void ecp22_rx_receiveframe(void *ctx, int ifindex, const u8 *buf, ++ size_t len) ++{ ++ struct ecp22 *ecp = (struct ecp22 *)ctx; ++ struct port *port; ++ struct ecp22_hdr *ecp_hdr, ecphdr; ++ ++ LLDPAD_DBG("%s:%s ifindex:%d len:%zd state:%s ecpdu_received:%d\n", ++ __func__, ecp->ifname, ifindex, len, ++ ecp22_rx_states[ecp->rx.state], ecp->rx.ecpdu_received); ++ hexdump_frame(ecp->ifname, "frame-in", buf, len); ++ port = port_find_by_ifindex(get_ifidx(ecp->ifname)); ++ if (!port || ecp->rx.ecpdu_received) ++ /* Port not found or buffer not free */ ++ return; ++ ++ memcpy(ecp->rx.frame, buf, len); ++ ecp->rx.frame_len = len; ++ ecp->stats.statsFramesInTotal++; ++ ++ ecp_hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; ++ ecphdr.ver_op_sub = ntohs(ecp_hdr->ver_op_sub); ++ ++ /* Check for correct subtype and version number */ ++ if (ecp22_hdr_read_version(&ecphdr) != 1) { ++ LLDPAD_ERR("%s:%s ERROR unknown version %#02hx seqno %#hx\n", ++ __func__, ecp->ifname, ecphdr.ver_op_sub, ++ ntohs(ecp_hdr->seqno)); ++ return; ++ } ++ switch (ecp22_hdr_read_subtype(&ecphdr)) { ++ default: ++ LLDPAD_ERR("%s:%s ERROR unknown subtype %#02hx seqno %#hx\n", ++ __func__, ecp->ifname, ecphdr.ver_op_sub, ++ ntohs(ecp_hdr->seqno)); ++ return; ++ case ECP22_PECSP: ++ case ECP22_VDP: ++ /* Subtype ok, fall through intended */ ++ break; ++ } ++ ++ switch (ecp22_hdr_read_op(&ecphdr)) { ++ case ECP22_REQUEST: ++ LLDPAD_DBG("%s:%s received REQ frame seqno %#hx\n", __func__, ++ ecp->ifname, ntohs(ecp_hdr->seqno)); ++ ecp->rx.ecpdu_received = true; ++ ecp22_rx_run_sm(ecp); ++ break; ++ case ECP22_ACK: ++ LLDPAD_DBG("%s:%s received ACK frame seqno %#hx\n", __func__, ++ ecp->ifname, ntohs(ecp_hdr->seqno)); ++ ecp22_recack_frame(ecp, ntohs(ecp_hdr->seqno)); ++ break; ++ default: ++ LLDPAD_ERR("%s:%s ERROR unknown mode %#02hx seqno %#hx\n", ++ __func__, ecp->ifname, ecphdr.ver_op_sub, ++ ntohs(ecp_hdr->seqno)); ++ } ++} ++ ++/* ++ * ecp22_create - create data structure and initialize ecp protocol ++ * @ifname: interface for which the ecp protocol is initialized ++ * ++ * returns NULL on error and an pointer to the ecp22 structure on success. ++ * ++ * finds the port to the interface name, sets up the receive handle for ++ * incoming ecp frames and initializes the ecp rx and tx state machines. ++ * To be called when a successful exchange of EVB TLVs has been ++ * made and ECP protocols are supported by both sides. ++ */ ++static struct ecp22 *ecp22_create(char *ifname, struct ecp22_user_data *eud) ++{ ++ struct ecp22 *ecp; ++ ++ ecp = calloc(1, sizeof *ecp); ++ if (!ecp) { ++ LLDPAD_ERR("%s:%s unable to allocate ecp protocol\n", __func__, ++ ifname); ++ return NULL; ++ } ++ strncpy(ecp->ifname, ifname, sizeof ecp->ifname); ++ ecp->l2 = l2_packet_init(ecp->ifname, 0, ETH_P_ECP22, ++ ecp22_rx_receiveframe, ecp, 1); ++ ++ if (!ecp->l2) { ++ LLDPAD_ERR("%s:%s error open layer 2 ETH_P_ECP\n", __func__, ++ ifname); ++ free(ecp); ++ return NULL; ++ } ++ LIST_INSERT_HEAD(&eud->head, ecp, node); ++ LLDPAD_DBG("%s:%s create ecp data\n", __func__, ifname); ++ return ecp; ++} ++ ++/* ++ * ecp22_start - build up ecp structures for an interface ++ * @ifname: name of the interface ++ */ ++void ecp22_start(char *ifname) ++{ ++ struct ecp22_user_data *eud; ++ struct ecp22 *ecp; ++ ++ LLDPAD_DBG("%s:%s start ecp\n", __func__, ifname); ++ eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); ++ if (!eud) { ++ LLDPAD_DBG("%s:%s no ECP module\n", __func__, ifname); ++ return; ++ } ++ ecp = find_ecpdata(ifname, eud); ++ if (!ecp) ++ ecp = ecp22_create(ifname, eud); ++ ecp->max_retries = ECP22_MAX_RETRIES_DEFAULT; ++ ecp->max_rte = ECP22_ACK_TIMER_DEFAULT; ++ LIST_INIT(&ecp->inuse.head); ++ ecp->inuse.last = 0; ++ LIST_INIT(&ecp->isfree.head); ++ ecp->isfree.freecnt = 0; ++ ecp->rx.state = ECP22_RX_BEGIN; ++ ecp22_rx_run_sm(ecp); ++ ecp->tx.state = ECP22_TX_BEGIN; ++ ecp22_tx_run_sm(ecp); ++} ++ ++/* ++ * Remove the ecp_payload nodes ++ */ ++static void ecp22_removelist(ecp22_list *ptr) ++{ ++ struct ecp22_payload_node *np; ++ ++ while ((np = LIST_FIRST(ptr))) { ++ LIST_REMOVE(np, node); ++ np->ptlv = free_pkd_tlv(np->ptlv); ++ free(np); ++ } ++} ++ ++static void ecp22_remove(struct ecp22 *ecp) ++{ ++ LLDPAD_DBG("%s:%s remove ecp\n", __func__, ecp->ifname); ++ ecp22_removelist(&ecp->inuse.head); ++ ecp->inuse.last = 0; ++ ecp22_removelist(&ecp->isfree.head); ++ ecp->isfree.freecnt = 0; ++ LIST_REMOVE(ecp, node); ++ free(ecp); ++} ++ ++/* ++ * ecp22_stop - tear down ecp structures for a interface ++ * @ifname: name of the interface ++ * ++ * no return value ++ * ++ */ ++void ecp22_stop(char *ifname) ++{ ++ struct ecp22_user_data *eud; ++ struct ecp22 *ecp; ++ ++ LLDPAD_DBG("%s:%s stop ecp\n", __func__, ifname); ++ eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); ++ ecp = find_ecpdata(ifname, eud); ++ if (ecp) ++ ecp22_remove(ecp); ++} ++ ++/* ++ * Update data exchanged via EVB protocol. ++ * Returns true when data update succeeded. ++ */ ++static int ecp22_data_from_evb(char *ifname, struct evb22_to_ecp22 *ptr) ++{ ++ struct ecp22_user_data *eud; ++ struct ecp22 *ecp; ++ ++ eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); ++ ecp = find_ecpdata(ifname, eud); ++ if (ecp) { ++ ecp->max_rte = ptr->max_rte; ++ ecp->max_retries = ptr->max_retry; ++ LLDPAD_DBG("%s:%s max_rte:%d max_retries:%d\n", __func__, ++ ifname, ecp->max_rte, ecp->max_retries); ++ return 0; ++ } ++ return -ENOENT; ++} ++ ++/* ++ * Add ecp payload data at the end of the queue. ++ */ ++static void ecp22_add_payload(struct ecp22 *ecp, ++ struct ecp22_payload_node *elem) ++{ ++ if (LIST_EMPTY(&ecp->inuse.head)) ++ LIST_INSERT_HEAD(&ecp->inuse.head, elem, node); ++ else ++ LIST_INSERT_AFTER(ecp->inuse.last, elem, node); ++ ecp->inuse.last = elem; ++ if (!ecp->tx.ecpdu_received) /* Transmit buffer free */ ++ ecp22_tx_run_sm(ecp); ++} ++ ++/* ++ * Copy the payload data. ++ */ ++static struct packed_tlv *copy_ptlv(struct packed_tlv *from) ++{ ++ struct packed_tlv *ptlv = create_ptlv(); ++ ++ if (!ptlv) ++ return NULL; ++ ptlv->size = from->size; ++ ptlv->tlv = calloc(ptlv->size, sizeof(unsigned char)); ++ if (!ptlv->tlv) { ++ free_pkd_tlv(ptlv); ++ return NULL; ++ } ++ memcpy(ptlv->tlv, from->tlv, from->size); ++ return ptlv; ++} ++ ++/* ++ * Create a node for the ecp payload data. Get it from the free list if not ++ * empty. Otherwise allocate from heap. ++ */ ++static struct ecp22_payload_node *ecp22_getnode(struct ecp22_freelist *list) ++{ ++ struct ecp22_payload_node *elem = LIST_FIRST(&list->head); ++ ++ if (!elem) ++ elem = calloc(1, sizeof *elem); ++ else { ++ LIST_REMOVE(elem, node); ++ --list->freecnt; ++ } ++ return elem; ++} ++ ++/* ++ * Receive upper layer protocol data unit for transmit. ++ * Returns error if the request could not be queued for transmision. ++ */ ++static int ecp22_req2send(char *ifname, unsigned short subtype, ++ unsigned const char *mac, struct packed_tlv *du) ++{ ++ struct ecp22_user_data *eud; ++ struct ecp22 *ecp; ++ struct ecp22_payload_node *payda; ++ struct packed_tlv *ptlv = copy_ptlv(du); ++ int rc = 0; ++ ++ LLDPAD_DBG("%s:%s subtype:%d\n", __func__, ifname, subtype); ++ ++ eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); ++ ecp = find_ecpdata(ifname, eud); ++ if (!ecp) { ++ rc = -ENODEV; ++ goto out; ++ } ++ if (!ptlv) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ if (ptlv->size >= ECP22_MAXPAYLOAD_LEN) { ++ rc = -E2BIG; ++ goto out; ++ } ++ payda = ecp22_getnode(&ecp->isfree); ++ if (!payda) { ++ free_pkd_tlv(ptlv); ++ rc = -ENOMEM; ++ goto out; ++ } ++ payda->ptlv = ptlv; ++ payda->subtype = subtype; ++ memcpy(payda->mac, mac, sizeof payda->mac); ++ ecp22_add_payload(ecp, payda); ++out: ++ LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); ++ return rc; ++} ++ ++/* ++ * Payload data from VDP module. ++ * Returns true when data update succeeded. ++ */ ++static int data_from_vdp(char *ifname, struct ecp22_to_ulp *ptr) ++{ ++ struct packed_tlv d; ++ ++ d.size = ptr->len; ++ d.tlv = ptr->data; ++ return ecp22_req2send(ifname, ECP22_VDP, nearest_customer_bridge, &d); ++} ++ ++/* ++ * Handle notifications from other modules. Check if sender-id and data type ++ * indicator match. Return false when data could not be delivered. ++ */ ++static int ecp22_notify(int sender_id, char *ifname, void *data) ++{ ++ struct qbg22_imm *qbg = (struct qbg22_imm *)data; ++ ++ LLDPAD_DBG("%s:%s sender-id:%#x data_type:%d\n", __func__, ifname, ++ sender_id, qbg->data_type); ++ if (sender_id == LLDP_MOD_EVB22 && qbg->data_type == EVB22_TO_ECP22) ++ return ecp22_data_from_evb(ifname, &qbg->u.a); ++ if (sender_id == LLDP_MOD_VDP22 && qbg->data_type == VDP22_TO_ECP22) ++ return data_from_vdp(ifname, &qbg->u.c); ++ return 0; ++} ++ ++static const struct lldp_mod_ops ecp22_ops = { ++ .lldp_mod_register = ecp22_register, ++ .lldp_mod_unregister = ecp22_unregister, ++ .lldp_mod_notify = ecp22_notify ++}; ++ ++/* ++ * ecp22_register - register ecp module to lldpad ++ * ++ * returns lldp_module struct on success, NULL on error ++ * ++ * allocates a module structure with ecp module information and returns it ++ * to lldpad. ++ */ ++struct lldp_module *ecp22_register(void) ++{ ++ struct lldp_module *mod; ++ struct ecp22_user_data *eud; ++ ++ mod = calloc(1, sizeof *mod); ++ if (!mod) { ++ LLDPAD_ERR("%s:can not allocate ecp module data\n", __func__); ++ return NULL; ++ } ++ eud = calloc(1, sizeof(struct ecp22_user_data)); ++ if (!eud) { ++ free(mod); ++ LLDPAD_ERR("%s:can not allocate ecp user data\n", __func__); ++ return NULL; ++ } ++ LIST_INIT(&eud->head); ++ mod->id = LLDP_MOD_ECP22; ++ mod->ops = &ecp22_ops; ++ mod->data = eud; ++ LLDPAD_DBG("%s: done\n", __func__); ++ return mod; ++} ++ ++/* ++ * ecp22_free_data - frees up ecp data chain ++ */ ++static void ecp22_free_data(struct ecp22_user_data *ud) ++{ ++ struct ecp22 *ecp; ++ ++ if (ud) { ++ while (!LIST_EMPTY(&ud->head)) { ++ ecp = LIST_FIRST(&ud->head); ++ ecp22_remove(ecp); ++ } ++ } ++} ++ ++/* ++ * ecp22_unregister - unregister ecp module from lldpad ++ * ++ * no return value ++ * ++ * frees ecp module structure and user data. ++ */ ++void ecp22_unregister(struct lldp_module *mod) ++{ ++ if (mod->data) { ++ ecp22_free_data((struct ecp22_user_data *)mod->data); ++ free(mod->data); ++ } ++ free(mod); ++ LLDPAD_DBG("%s: done\n", __func__); ++} +diff --git a/qbg/lldp_ecp22.c b/qbg/lldp_ecp22.c +deleted file mode 100644 +index 3341cc6..0000000 +--- a/qbg/lldp_ecp22.c ++++ /dev/null +@@ -1,1060 +0,0 @@ +-/****************************************************************************** +- +- Implementation of ECP according to 802.1Qbg +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Jens Osterkamp +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-#include +-#include +-#include +-#include +- +-#include "eloop.h" +-#include "lldp_ecp22.h" +-#include "messages.h" +-#include "lldp_qbg_utils.h" +-#include "lldp/l2_packet.h" +-#include "lldp_tlv.h" +- +-#define ECP22_MAX_RETRIES_DEFAULT (3) /* Default # of max retries */ +-#define ECP22_ACK_TIMER_STOPPED (-1) +-/* +- * Defaults to 2ms wait time for acknowledgement packet reception. +- */ +-#define ECP22_ACK_TIMER_DEFAULT (8) +- +-static void ecp22_tx_run_sm(struct ecp22 *); +- +-static const char *const ecp22_rx_states[] = { /* Receive states verbatim */ +- "ECP22_RX_BEGIN", +- "ECP22_RX_WAIT", +- "ECP22_RX_WAIT2", +- "ECP22_RX_FIRST", +- "ECP22_RX_REC_ECPDU", +- "ECP22_RX_NEW_ECPDU", +- "ECP22_RX_SEND_ACK" +-}; +- +-static const char *const ecp22_tx_states[] = { /* Transmit states verbatim */ +- "ECP22_TX_BEGIN", +- "ECP22_TX_INIT", +- "ECP22_TX_TXMIT_ECPDU", +- "ECP22_TX_WAIT_FORREQ", +- "ECP22_TX_WAIT_ONDATA", +- "ECP22_TX_ERROR" +-}; +- +-/* +- * Increment sequence number. Do not return zero as sequence number. +- */ +-static unsigned short inc_seqno(unsigned short x) +-{ +- ++x; +- if (!x) /* Wrapped */ +- ++x; +- return x; +-} +- +-/* +- * Find the ecp data associated with an interface. +- * Return pointer or NULL if not found. +- */ +-static struct ecp22 *find_ecpdata(char *ifname, struct ecp22_user_data *eud) +-{ +- struct ecp22 *ecp = 0; +- +- if (eud) { +- LIST_FOREACH(ecp, &eud->head, node) +- if (!strncmp(ifname, ecp->ifname, IFNAMSIZ)) +- break; +- } +- return ecp; +-} +- +-/* +- * ecp22_txframe - transmit ecp frame +- * @ecp: pointer to currently used ecp data structure +- * +- * returns the number of characters sent on success, -1 on failure +- * +- * sends out the frame stored in the frame structure using l2_packet_send. +- */ +-static int ecp22_txframe(struct ecp22 *ecp, char *txt, unsigned char *dst, +- unsigned char *ack, size_t len) +-{ +- hexdump_frame(ecp->ifname, txt, ack, len); +- return l2_packet_send(ecp->l2, dst, htons(ETH_P_ECP22), ack, len); +-} +- +-/* +- * Append some data at the end of the transmit data buffer. Make sure the +- * End TLV always fits into the buffer. +- */ +-static unsigned char end_tlv[2] = { 0x0, 0x0 }; /* END TLV */ +- +-static void ecp22_append(u8 *buffer, u32 *pos, void *data, u32 len) +-{ +- if (*pos + len > ETH_FRAME_LEN - sizeof end_tlv) +- return; +- memcpy(buffer + *pos, data, len); +- *pos += len; +-} +- +-/* +- * Return a payload node to the freelist. +- */ +-void ecp22_putnode(struct ecp22_freelist *list, struct ecp22_payload_node *elm) +-{ +- elm->ptlv = free_pkd_tlv(elm->ptlv); +- if (list->freecnt > ecp22_maxpayload) +- free(elm); +- else { +- ++list->freecnt; +- LIST_INSERT_HEAD(&list->head, elm, node); +- } +-} +- +-/* +- * ecp22_build_ecpdu - create an ecp protocol data unit +- * @ecp: pointer to currently used ecp data structure +- * +- * returns true on success, false on failure +- * +- * creates the frame header with the ports mac address, the ecp header with REQ +- * plus a packed TLVs created taken from the send queue. +- */ +-static bool ecp22_build_ecpdu(struct ecp22 *ecp) +-{ +- struct l2_ethhdr eth; +- struct ecp22_hdr ecph; +- u32 fb_offset = 0; +- struct packed_tlv *ptlv; +- struct ecp22_payload_node *p = LIST_FIRST(&ecp->inuse.head); +- +- if (!p) +- return false; +- ecp->tx.ecpdu_received = true; /* Txmit buffer in use */ +- memcpy(eth.h_dest, p->mac, ETH_ALEN); +- l2_packet_get_own_src_addr(ecp->l2, eth.h_source); +- eth.h_proto = htons(ETH_P_ECP22); +- memset(ecp->tx.frame, 0, sizeof ecp->tx.frame); +- ecp22_append(ecp->tx.frame, &fb_offset, (void *)ð, sizeof eth); +- +- ecp22_hdr_set_version(&ecph, 1); +- ecp22_hdr_set_op(&ecph, ECP22_REQUEST); +- ecp22_hdr_set_subtype(&ecph, ECP22_VDP); +- ecph.ver_op_sub = htons(ecph.ver_op_sub); +- ecph.seqno = htons(ecp->tx.seqno); +- ecp22_append(ecp->tx.frame, &fb_offset, (void *)&ecph, sizeof ecph); +- +- ptlv = p->ptlv; +- ecp22_append(ecp->tx.frame, &fb_offset, ptlv->tlv, ptlv->size); +- ecp22_append(ecp->tx.frame, &fb_offset, end_tlv, sizeof end_tlv); +- ecp->tx.frame_len = MAX(fb_offset, (unsigned)ETH_ZLEN); +- LIST_REMOVE(p, node); +- ecp22_putnode(&ecp->isfree, p); +- LLDPAD_DBG("%s:%s seqno %#hx frame_len %#hx\n", __func__, +- ecp->ifname, ecp->tx.seqno, ecp->tx.frame_len); +- return true; +-} +- +-/* +- * Execute transmit state transmitECPDU. +- */ +-static void ecp22_es_waitforreq(struct ecp22 *ecp) +-{ +- ecp->tx.retries = 0; +- ecp->tx.ack_received = false; +- ecp->tx.ecpdu_received = false; +- ecp->tx.seqno = inc_seqno(ecp->tx.seqno); +- LLDPAD_DBG("%s:%s seqno %#hx\n", __func__, ecp->ifname, ecp->tx.seqno); +-} +- +-/* +- * Execute transmit state countErrors. +- */ +-static void ecp22_es_counterror(struct ecp22 *ecp) +-{ +- ++ecp->tx.errors; +- LLDPAD_DBG("%s:%s errors %lu\n", __func__, ecp->ifname, +- ecp->tx.errors); +-} +- +-/* +- * Execute transmit state initTransmit. +- */ +-static void ecp22_es_inittransmit(struct ecp22 *ecp) +-{ +- ecp->tx.errors = 0; +- ecp->tx.seqno = 0; +-} +- +-/* +- * Return RTE value in milliseconds. +- */ +-static int rtevalue(unsigned char rte) +-{ +- return (1 << rte) * 10; +-} +- +-/* +- * ecp22_ack_timeout_handler - handles the ack timer expiry +- * @eloop_data: data structure of event loop +- * @user_ctx: user context, vdp_data here +- * +- * no return value +- * +- * called when the ECP timer has expired. Calls the ECP station state machine. +- */ +-static void ecp22_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) +-{ +- struct ecp22 *ecp = (struct ecp22 *)user_ctx; +- +- LLDPAD_DBG("%s:%s retries:%d\n", __func__, +- ecp->ifname, ecp->tx.retries); +- ecp22_tx_run_sm(ecp); +-} +- +-/* +- * ecp22_tx_start_acktimer - starts the ECP ack timer +- * @ecp: pointer to currently used ecp data structure +- * +- * returns 0 on success, -1 on error +- * +- * starts the ack timer when a frame has been sent out. +- */ +-static void ecp22_tx_start_acktimer(struct ecp22 *ecp) +-{ +- unsigned long ack_sec = rtevalue(ecp->max_rte) / 1000000; +- unsigned long ack_usec = rtevalue(ecp->max_rte) % 1000000; +- +- LLDPAD_DBG("%s:%s [%ld.%06ld]\n", __func__, ecp->ifname, ack_sec, +- ack_usec); +- eloop_register_timeout(ack_sec, ack_usec, ecp22_ack_timeout_handler, +- 0, (void *)ecp); +-} +- +-/* +- * ecp22_tx_change_state - changes the ecp tx sm state +- * @ecp: pointer to currently used ecp data structure +- * @newstate: new state for the sm +- * +- * no return value +- * +- * checks state transistion for consistency and finally changes the state of +- * the profile. +- */ +-static void ecp22_tx_change_state(struct ecp22 *ecp, unsigned char newstate) +-{ +- switch (newstate) { +- case ECP22_TX_BEGIN: +- break; +- case ECP22_TX_INIT: +- assert(ecp->tx.state == ECP22_TX_BEGIN); +- break; +- case ECP22_TX_WAIT_FORREQ: +- assert(ecp->tx.state == ECP22_TX_INIT || +- ecp->tx.state == ECP22_TX_ERROR || +- ecp->tx.state == ECP22_TX_TXMIT_ECPDU); +- break; +- case ECP22_TX_WAIT_ONDATA: +- assert(ecp->tx.state == ECP22_TX_WAIT_FORREQ); +- break; +- case ECP22_TX_TXMIT_ECPDU: +- assert(ecp->tx.state == ECP22_TX_WAIT_ONDATA); +- break; +- case ECP22_TX_ERROR: +- assert(ecp->tx.state == ECP22_TX_TXMIT_ECPDU); +- break; +- default: +- LLDPAD_ERR("%s: ECP TX state machine invalid state %d\n", +- ecp->ifname, newstate); +- } +- LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, +- ecp->ifname, ecp22_tx_states[ecp->tx.state], +- ecp22_tx_states[newstate]); +- ecp->tx.state = newstate; +-} +- +-/* +- * Send the payload data. +- */ +-static int ecp22_es_txmit(struct ecp22 *ecp) +-{ +- int rc = 0; +- +- ++ecp->tx.retries; +- ecp22_txframe(ecp, "ecp-out", ecp->tx.frame, ecp->tx.frame, +- ecp->tx.frame_len); +- ecp22_tx_start_acktimer(ecp); +- return rc; +-} +- +-/* +- * ecp22_set_tx_state - sets the ecp tx state machine state +- * @ecp: pointer to currently used ecp data structure +- * +- * returns true or false +- * +- * switches the state machine to the next state depending on the input +- * variables. returns true or false depending on wether the state machine +- * can be run again with the new state or can stop at the current state. +- */ +-static bool ecp22_set_tx_state(struct ecp22 *ecp) +-{ +- struct port *port = port_find_by_name(ecp->ifname); +- +- if (!port) { +- LLDPAD_ERR("%s:%s port not found\n", __func__, ecp->ifname); +- return 0; +- } +- if ((port->portEnabled == false) && (port->prevPortEnabled == true)) { +- LLDPAD_ERR("%s:%s port was disabled\n", __func__, ecp->ifname); +- ecp22_tx_change_state(ecp, ECP22_TX_BEGIN); +- } +- port->prevPortEnabled = port->portEnabled; +- +- switch (ecp->tx.state) { +- case ECP22_TX_BEGIN: +- ecp22_tx_change_state(ecp, ECP22_TX_INIT); +- return true; +- case ECP22_TX_INIT: +- ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); +- return true; +- case ECP22_TX_WAIT_FORREQ: +- ecp22_tx_change_state(ecp, ECP22_TX_WAIT_ONDATA); +- return true; +- case ECP22_TX_WAIT_ONDATA: +- if (LIST_FIRST(&ecp->inuse.head)) { /* Data to send */ +- ecp22_build_ecpdu(ecp); +- ecp22_tx_change_state(ecp, ECP22_TX_TXMIT_ECPDU); +- return true; +- } +- return false; +- case ECP22_TX_TXMIT_ECPDU: +- if (ecp->tx.ack_received) { +- ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); +- return true; +- } +- if (ecp->tx.retries > ecp->max_retries) { +- ecp22_tx_change_state(ecp, ECP22_TX_ERROR); +- return true; +- } +- return false; +- case ECP22_TX_ERROR: +- ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); +- return true; +- default: +- LLDPAD_ERR("%s: ECP TX state machine in invalid state %d\n", +- ecp->ifname, ecp->tx.state); +- return false; +- } +-} +- +-/* +- * ecp22_tx_run_sm - state machine for ecp transmit +- * @ecp: pointer to currently used ecp data structure +- * +- * no return value +- */ +-static void ecp22_tx_run_sm(struct ecp22 *ecp) +-{ +- ecp22_set_tx_state(ecp); +- do { +- LLDPAD_DBG("%s:%s state %s\n", __func__, +- ecp->ifname, ecp22_tx_states[ecp->tx.state]); +- +- switch (ecp->tx.state) { +- case ECP22_TX_BEGIN: +- break; +- case ECP22_TX_INIT: +- ecp22_es_inittransmit(ecp); +- break; +- case ECP22_TX_WAIT_FORREQ: +- ecp22_es_waitforreq(ecp); +- break; +- case ECP22_TX_WAIT_ONDATA: +- break; +- case ECP22_TX_TXMIT_ECPDU: +- ecp22_es_txmit(ecp); +- break; +- case ECP22_TX_ERROR: +- ecp22_es_counterror(ecp); +- break; +- } +- } while (ecp22_set_tx_state(ecp) == true); +-} +- +-/* +- * ecp22_rx_change_state - changes the ecp rx sm state +- * @ecp: pointer to currently used ecp data structure +- * @newstate: new state for the sm +- * +- * no return value +- * +- * checks state transistion for consistency and finally changes the state of +- * the ecp receive buffer. +- */ +-static void ecp22_rx_change_state(struct ecp22 *ecp, u8 newstate) +-{ +- switch (newstate) { +- case ECP22_RX_BEGIN: +- break; +- case ECP22_RX_WAIT: +- assert(ecp->rx.state == ECP22_RX_BEGIN); +- break; +- case ECP22_RX_FIRST: +- assert(ecp->rx.state == ECP22_RX_WAIT); +- break; +- case ECP22_RX_REC_ECPDU: +- assert((ecp->rx.state == ECP22_RX_FIRST) || +- (ecp->rx.state == ECP22_RX_WAIT2)); +- break; +- case ECP22_RX_NEW_ECPDU: +- assert(ecp->rx.state == ECP22_RX_REC_ECPDU); +- break; +- case ECP22_RX_SEND_ACK: +- assert((ecp->rx.state == ECP22_RX_REC_ECPDU) || +- (ecp->rx.state == ECP22_RX_NEW_ECPDU)); +- break; +- case ECP22_RX_WAIT2: +- assert(ecp->rx.state == ECP22_RX_SEND_ACK); +- break; +- default: +- LLDPAD_ERR("%s:%s LLDP RX state machine invalid state %d\n", +- __func__, ecp->ifname, newstate); +- } +- LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, +- ecp->ifname, ecp22_rx_states[ecp->rx.state], +- ecp22_rx_states[newstate]); +- ecp->rx.state = newstate; +-} +- +-/* +- * Execute action in state sendack. Construct and send an acknowledgement +- * for the received ECP packet. +- */ +-static void ecp22_es_send_ack(struct ecp22 *ecp) +-{ +- unsigned char ack_frame[ETH_HLEN + sizeof(struct ecp22_hdr)]; +- struct ethhdr *ethdst = (struct ethhdr *)ack_frame; +- struct ecp22_hdr *ecpdst = (struct ecp22_hdr *)&ack_frame[ETH_HLEN]; +- struct ethhdr *ethsrc = (struct ethhdr *)ecp->rx.frame; +- struct ecp22_hdr *ecpsrc = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; +- struct ecp22_hdr ack; +- +- LLDPAD_DBG("%s:%s state %s seqno %#hx\n", __func__, ecp->ifname, +- ecp22_rx_states[ecp->rx.state], ecp->rx.seqno); +- memcpy(ethdst->h_dest, nearest_customer_bridge, ETH_ALEN); +- l2_packet_get_own_src_addr(ecp->l2, (u8 *)ðdst->h_source); +- ethdst->h_proto = ethsrc->h_proto; +- /* Set ECP header */ +- ack.ver_op_sub = ntohs(ecpsrc->ver_op_sub); +- ecp22_hdr_set_op(&ack, ECP22_ACK); +- ecpdst->ver_op_sub = htons(ack.ver_op_sub); +- ecpdst->seqno = htons(ecp->rx.seqno); +- ecp22_txframe(ecp, "ecp-ack", ethsrc->h_source, ack_frame, +- sizeof ack_frame); +-} +- +- +-/* +- * Notify upper layer protocol function of ECP payload data just received. +- */ +-static void ecp22_to_ulp(unsigned short ulp, struct ecp22 *ecp) +-{ +- size_t offset = ETH_HLEN + sizeof(struct ecp22_hdr); +- struct qbg22_imm to_ulp; +- +- to_ulp.data_type = ECP22_TO_ULP; +- to_ulp.u.c.len = ecp->rx.frame_len - offset; +- to_ulp.u.c.data = &ecp->rx.frame[offset]; +- if (ulp == ECP22_VDP) +- modules_notify(LLDP_MOD_VDP22, LLDP_MOD_ECP22, ecp->ifname, +- &to_ulp); +- else +- LLDPAD_INFO("%s:%s ECP subtype %d not yet implemented\n", +- __func__, ecp->ifname, ulp); +-} +- +-/* +- * Execute action in state newECPDU. +- * Notify upper layer protocol of new data. +- */ +-static void ecp22_es_new_ecpdu(struct ecp22 *ecp) +-{ +- struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; +- struct ecp22_hdr ecphdr; +- unsigned short ulp; +- +- ecphdr.ver_op_sub = ntohs(hdr->ver_op_sub); +- ulp = ecp22_hdr_read_subtype(&ecphdr); +- LLDPAD_DBG("%s:%s state %s notify ULP %d seqno %#hx\n", __func__, +- ecp->ifname, ecp22_rx_states[ecp->rx.state], +- ulp, ecp->rx.seqno); +- ecp->rx.last_seqno = ecp->rx.seqno; +- ecp22_to_ulp(ulp, ecp); +-} +- +-/* +- * Execute action in state receiveECPDU. +- */ +-static void ecp22_es_rec_ecpdu(struct ecp22 *ecp) +-{ +- struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; +- +- ecp->rx.seqno = ntohs(hdr->seqno); +- LLDPAD_DBG("%s:%s state %s seqno %#hx\n", __func__, ecp->ifname, +- ecp22_rx_states[ecp->rx.state], ecp->rx.seqno); +-} +- +-/* +- * Execute action in state receiveFirst. +- */ +-static void ecp22_es_first(struct ecp22 *ecp) +-{ +- struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; +- +- LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, +- ecp22_rx_states[ecp->rx.state]); +- ecp->rx.last_seqno = ntohs(hdr->seqno) - 1; +-} +- +-/* +- * Execute action in state receiveWait. +- */ +-static void ecp22_es_wait(struct ecp22 *ecp) +-{ +- LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, +- ecp22_rx_states[ecp->rx.state]); +- ecp->rx.ecpdu_received = false; +-} +- +-/* +- * ecp22_set_rx_state - sets the ecp receive state machine state +- * @ecp: pointer to currently used ecp data structure +- * +- * returns true or false +- * +- * switches the state machine to the next state depending on the input +- * variables. Returns true or false depending on wether the state machine +- * can be run again with the new state or can stop at the current state. +- */ +-static bool ecp22_set_rx_state(struct ecp22 *ecp) +-{ +- struct port *port = port_find_by_name(ecp->ifname); +- +- if (!port) +- return false; +- +- LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, +- ecp22_rx_states[ecp->rx.state]); +- if (port->portEnabled == false) +- ecp22_rx_change_state(ecp, ECP22_RX_BEGIN); +- switch (ecp->rx.state) { +- case ECP22_RX_BEGIN: +- ecp22_rx_change_state(ecp, ECP22_RX_WAIT); +- return false; +- case ECP22_RX_WAIT: +- if (ecp->rx.ecpdu_received) { +- ecp22_rx_change_state(ecp, ECP22_RX_FIRST); +- return true; +- } +- return false; +- case ECP22_RX_WAIT2: +- if (ecp->rx.ecpdu_received) { +- ecp22_rx_change_state(ecp, ECP22_RX_REC_ECPDU); +- return true; +- } +- return false; +- case ECP22_RX_FIRST: +- ecp22_rx_change_state(ecp, ECP22_RX_REC_ECPDU); +- return true; +- case ECP22_RX_REC_ECPDU: +- if (ecp->rx.seqno == ecp->rx.last_seqno) +- ecp22_rx_change_state(ecp, ECP22_RX_SEND_ACK); +- else +- ecp22_rx_change_state(ecp, ECP22_RX_NEW_ECPDU); +- return true; +- case ECP22_RX_NEW_ECPDU: +- ecp22_rx_change_state(ecp, ECP22_RX_SEND_ACK); +- return true; +- case ECP22_RX_SEND_ACK: +- ecp22_rx_change_state(ecp, ECP22_RX_WAIT2); +- return true; +- default: +- LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", +- __func__, ecp->ifname, ecp->rx.state); +- return false; +- } +-} +- +-/* +- * ecp22_rx_run_sm - state machine for ecp receive protocol +- * @ecp: pointer to currently used ecp data structure +- * +- * no return value +- * +- * runs the state machine for ecp22 receive function. +- */ +-static void ecp22_rx_run_sm(struct ecp22 *ecp) +-{ +- ecp22_set_rx_state(ecp); +- do { +- switch (ecp->rx.state) { +- case ECP22_RX_WAIT: +- case ECP22_RX_WAIT2: +- ecp22_es_wait(ecp); +- break; +- case ECP22_RX_FIRST: +- ecp22_es_first(ecp); +- break; +- case ECP22_RX_REC_ECPDU: +- ecp22_es_rec_ecpdu(ecp); +- break; +- case ECP22_RX_NEW_ECPDU: +- ecp22_es_new_ecpdu(ecp); +- break; +- case ECP22_RX_SEND_ACK: +- ecp22_es_send_ack(ecp); +- break; +- default: +- LLDPAD_DBG("%s:%s ECP RX state machine in invalid " +- "state %d\n", __func__, ecp->ifname, +- ecp->rx.state); +- } +- } while (ecp22_set_rx_state(ecp) == true); +-} +- +-/* +- * Received an aknowledgement frame. +- * Check if we have a transmit pending and the ack'ed packet number matches +- * the send packet. +- */ +-static void ecp22_recack_frame(struct ecp22 *ecp, unsigned short seqno) +-{ +- LLDPAD_DBG("%s:%s txmit:%d seqno %#hx ack-seqno %#hx\n", __func__, +- ecp->ifname, ecp->tx.ecpdu_received, ecp->tx.seqno, seqno); +- if (ecp->tx.ecpdu_received) { +- if (ecp->tx.seqno == seqno) +- ecp->tx.ack_received = true; +- } +-} +- +-/* +- * ecp22_rx_receiveframe - receive am ecp frame +- * @ctx: rx callback context, struct ecp * in this case +- * @ifindex: index of interface +- * @buf: buffer which contains the frame just received +- * @len: size of buffer (frame) +- * +- * no return value +- * +- * creates a local copy of the buffer and checks the header. keeps some +- * statistics about ecp frames. Checks if it is a request or an ack frame and +- * branches to ecp rx or ecp tx state machine. +- */ +-static void ecp22_rx_receiveframe(void *ctx, int ifindex, const u8 *buf, +- size_t len) +-{ +- struct ecp22 *ecp = (struct ecp22 *)ctx; +- struct port *port; +- struct ecp22_hdr *ecp_hdr, ecphdr; +- +- LLDPAD_DBG("%s:%s ifindex:%d len:%zd state:%s ecpdu_received:%d\n", +- __func__, ecp->ifname, ifindex, len, +- ecp22_rx_states[ecp->rx.state], ecp->rx.ecpdu_received); +- hexdump_frame(ecp->ifname, "frame-in", buf, len); +- port = port_find_by_name(ecp->ifname); +- if (!port || ecp->rx.ecpdu_received) +- /* Port not found or buffer not free */ +- return; +- +- memcpy(ecp->rx.frame, buf, len); +- ecp->rx.frame_len = len; +- ecp->stats.statsFramesInTotal++; +- +- ecp_hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; +- ecphdr.ver_op_sub = ntohs(ecp_hdr->ver_op_sub); +- +- /* Check for correct subtype and version number */ +- if (ecp22_hdr_read_version(&ecphdr) != 1) { +- LLDPAD_ERR("%s:%s ERROR unknown version %#02hx seqno %#hx\n", +- __func__, ecp->ifname, ecphdr.ver_op_sub, +- ntohs(ecp_hdr->seqno)); +- return; +- } +- switch (ecp22_hdr_read_subtype(&ecphdr)) { +- default: +- LLDPAD_ERR("%s:%s ERROR unknown subtype %#02hx seqno %#hx\n", +- __func__, ecp->ifname, ecphdr.ver_op_sub, +- ntohs(ecp_hdr->seqno)); +- return; +- case ECP22_PECSP: +- case ECP22_VDP: +- /* Subtype ok, fall through intended */ +- break; +- } +- +- switch (ecp22_hdr_read_op(&ecphdr)) { +- case ECP22_REQUEST: +- LLDPAD_DBG("%s:%s received REQ frame seqno %#hx\n", __func__, +- ecp->ifname, ntohs(ecp_hdr->seqno)); +- ecp->rx.ecpdu_received = true; +- ecp22_rx_run_sm(ecp); +- break; +- case ECP22_ACK: +- LLDPAD_DBG("%s:%s received ACK frame seqno %#hx\n", __func__, +- ecp->ifname, ntohs(ecp_hdr->seqno)); +- ecp22_recack_frame(ecp, ntohs(ecp_hdr->seqno)); +- break; +- default: +- LLDPAD_ERR("%s:%s ERROR unknown mode %#02hx seqno %#hx\n", +- __func__, ecp->ifname, ecphdr.ver_op_sub, +- ntohs(ecp_hdr->seqno)); +- } +-} +- +-/* +- * ecp22_create - create data structure and initialize ecp protocol +- * @ifname: interface for which the ecp protocol is initialized +- * +- * returns NULL on error and an pointer to the ecp22 structure on success. +- * +- * finds the port to the interface name, sets up the receive handle for +- * incoming ecp frames and initializes the ecp rx and tx state machines. +- * To be called when a successful exchange of EVB TLVs has been +- * made and ECP protocols are supported by both sides. +- */ +-static struct ecp22 *ecp22_create(char *ifname, struct ecp22_user_data *eud) +-{ +- struct ecp22 *ecp; +- +- ecp = calloc(1, sizeof *ecp); +- if (!ecp) { +- LLDPAD_ERR("%s:%s unable to allocate ecp protocol\n", __func__, +- ifname); +- return NULL; +- } +- strncpy(ecp->ifname, ifname, sizeof ecp->ifname); +- ecp->l2 = l2_packet_init(ecp->ifname, 0, ETH_P_ECP22, +- ecp22_rx_receiveframe, ecp, 1); +- +- if (!ecp->l2) { +- LLDPAD_ERR("%s:%s error open layer 2 ETH_P_ECP\n", __func__, +- ifname); +- free(ecp); +- return NULL; +- } +- LIST_INSERT_HEAD(&eud->head, ecp, node); +- LLDPAD_DBG("%s:%s create ecp data\n", __func__, ifname); +- return ecp; +-} +- +-/* +- * ecp22_start - build up ecp structures for an interface +- * @ifname: name of the interface +- */ +-void ecp22_start(char *ifname) +-{ +- struct ecp22_user_data *eud; +- struct ecp22 *ecp; +- +- LLDPAD_DBG("%s:%s start ecp\n", __func__, ifname); +- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); +- if (!eud) { +- LLDPAD_DBG("%s:%s no ECP module\n", __func__, ifname); +- return; +- } +- ecp = find_ecpdata(ifname, eud); +- if (!ecp) +- ecp = ecp22_create(ifname, eud); +- ecp->max_retries = ECP22_MAX_RETRIES_DEFAULT; +- ecp->max_rte = ECP22_ACK_TIMER_DEFAULT; +- LIST_INIT(&ecp->inuse.head); +- ecp->inuse.last = 0; +- LIST_INIT(&ecp->isfree.head); +- ecp->isfree.freecnt = 0; +- ecp->rx.state = ECP22_RX_BEGIN; +- ecp22_rx_run_sm(ecp); +- ecp->tx.state = ECP22_TX_BEGIN; +- ecp22_tx_run_sm(ecp); +-} +- +-/* +- * Remove the ecp_payload nodes +- */ +-static void ecp22_removelist(ecp22_list *ptr) +-{ +- struct ecp22_payload_node *np; +- +- while ((np = LIST_FIRST(ptr))) { +- LIST_REMOVE(np, node); +- np->ptlv = free_pkd_tlv(np->ptlv); +- free(np); +- } +-} +- +-static void ecp22_remove(struct ecp22 *ecp) +-{ +- LLDPAD_DBG("%s:%s remove ecp\n", __func__, ecp->ifname); +- ecp22_removelist(&ecp->inuse.head); +- ecp->inuse.last = 0; +- ecp22_removelist(&ecp->isfree.head); +- ecp->isfree.freecnt = 0; +- LIST_REMOVE(ecp, node); +- free(ecp); +-} +- +-/* +- * ecp22_stop - tear down ecp structures for a interface +- * @ifname: name of the interface +- * +- * no return value +- * +- */ +-void ecp22_stop(char *ifname) +-{ +- struct ecp22_user_data *eud; +- struct ecp22 *ecp; +- +- LLDPAD_DBG("%s:%s stop ecp\n", __func__, ifname); +- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); +- ecp = find_ecpdata(ifname, eud); +- if (ecp) +- ecp22_remove(ecp); +-} +- +-/* +- * Update data exchanged via EVB protocol. +- * Returns true when data update succeeded. +- */ +-static int data_from_evb(char *ifname, struct evb22_to_ecp22 *ptr) +-{ +- struct ecp22_user_data *eud; +- struct ecp22 *ecp; +- +- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); +- ecp = find_ecpdata(ifname, eud); +- if (ecp) { +- ecp->max_rte = ptr->max_rte; +- ecp->max_retries = ptr->max_retry; +- return 0; +- } +- return -ENOENT; +-} +- +-/* +- * Add ecp payload data at the end of the queue. +- */ +-static void ecp22_add_payload(struct ecp22 *ecp, +- struct ecp22_payload_node *elem) +-{ +- if (LIST_EMPTY(&ecp->inuse.head)) +- LIST_INSERT_HEAD(&ecp->inuse.head, elem, node); +- else +- LIST_INSERT_AFTER(ecp->inuse.last, elem, node); +- ecp->inuse.last = elem; +- if (!ecp->tx.ecpdu_received) /* Transmit buffer free */ +- ecp22_tx_run_sm(ecp); +-} +- +-/* +- * Copy the payload data. +- */ +-static struct packed_tlv *copy_ptlv(struct packed_tlv *from) +-{ +- struct packed_tlv *ptlv = create_ptlv(); +- +- if (!ptlv) +- return NULL; +- ptlv->size = from->size; +- ptlv->tlv = calloc(ptlv->size, sizeof(unsigned char)); +- if (!ptlv->tlv) { +- free_pkd_tlv(ptlv); +- return NULL; +- } +- memcpy(ptlv->tlv, from->tlv, from->size); +- return ptlv; +-} +- +-/* +- * Create a node for the ecp payload data. Get it from the free list if not +- * empty. Otherwise allocate from heap. +- */ +-static struct ecp22_payload_node *ecp22_getnode(struct ecp22_freelist *list) +-{ +- struct ecp22_payload_node *elem = LIST_FIRST(&list->head); +- +- if (!elem) +- elem = calloc(1, sizeof *elem); +- else { +- LIST_REMOVE(elem, node); +- --list->freecnt; +- } +- return elem; +-} +- +-/* +- * Receive upper layer protocol data unit for transmit. +- * Returns error if the request could not be queued for transmision. +- */ +-static int ecp22_req2send(char *ifname, unsigned short subtype, +- unsigned const char *mac, struct packed_tlv *du) +-{ +- struct ecp22_user_data *eud; +- struct ecp22 *ecp; +- struct ecp22_payload_node *payda; +- struct packed_tlv *ptlv = copy_ptlv(du); +- int rc = 0; +- +- LLDPAD_DBG("%s:%s subtype:%d\n", __func__, ifname, subtype); +- +- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); +- ecp = find_ecpdata(ifname, eud); +- if (!ecp) { +- rc = -ENODEV; +- goto out; +- } +- if (!ptlv) { +- rc = -ENOMEM; +- goto out; +- } +- if (ptlv->size >= ECP22_MAXPAYLOAD_LEN) { +- rc = -E2BIG; +- goto out; +- } +- payda = ecp22_getnode(&ecp->isfree); +- if (!payda) { +- free_pkd_tlv(ptlv); +- rc = -ENOMEM; +- goto out; +- } +- payda->ptlv = ptlv; +- payda->subtype = subtype; +- memcpy(payda->mac, mac, sizeof payda->mac); +- ecp22_add_payload(ecp, payda); +-out: +- LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); +- return rc; +-} +- +-/* +- * Payload data from VDP module. +- * Returns true when data update succeeded. +- */ +-static int data_from_vdp(char *ifname, struct ecp22_to_ulp *ptr) +-{ +- struct packed_tlv d; +- +- d.size = ptr->len; +- d.tlv = ptr->data; +- return ecp22_req2send(ifname, ECP22_VDP, nearest_customer_bridge, &d); +-} +- +-/* +- * Handle notifications from other modules. Check if sender-id and data type +- * indicator match. Return false when data could not be delivered. +- */ +-static int ecp22_notify(int sender_id, char *ifname, void *data) +-{ +- struct qbg22_imm *qbg = (struct qbg22_imm *)data; +- +- LLDPAD_DBG("%s:%s sender-id:%#x data_type:%d\n", __func__, ifname, +- sender_id, qbg->data_type); +- if (sender_id == LLDP_MOD_EVB22 && qbg->data_type == EVB22_TO_ECP22) +- return data_from_evb(ifname, &qbg->u.a); +- if (sender_id == LLDP_MOD_VDP22 && qbg->data_type == VDP22_TO_ECP22) +- return data_from_vdp(ifname, &qbg->u.c); +- return 0; +-} +- +-static const struct lldp_mod_ops ecp22_ops = { +- .lldp_mod_register = ecp22_register, +- .lldp_mod_unregister = ecp22_unregister, +- .lldp_mod_notify = ecp22_notify +-}; +- +-/* +- * ecp22_register - register ecp module to lldpad +- * +- * returns lldp_module struct on success, NULL on error +- * +- * allocates a module structure with ecp module information and returns it +- * to lldpad. +- */ +-struct lldp_module *ecp22_register(void) +-{ +- struct lldp_module *mod; +- struct ecp22_user_data *eud; +- +- mod = calloc(1, sizeof *mod); +- if (!mod) { +- LLDPAD_ERR("%s:can not allocate ecp module data\n", __func__); +- return NULL; +- } +- eud = calloc(1, sizeof(struct ecp22_user_data)); +- if (!eud) { +- free(mod); +- LLDPAD_ERR("%s:can not allocate ecp user data\n", __func__); +- return NULL; +- } +- LIST_INIT(&eud->head); +- mod->id = LLDP_MOD_ECP22; +- mod->ops = &ecp22_ops; +- mod->data = eud; +- LLDPAD_DBG("%s: done\n", __func__); +- return mod; +-} +- +-/* +- * ecp22_free_data - frees up ecp data chain +- */ +-static void ecp22_free_data(struct ecp22_user_data *ud) +-{ +- struct ecp22 *ecp; +- +- if (ud) { +- while (!LIST_EMPTY(&ud->head)) { +- ecp = LIST_FIRST(&ud->head); +- ecp22_remove(ecp); +- } +- } +-} +- +-/* +- * ecp22_unregister - unregister ecp module from lldpad +- * +- * no return value +- * +- * frees ecp module structure and user data. +- */ +-void ecp22_unregister(struct lldp_module *mod) +-{ +- if (mod->data) { +- ecp22_free_data((struct ecp22_user_data *)mod->data); +- free(mod->data); +- } +- free(mod); +- LLDPAD_DBG("%s: done\n", __func__); +-} +diff --git a/qbg/lldp_evb22.c b/qbg/lldp_evb22.c +deleted file mode 100644 +index f9eeace..0000000 +--- a/qbg/lldp_evb22.c ++++ /dev/null +@@ -1,556 +0,0 @@ +-/****************************************************************************** +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2012 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-#define _GNU_SOURCE +-#include +-#include +- +-#include "lldp.h" +-#include "lldp_tlv.h" +-#include "lldp_evb22.h" +-#include "lldp_ecp22.h" +-#include "lldp_vdp22.h" +-#include "lldp_qbg_utils.h" +-#include "lldp_evb_cmds.h" +-#include "messages.h" +-#include "config.h" +- +-extern struct lldp_head lldp_head; +- +-struct evb22_data *evb22_data(char *ifname, enum agent_type type) +-{ +- struct evb22_user_data *ud; +- struct evb22_data *ed = NULL; +- +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_EVB22); +- if (ud) { +- LIST_FOREACH(ed, &ud->head, entry) { +- if (!strncmp(ifname, ed->ifname, IFNAMSIZ) && +- (type == ed->agenttype)) +- break; +- } +- } +- return ed; +-} +- +-static void evb22_format_tlv(char *buf, size_t len, struct evb22_tlv *tlv) +-{ +- int comma = 0; +- char bridge_txt[32], station_txt[32]; +- +- memset(bridge_txt, 0, sizeof bridge_txt); +- if (evb_ex_bgid(tlv->bridge_s)) { +- strcat(bridge_txt, "bgid"); +- comma = 1; +- } +- if (evb_ex_rrcap(tlv->bridge_s)) { +- if (comma) +- strcat(bridge_txt, ","); +- strcat(bridge_txt, "rrcap"); +- comma = 1; +- } +- if (evb_ex_rrctr(tlv->bridge_s)) { +- if (comma) +- strcat(bridge_txt, ","); +- strcat(bridge_txt, "rrctr"); +- } +- +- comma = 0; +- memset(station_txt, 0, sizeof station_txt); +- if (evb_ex_sgid(tlv->station_s)) { +- strcat(station_txt, "sgid"); +- comma = 1; +- } +- if (evb_ex_rrreq(tlv->station_s)) { +- if (comma) +- strcat(station_txt, ","); +- strcat(station_txt, "rrreq"); +- comma = 1; +- } +- if (evb_ex_rrstat(tlv->station_s)) { +- if (comma) +- strcat(station_txt, ","); +- strcat(station_txt, "rrstat"); +- } +- snprintf(buf, len, "bridge:%s(%#02x) station:%s(%#02x) " +- "retries:%d rte:%d mode:%d r/l:%d rwd:%d " +- "r/l:%d rka:%d", bridge_txt, tlv->bridge_s, +- station_txt, tlv->station_s, +- evb_ex_retries(tlv->r_rte), evb_ex_rte(tlv->r_rte), +- evb_ex_evbmode(tlv->evb_mode), evb_ex_rol(tlv->evb_mode), +- evb_ex_rwd(tlv->evb_mode), +- evb_ex_rol(tlv->rl_rka), evb_ex_rka(tlv->rl_rka)); +-} +- +-static void evb22_print_tlvinfo(char *ifname, struct evb22_tlv *tlv) +-{ +- char buf[256]; +- +- evb22_format_tlv(buf, sizeof buf, tlv); +- LLDPAD_DBG("%s evb %s\n", ifname, buf); +-} +- +-static void evb22_dump_tlv(char *ifname, struct unpacked_tlv *tlv) +-{ +- int i, left = 0; +- char buffer[256]; +- +- for (i = 0; i < tlv->length; i++) { +- int c; +- +- c = snprintf(buffer + left, +- sizeof buffer - left, +- "%02x ", tlv->info[i]); +- +- if (c < 0 || (c >= (int)sizeof buffer - left)) +- break; +- else +- left += c; +- } +- +- LLDPAD_DBG("%s:%s type %i length %i info %s\n", +- __func__, ifname, tlv->type, tlv->length, buffer); +-} +- +-static void common_tlv(struct evb22_data *ed) +-{ +- struct evb22_tlv *recv = &ed->last; +- struct evb22_tlv *mine = &ed->policy; +- u8 val; +- +- /* Set retries and rte value */ +- val = evb_ex_retries(recv->r_rte); +- if (evb_ex_retries(mine->r_rte) > val) +- val = evb_ex_retries(mine->r_rte); +- ed->out.r_rte = evb_set_retries(val); +- val = evb_ex_rte(recv->r_rte); +- if (evb_ex_rte(mine->r_rte) > val) +- val = evb_ex_rte(mine->r_rte); +- ed->out.r_rte |= evb_set_rte(val); +- +- /* Set evbmode */ +- ed->out.evb_mode = evb_set_evbmode(evb_ex_evbmode(mine->evb_mode)); +- val = evb_ex_rwd(recv->evb_mode); +- if (evb_ex_rwd(mine->evb_mode) > val) +- val = evb_ex_rwd(mine->evb_mode); +- else +- ed->out.evb_mode |= evb_set_rol(1); +- ed->out.evb_mode |= evb_set_rwd(val); +- +- /* Set rka */ +- ed->out.rl_rka = 0; +- val = evb_ex_rka(recv->rl_rka); +- if (evb_ex_rka(mine->rl_rka) > val) +- val = evb_ex_rka(mine->rl_rka); +- else +- ed->out.rl_rka = evb_set_rol(1); +- ed->out.rl_rka |= evb_set_rka(val); +-} +- +-/* +- * Fill the EVB DU for LLDP transmition. Sender is bridge. +- */ +-static void bridge_tlv(struct evb22_data *ed) +-{ +- struct evb22_tlv *recv = &ed->last; +- struct evb22_tlv *mine = &ed->policy; +- +- /* Copy my last station status */ +- ed->out.station_s = recv->station_s; +- +- /* Set bridge status */ +- ed->out.bridge_s = mine->bridge_s; +- if (evb_ex_rrreq(recv->station_s) && evb_ex_rrcap(mine->bridge_s)) +- ed->out.bridge_s |= evb_set_rrctr(1); +- common_tlv(ed); +-} +- +-/* +- * Fill the EVB DU for LLDP transmition. Sender is station. +- */ +-static void station_tlv(struct evb22_data *ed) +-{ +- struct evb22_tlv *recv = &ed->last; +- struct evb22_tlv *mine = &ed->policy; +- u8 val; +- +- /* Copy my last bridge status */ +- ed->out.bridge_s = recv->bridge_s; +- +- /* +- * Set station status, 2nd byte of OUI is 0x80. If 0x00 +- * nothing received from bridge. +- */ +- if (recv->oui[1] == 0) +- val = EVB_RRSTAT_DONT; +- else if (evb_ex_rrctr(recv->bridge_s)) +- val = EVB_RRSTAT_YES; +- else +- val = EVB_RRSTAT_NO; +- ed->out.station_s = evb_maskoff_rrstat(mine->station_s) +- | evb_set_rrstat(val); +- common_tlv(ed); +-} +- +-/* +- * Checks values received in TLV and takes over some values. +- * Sets the new suggestion in member tie to be send out to switch. +- * +- * Also notify depending modules about the new values. +- */ +-static void evb22_update_tlv(struct evb22_data *ed) +-{ +- struct qbg22_imm qbg; +- +- if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) +- station_tlv(ed); +- else +- bridge_tlv(ed); +- +- qbg.data_type = EVB22_TO_ECP22; +- qbg.u.a.max_rte = evb_ex_rte(ed->out.r_rte); +- qbg.u.a.max_retry = evb_ex_retries(ed->out.r_rte); +- modules_notify(LLDP_MOD_ECP22, LLDP_MOD_EVB22, ed->ifname, &qbg); +- +- qbg.data_type = EVB22_TO_VDP22; +- qbg.u.b.max_rka = evb_ex_rka(ed->out.rl_rka); +- qbg.u.b.max_rwd = evb_ex_rwd(ed->out.evb_mode); +- /* Support group identifiers when advertised by both sides */ +- qbg.u.b.gpid = evb_ex_bgid(ed->out.bridge_s) +- && evb_ex_sgid(ed->out.station_s); +- modules_notify(LLDP_MOD_VDP22, LLDP_MOD_EVB22, ed->ifname, &qbg); +-} +- +-/* +- * Build the packed EVB TLV. +- * Returns a pointer to the packed tlv or 0 on failure. +- */ +-static struct packed_tlv *evb22_build_tlv(struct evb22_data *ed) +-{ +- struct packed_tlv *ptlv = 0; +- u8 infobuf[sizeof(struct evb22_tlv)]; +- struct unpacked_tlv tlv = { +- .type = ORG_SPECIFIC_TLV, +- .length = sizeof(struct evb22_tlv), +- .info = infobuf +- }; +- +- evb22_update_tlv(ed); +- memcpy(tlv.info, &ed->out, tlv.length); +- ptlv = pack_tlv(&tlv); +- if (ptlv) { +- LLDPAD_DBG("%s:%s TLV about to be sent out:\n", __func__, +- ed->ifname); +- evb22_dump_tlv(ed->ifname, &tlv); +- } else +- LLDPAD_DBG("%s:%s failed to pack EVB TLV\n", __func__, +- ed->ifname); +- return ptlv; +-} +- +-/* +- * Function call to build and return module specific packed EVB TLV. +- * Returned packed_tlv is free'ed by caller of this function. +- */ +-static struct packed_tlv *evb22_gettlv(struct port *port, +- struct lldp_agent *agent) +-{ +- struct evb22_data *ed; +- +- if (agent->type != NEAREST_CUSTOMER_BRIDGE) +- return 0; +- ed = evb22_data(port->ifname, agent->type); +- if (!ed) { +- LLDPAD_ERR("%s:%s agent %d failed\n", __func__, port->ifname, +- agent->type); +- return 0; +- } +- return (ed->txmit) ? evb22_build_tlv(ed) : 0; +-} +- +-/* +- * evb_rchange: process received EVB TLV LLDPDU +- * +- * TLV not consumed on error +- */ +-static int evb22_rchange(struct port *port, struct lldp_agent *agent, +- struct unpacked_tlv *tlv) +-{ +- struct evb22_data *ed; +- u8 oui_subtype[OUI_SUB_SIZE] = LLDP_MOD_EVB22_OUI; +- +- if (agent->type != NEAREST_CUSTOMER_BRIDGE) +- return 0; +- ed = evb22_data(port->ifname, agent->type); +- +- if (!ed) +- return SUBTYPE_INVALID; +- +- if (tlv->type == TYPE_127) { +- /* check for length */ +- if (tlv->length < OUI_SUB_SIZE) +- return TLV_ERR; +- +- /* check for oui */ +- if (memcmp(tlv->info, &oui_subtype, OUI_SUB_SIZE)) +- return SUBTYPE_INVALID; +- +- /* disable rx if tx has been disabled by administrator */ +- if (!ed->txmit) { +- LLDPAD_WARN("%s:%s agent %d EVB Config disabled\n", +- __func__, ed->ifname, agent->type); +- return TLV_OK; +- } +- +- LLDPAD_DBG("%s:%s agent %d received tlv:\n", __func__, +- port->ifname, agent->type); +- evb22_dump_tlv(ed->ifname, tlv); +- memcpy(&ed->last, tlv->info, tlv->length); +- evb22_print_tlvinfo(ed->ifname, &ed->last); +- +- evb22_update_tlv(ed); +- somethingChangedLocal(ed->ifname, agent->type); +- +- LLDPAD_DBG("%s:%s agent %d new tlv:\n", __func__, port->ifname, +- agent->type); +- evb22_print_tlvinfo(ed->ifname, &ed->out); +- /* TODO vdp_update(port->ifname, ed->tie.ccap); */ +- } +- return TLV_OK; +-} +- +-/* +- * Stop all modules which depend on EVB capabilities. +- */ +-static void evb22_stop_modules(char *ifname) +-{ +- LLDPAD_DBG("%s:%s STOP\n", __func__, ifname); +- ecp22_stop(ifname); +- vdp22_stop(ifname); +-} +- +-static void evb22_ifdown(char *ifname, struct lldp_agent *agent) +-{ +- struct evb22_data *ed; +- +- if (agent->type != NEAREST_CUSTOMER_BRIDGE) +- return; +- LLDPAD_DBG("%s:%s agent %d called\n", __func__, ifname, agent->type); +- +- ed = evb22_data(ifname, agent->type); +- if (!ed) { +- LLDPAD_DBG("%s:%s agent %d does not exist.\n", __func__, +- ifname, agent->type); +- return; +- } +- if (ed->vdp_start) +- evb22_stop_modules(ifname); +- LIST_REMOVE(ed, entry); +- free(ed); +- LLDPAD_INFO("%s:%s agent %d removed\n", __func__, ifname, agent->type); +-} +- +-/* +- * Fill up evb structure with reasonable info from the configuration file. +- */ +-static void evb22_init_tlv(struct evb22_data *ed, struct lldp_agent *agent) +-{ +- u8 mode; +- +- memset(&ed->last, 0, sizeof ed->last); +- memset(&ed->out, 0, sizeof ed->out); +- memset(&ed->policy, 0, sizeof ed->policy); +- +- ed->txmit = evb22_conf_enabletx(ed->ifname, agent->type); +- if (!ed->txmit) +- LLDPAD_DBG("%s:%s agent %d EVB tx is currently disabled\n", +- __func__, ed->ifname, agent->type); +- +- hton24(ed->policy.oui, LLDP_MOD_EVB22); +- ed->policy.sub = LLDP_MOD_EVB22_SUBTYPE; +- hton24(ed->out.oui, LLDP_MOD_EVB22); +- ed->out.sub = LLDP_MOD_EVB22_SUBTYPE; +- +- mode = evb22_conf_evbmode(ed->ifname, agent->type); +- ed->policy.evb_mode = evb_set_rol(0) +- | evb_set_rwd(evb22_conf_rwd(ed->ifname, agent->type)) +- | evb_set_evbmode(mode); +- if (mode == EVB_STATION) { +- mode = evb22_conf_rrreq(ed->ifname, agent->type); +- ed->policy.station_s = evb_set_rrstat(EVB_RRSTAT_DONT) +- | evb_set_sgid(evb22_conf_gid(ed->ifname, agent->type)) +- | evb_set_rrreq(mode); +- ed->policy.bridge_s = 0; +- } else { +- mode = evb22_conf_rrcap(ed->ifname, agent->type); +- ed->policy.bridge_s = evb_set_rrcap(mode) +- | evb_set_bgid(evb22_conf_gid(ed->ifname, agent->type)); +- ed->policy.station_s = 0; +- } +- ed->policy.r_rte = +- evb_set_retries(evb22_conf_retries(ed->ifname, agent->type)) +- | evb_set_rte(evb22_conf_rte(ed->ifname, agent->type)); +- ed->policy.rl_rka = evb_set_rol(0) +- | evb_set_rka(evb22_conf_rka(ed->ifname, agent->type)); +-} +- +-static void evb22_ifup(char *ifname, struct lldp_agent *agent) +-{ +- struct evb22_data *ed; +- struct evb22_user_data *ud; +- +- if (agent->type != NEAREST_CUSTOMER_BRIDGE) +- return; +- LLDPAD_DBG("%s:%s agent %d called\n", __func__, ifname, agent->type); +- +- ed = evb22_data(ifname, agent->type); +- if (ed) { +- LLDPAD_DBG("%s:%s agent %d already exists\n", __func__, ifname, +- agent->type); +- return; +- } +- +- /* not found, alloc/init per-port tlv data */ +- ed = (struct evb22_data *) calloc(1, sizeof *ed); +- if (!ed) { +- LLDPAD_ERR("%s:%s agent %d malloc %zu failed\n", +- __func__, ifname, agent->type, sizeof *ed); +- return; +- } +- strncpy(ed->ifname, ifname, IFNAMSIZ); +- ed->agenttype = agent->type; +- evb22_init_tlv(ed, agent); +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_EVB22); +- LIST_INSERT_HEAD(&ud->head, ed, entry); +- LLDPAD_DBG("%s:%s agent %d added\n", __func__, ifname, agent->type); +-} +- +-/* +- * Start all modules which depend on EVB capabilities: ECP, VDP, CDCP. +- */ +-static void evb22_start_modules(char *ifname) +-{ +- LLDPAD_DBG("%s:%s START\n", __func__, ifname); +- ecp22_start(ifname); +- vdp22_start(ifname); +-} +- +-/* +- * Check for stable interfaces. When an interface goes up the carrier might +- * come and go during a start up time. Define a window during which the port +- * is considered unstable for EVB/VDP protocols. +- * +- * Use the dormantDelay counter of the port to determine a stable interface. +- */ +-static int evb22_timer(struct port *port, struct lldp_agent *agent) +-{ +- struct evb22_data *ed; +- +- if (agent->type != NEAREST_CUSTOMER_BRIDGE) +- return 0; +- ed = evb22_data(port->ifname, agent->type); +- if (!ed) +- return 0; +- if (!ed->vdp_start +- && evb_ex_rrstat(ed->out.station_s) == EVB_RRSTAT_YES) { +- ed->vdp_start = true; +- evb22_start_modules(port->ifname); +- } +- return 0; +-} +- +-static u8 evb22_mibdelete(struct port *port, struct lldp_agent *agent) +-{ +- struct evb22_data *ed; +- +- ed = evb22_data(port->ifname, agent->type); +- if (ed && (agent->type == ed->agenttype)) { +- memset(&ed->last, 0, sizeof ed->last); +- /* TODO vdp_update(port->ifname, 0); */ +- } +- return 0; +-} +- +-/* +- * Remove all interface/agent specific evb data. +- */ +-static void evb22_free_data(struct evb22_user_data *ud) +-{ +- struct evb22_data *ed; +- +- if (ud) { +- while (!LIST_EMPTY(&ud->head)) { +- ed = LIST_FIRST(&ud->head); +- LIST_REMOVE(ed, entry); +- free(ed); +- } +- } +-} +- +-void evb22_unregister(struct lldp_module *mod) +-{ +- if (mod->data) { +- evb22_free_data((struct evb22_user_data *) mod->data); +- free(mod->data); +- } +- free(mod); +- LLDPAD_DBG("%s:done\n", __func__); +-} +- +-static const struct lldp_mod_ops evb22_ops = { +- .lldp_mod_gettlv = evb22_gettlv, +- .lldp_mod_rchange = evb22_rchange, +- .lldp_mod_mibdelete = evb22_mibdelete, +- .timer = evb22_timer, +- .lldp_mod_ifdown = evb22_ifdown, +- .lldp_mod_ifup = evb22_ifup, +- .lldp_mod_register = evb22_register, +- .lldp_mod_unregister = evb22_unregister, +- .get_arg_handler = evb22_get_arg_handlers +-}; +- +-struct lldp_module *evb22_register(void) +-{ +- struct lldp_module *mod; +- struct evb22_user_data *ud; +- +- mod = calloc(1, sizeof *mod); +- if (!mod) { +- LLDPAD_ERR("%s: failed to malloc module data\n", __func__); +- return NULL; +- } +- ud = calloc(1, sizeof *ud); +- if (!ud) { +- free(mod); +- LLDPAD_ERR("%s failed to malloc module user data\n", __func__); +- return NULL; +- } +- LIST_INIT(&ud->head); +- mod->id = LLDP_MOD_EVB22; +- mod->ops = &evb22_ops; +- mod->data = ud; +- LLDPAD_DBG("%s:done\n", __func__); +- return mod; +-} +diff --git a/qbg/lldp_evb22_clif.c b/qbg/lldp_evb22_clif.c +deleted file mode 100644 +index 336273f..0000000 +--- a/qbg/lldp_evb22_clif.c ++++ /dev/null +@@ -1,201 +0,0 @@ +-/****************************************************************************** +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2010, 2012 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-#include +-#include +- +-#include "lldp_tlv.h" +-#include "clif_msgs.h" +-#include "lldp_mod.h" +-#include "lldptool.h" +-#include "lldp.h" +-#include "lldp_evb22.h" +-#include "lldp_evb22_clif.h" +- +-static void show_tlv(char *buf, size_t len, struct evb22_tlv *tlv) +-{ +- int comma = 0; +- char bridge_txt[32], station_txt[32]; +- +- memset(bridge_txt, 0, sizeof bridge_txt); +- if (evb_ex_bgid(tlv->bridge_s)) { +- strcat(bridge_txt, "bgid"); +- comma = 1; +- } +- if (evb_ex_rrcap(tlv->bridge_s)) { +- if (comma) +- strcat(bridge_txt, ","); +- strcat(bridge_txt, "rrcap"); +- comma = 1; +- } +- if (evb_ex_rrctr(tlv->bridge_s)) { +- if (comma) +- strcat(bridge_txt, ","); +- strcat(bridge_txt, "rrctr"); +- } +- +- comma = 0; +- memset(station_txt, 0, sizeof station_txt); +- if (evb_ex_sgid(tlv->station_s)) { +- strcat(station_txt, "sgid"); +- comma = 1; +- } +- if (evb_ex_rrreq(tlv->station_s)) { +- if (comma) +- strcat(station_txt, ","); +- strcat(station_txt, "rrreq"); +- comma = 1; +- } +- if (evb_ex_rrstat(tlv->station_s)) { +- if (comma) +- strcat(station_txt, ","); +- strcat(station_txt, "rrstat"); +- } +- +- snprintf(buf, len, "bridge:%s(%#02x)\n" +- "\tstation:%s(%#02x)\n" +- "\tretries:%d rte:%d\n" +- "\tmode:%s r/l:%d rwd:%d\n" +- "\tr/l:%d rka:%d\n", +- bridge_txt, tlv->bridge_s, +- station_txt, tlv->station_s, +- evb_ex_retries(tlv->r_rte), evb_ex_rte(tlv->r_rte), +- evb_ex_evbmode(tlv->evb_mode) == EVB_STATION ? +- "station" : "bridge", +- evb_ex_rol(tlv->evb_mode), +- evb_ex_rwd(tlv->evb_mode), +- evb_ex_rol(tlv->rl_rka), evb_ex_rka(tlv->rl_rka)); +-} +- +-static void evb22_print_cfg_tlv(u16 len, char *info) +-{ +- struct evb22_tlv tlv; +- char buf[256]; +- +- if (len != 5) { +- printf("Bad evbcfg TLV: %s\n", info); +- return; +- } +- memset(&tlv, 0, sizeof tlv); +- memset(buf, 0, sizeof buf); +- hexstr2bin(&info[0], &tlv.bridge_s, sizeof tlv.bridge_s); +- hexstr2bin(&info[2], &tlv.station_s, sizeof tlv.station_s); +- hexstr2bin(&info[4], &tlv.r_rte, sizeof tlv.r_rte); +- hexstr2bin(&info[6], &tlv.evb_mode, sizeof tlv.evb_mode); +- hexstr2bin(&info[8], &tlv.rl_rka, sizeof tlv.rl_rka); +- show_tlv(buf, sizeof buf, &tlv); +- printf("%s", buf); +-} +- +-static struct type_name_info evb22_tlv_names[] = { +- { +- .type = TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), +- .name = "EVB Configuration TLV", +- .key = "evb", +- .print_info = evb22_print_cfg_tlv +- }, +- { +- .type = INVALID_TLVID +- } +-}; +- +-static int evb22_print_help() +-{ +- struct type_name_info *tn = &evb22_tlv_names[0]; +- +- while (tn->type != INVALID_TLVID) { +- if (tn->key && strlen(tn->key) && tn->name) { +- printf(" %s", tn->key); +- if (strlen(tn->key)+3 < 8) +- printf("\t"); +- printf("\t: %s\n", tn->name); +- } +- tn++; +- } +- +- return 0; +-} +- +-static void evb22_cli_unregister(struct lldp_module *mod) +-{ +- free(mod); +-} +- +-/* return 1: if it printed the TLV +- * 0: if it did not +- */ +-static int evb22_print_tlv(u32 tlvid, u16 len, char *info) +-{ +- struct type_name_info *tn = &evb22_tlv_names[0]; +- +- while (tn->type != INVALID_TLVID) { +- if (tlvid == tn->type) { +- printf("%s\n", tn->name); +- if (tn->print_info) { +- printf("\t"); +- tn->print_info(len-4, info); +- } +- return 1; +- } +- tn++; +- } +- +- return 0; +-} +- +-static u32 evb22_lookup_tlv_name(char *tlvid_str) +-{ +- struct type_name_info *tn = &evb22_tlv_names[0]; +- +- while (tn->type != INVALID_TLVID) { +- if (!strcasecmp(tn->key, tlvid_str)) +- return tn->type; +- tn++; +- } +- return INVALID_TLVID; +-} +- +-static const struct lldp_mod_ops evb22_ops_clif = { +- .lldp_mod_register = evb22_cli_register, +- .lldp_mod_unregister = evb22_cli_unregister, +- .print_tlv = evb22_print_tlv, +- .lookup_tlv_name = evb22_lookup_tlv_name, +- .print_help = evb22_print_help +-}; +- +-struct lldp_module *evb22_cli_register(void) +-{ +- struct lldp_module *mod; +- +- mod = calloc(1, sizeof(*mod)); +- if (!mod) { +- fprintf(stderr, "%s failed to malloc module data\n", __func__); +- return NULL; +- } +- mod->id = LLDP_MOD_EVB22; +- mod->ops = &evb22_ops_clif; +- +- return mod; +-} +diff --git a/qbg/lldp_evb22_cmds.c b/qbg/lldp_evb22_cmds.c +deleted file mode 100644 +index 51b7ba1..0000000 +--- a/qbg/lldp_evb22_cmds.c ++++ /dev/null +@@ -1,738 +0,0 @@ +-/****************************************************************************** +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2012 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-#define _GNU_SOURCE +- +-#include +-#include +-#include +- +-#include "lldp.h" +-#include "lldp_evb22.h" +-#include "lldp_tlv.h" +-#include "lldp_mand_clif.h" +-#include "config.h" +-#include "clif_msgs.h" +-#include "messages.h" +- +-/* +- * Defines for configuration file name tags. +- */ +-#define EVB_BUF_SIZE 256 +-#define EVB_CONF_MODE "evbmode" +-#define EVB_CONF_RRREQ "evbrrreq" +-#define EVB_CONF_RRCAP "evbrrcap" +-#define EVB_CONF_GPID "evbgpid" +-#define EVB_CONF_RETRIES "ecpretries" +-#define EVB_CONF_RTE "ecprte" +-#define EVB_CONF_RWD "vdprwd" +-#define EVB_CONF_RKA "vdprka" +-#define EVB_CONF_BRIDGE "bridge" +-#define EVB_CONF_STATION "station" +- +-/* +- * Read EVB specific data from the configuration file. +- */ +-static const char *evb22_conf_string(char *ifname, enum agent_type type, +- char *ext, int def) +-{ +- char arg_path[EVB_BUF_SIZE]; +- const char *param = NULL; +- +- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", +- TLVID_PREFIX, TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), +- ext); +- if (get_cfg(ifname, type, arg_path, ¶m, CONFIG_TYPE_STRING)) +- LLDPAD_INFO("%s:%s agent %d loading EVB policy for %s" +- " failed, using default (%d)\n", __func__, +- ifname, type, ext, def); +- return param; +-} +- +-static int evb22_conf_int(char *ifname, enum agent_type type, +- char *ext, int def, int cfgtype) +-{ +- char arg_path[EVB_BUF_SIZE]; +- int param; +- +- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", +- TLVID_PREFIX, TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), +- ext); +- if (get_cfg(ifname, type, arg_path, ¶m, cfgtype)) { +- LLDPAD_INFO("%s:%s agent %d loading EVB policy for %s" +- " failed, using default (%d)\n", __func__, +- ifname, type, ext, def); +- return def; +- } +- return param; +-} +- +-/* +- * Read EXP parameter. Defaults to 8 --> 10 * 2 ^ 8 = 2560us > 2ms. +- */ +-static int exponent(char *ifname, enum agent_type type, char *txt, int def) +-{ +- int value; +- +- value = evb22_conf_int(ifname, type, txt, def, CONFIG_TYPE_INT); +- if (value > 31) { +- LLDPAD_DBG("%s:%s agent %d invalid %s %d\n", __func__, +- ifname, type, txt, value); +- value = def; +- } +- LLDPAD_DBG("%s:%s agent %d policy %s %d\n", __func__, +- ifname, type, txt, value); +- return value; +-} +- +-/* +- * Read retransmission exponent parameter. +- */ +-int evb22_conf_rte(char *ifname, enum agent_type type) +-{ +- return exponent(ifname, type, EVB_CONF_RTE, 8); +-} +- +-/* +- * Read reinit keep alive parameter. Same as RTE. +- */ +-int evb22_conf_rka(char *ifname, enum agent_type type) +-{ +- return exponent(ifname, type, EVB_CONF_RKA, 20); +-} +- +-/* +- * Read resource wait delay parameter. Same as RTE. +- */ +-int evb22_conf_rwd(char *ifname, enum agent_type type) +-{ +- return exponent(ifname, type, EVB_CONF_RWD, 20); +-} +- +-/* +- * Read max retries parameter. Defaults to 3. +- */ +-int evb22_conf_retries(char *ifname, enum agent_type type) +-{ +- int value; +- +- value = evb22_conf_int(ifname, type, EVB_CONF_RETRIES, 3, +- CONFIG_TYPE_INT); +- if (value > 7) { +- LLDPAD_DBG("%s:%s agent %d invalid %s %d\n", __func__, +- ifname, type, EVB_CONF_RETRIES, value); +- value = 3; +- } +- LLDPAD_DBG("%s:%s agent %d policy %s %d\n", __func__, +- ifname, type, EVB_CONF_RETRIES, value); +- return value; +-} +- +-/* +- * Read station group id parameter. Defaults to false. +- */ +-int evb22_conf_gid(char *ifname, enum agent_type type) +-{ +- int value; +- +- value = evb22_conf_int(ifname, type, EVB_CONF_GPID, false, +- CONFIG_TYPE_BOOL); +- LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, +- ifname, type, EVB_CONF_GPID, value ? "true" : "false"); +- return value; +-} +- +-/* +- * Read reflective-relay bridge capability parameter. Defaults to false. +- */ +-int evb22_conf_rrcap(char *ifname, enum agent_type type) +-{ +- int value; +- +- value = evb22_conf_int(ifname, type, EVB_CONF_RRCAP, false, +- CONFIG_TYPE_BOOL); +- LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, +- ifname, type, EVB_CONF_RRCAP, value ? "true" : "false"); +- return value; +-} +- +-/* +- * Read reflective-relay station request parameter. Defaults to false. +- */ +-int evb22_conf_rrreq(char *ifname, enum agent_type type) +-{ +- int value; +- +- value = evb22_conf_int(ifname, type, EVB_CONF_RRREQ, false, +- CONFIG_TYPE_BOOL); +- LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, +- ifname, type, EVB_CONF_RRREQ, value ? "true" : "false"); +- return value; +-} +- +-/* +- * Read station/bridge role from configuration file. Defaults to station +- */ +-int evb22_conf_evbmode(char *ifname, enum agent_type type) +-{ +- int mode = EVB_STATION; +- const char *value; +- +- value = evb22_conf_string(ifname, type, EVB_CONF_MODE, mode); +- if (value) { +- if (!strcasecmp(value, EVB_CONF_BRIDGE)) +- mode = EVB_BRIDGE; +- else if (strcasecmp(value, EVB_CONF_STATION)) { +- LLDPAD_ERR("%s:%s agent %d invalid evbmode %s\n", +- __func__, ifname, type, value); +- value = EVB_CONF_STATION; +- } +- } else +- value = EVB_CONF_STATION; +- LLDPAD_DBG("%s:%s agent %d policy %s %s(%#x)\n", __func__, +- ifname, type, EVB_CONF_MODE, value, mode); +- return mode; +-} +- +-/* +- * Read transmit status from configuration file. +- */ +-int evb22_conf_enabletx(char *ifname, enum agent_type type) +-{ +- return is_tlv_txenabled(ifname, type, +- TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE)); +-} +- +-static int evb22_cmdok(struct cmd *cmd, cmd_status expected) +-{ +- if (cmd->cmd != expected) +- return cmd_invalid; +- switch (cmd->tlvid) { +- case TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE): +- return cmd_success; +- case INVALID_TLVID: +- return cmd_invalid; +- default: +- return cmd_not_applicable; +- } +-} +- +-static int get_arg_evbmode(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- struct evb22_data *ed; +- char *s; +- cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); +- +- if (good_cmd != cmd_success) +- return good_cmd; +- ed = evb22_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) +- s = EVB_CONF_STATION; +- else +- s = EVB_CONF_BRIDGE; +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); +- return cmd_success; +-} +- +-static int set2_arg_evbmode(struct cmd *cmd, char *arg, const char *argvalue, +- bool test) +-{ +- char arg_path[EVB_BUF_SIZE]; +- struct evb22_data *ed; +- cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); +- u8 mode; +- +- if (good_cmd != cmd_success) +- return good_cmd; +- if (strcasecmp(argvalue, EVB_CONF_BRIDGE) +- && strcasecmp(argvalue, EVB_CONF_STATION)) +- return cmd_bad_params; +- ed = evb22_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (test) +- return cmd_success; +- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", +- TLVID_PREFIX, cmd->tlvid, arg); +- +- if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, +- CONFIG_TYPE_STRING)) { +- LLDPAD_ERR("%s: error saving EVB mode (%s)\n", ed->ifname, +- argvalue); +- return cmd_failed; +- } +- mode = strcasecmp(argvalue, EVB_CONF_BRIDGE) ? EVB_STATION : EVB_BRIDGE; +- ed->policy.evb_mode = evb_maskoff_evbmode(ed->policy.evb_mode) | +- evb_set_evbmode(mode); +- LLDPAD_INFO("%s: changed EVB mode (%s)\n", ed->ifname, argvalue); +- return cmd_success; +-} +- +-static int set_arg_evbmode(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return set2_arg_evbmode(cmd, arg, argvalue, false); +-} +- +-static int test_arg_evbmode(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return set2_arg_evbmode(cmd, arg, argvalue, true); +-} +- +-static int get_txmit(struct evb22_data *ed) +-{ +- return ed->txmit; +-} +- +-static void set_txmit(struct evb22_data *ed, int value) +-{ +- ed->txmit = value; +-} +- +-static int get_gpid(struct evb22_data *ed) +-{ +- int mode = evb_ex_evbmode(ed->policy.evb_mode); +- +- if (mode == EVB_STATION && evb_ex_sgid(ed->policy.station_s)) +- return 1; +- if (mode == EVB_BRIDGE && evb_ex_bgid(ed->policy.bridge_s)) +- return 1; +- return 0; +-} +- +-static void set_gpid(struct evb22_data *ed, int value) +-{ +- if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) +- ed->policy.station_s = evb_maskoff_sgid(ed->policy.station_s) +- | evb_set_sgid(value); +- else +- ed->policy.bridge_s = evb_maskoff_bgid(ed->policy.bridge_s) +- | evb_set_bgid(value); +-} +- +-static void set_rrcap(struct evb22_data *ed, int value) +-{ +- ed->policy.bridge_s = evb_maskoff_rrcap(ed->policy.bridge_s) +- | evb_set_rrcap(value); +-} +- +-static int get_rrcap(struct evb22_data *ed) +-{ +- return evb_ex_rrcap(ed->policy.bridge_s); +-} +- +-static void set_rrreq(struct evb22_data *ed, int value) +-{ +- ed->policy.station_s = evb_maskoff_rrreq(ed->policy.station_s) +- | evb_set_rrreq(value); +-} +- +-static int get_rrreq(struct evb22_data *ed) +-{ +- return evb_ex_rrreq(ed->policy.station_s); +-} +- +-/* +- * Read a boolean value from the command line argument and apply the new +- * value to parameter. +- */ +-static int scan_bool(struct cmd *cmd, char *arg, char *argvalue, bool test, +- void (*fct)(struct evb22_data *, int)) +-{ +- int value; +- char arg_path[EVB_BUF_SIZE]; +- struct evb22_data *ed; +- cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); +- +- if (good_cmd != cmd_success) +- return good_cmd; +- if (!strcasecmp(argvalue, VAL_YES)) +- value = 1; +- else if (!strcasecmp(argvalue, VAL_NO)) +- value = 0; +- else +- return cmd_bad_params; +- ed = evb22_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (test) +- return cmd_success; +- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", +- TLVID_PREFIX, cmd->tlvid, arg); +- if (set_cfg(cmd->ifname, cmd->type, arg_path, &value, +- CONFIG_TYPE_BOOL)){ +- LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", ed->ifname, +- argvalue); +- return cmd_failed; +- } +- LLDPAD_INFO("%s: changed EVB %s (%s)\n", ed->ifname, arg, argvalue); +- (*fct)(ed, value); +- somethingChangedLocal(cmd->ifname, cmd->type); +- return cmd_success; +-} +- +-static int show_bool(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len, +- int (*fct)(struct evb22_data *)) +-{ +- struct evb22_data *ed; +- char *s; +- cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); +- +- if (good_cmd != cmd_success) +- return good_cmd; +- ed = evb22_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if ((*fct)(ed)) +- s = VAL_YES; +- else +- s = VAL_NO; +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); +- return cmd_success; +-} +- +-static int get_arg_tlvtxenable(struct cmd *cmd, char *arg, +- UNUSED char *argvalue, char *obuf, int obuf_len) +-{ +- return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_txmit); +-} +- +-static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_bool(cmd, arg, argvalue, false, set_txmit); +-} +- +-static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_bool(cmd, arg, argvalue, true, 0); +-} +- +-static int get_arg_gpid(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_gpid); +-} +- +-static int set_arg_gpid(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_bool(cmd, arg, argvalue, false, set_gpid); +-} +- +-static int test_arg_gpid(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_bool(cmd, arg, argvalue, true, 0); +-} +- +-static int get_arg_rrcap(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_rrcap); +-} +- +-static int set_arg_rrcap(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_bool(cmd, arg, argvalue, false, set_rrcap); +-} +- +-static int test_arg_rrcap(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_bool(cmd, arg, argvalue, true, 0); +-} +- +-static int get_arg_rrreq(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_rrreq); +-} +- +-static int set_arg_rrreq(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_bool(cmd, arg, argvalue, false, set_rrreq); +-} +- +-static int test_arg_rrreq(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_bool(cmd, arg, argvalue, true, 0); +-} +- +- +-static void set_retries(struct evb22_data *ed, int value) +-{ +- ed->policy.r_rte = evb_maskoff_retries(ed->policy.r_rte) +- | evb_set_retries(value); +-} +- +-static int get_retries(struct evb22_data *ed) +-{ +- return evb_ex_retries(ed->policy.r_rte); +-} +- +-static void set_rte(struct evb22_data *ed, int value) +-{ +- ed->policy.r_rte = evb_maskoff_rte(ed->policy.r_rte) +- | evb_set_rte(value); +-} +- +-static int get_rte(struct evb22_data *ed) +-{ +- return evb_ex_rte(ed->policy.r_rte); +-} +- +-static void set_rwd(struct evb22_data *ed, int value) +-{ +- ed->policy.evb_mode = evb_maskoff_rwd(ed->policy.evb_mode) +- | evb_set_rwd(value); +-} +- +-static int get_rwd(struct evb22_data *ed) +-{ +- return evb_ex_rwd(ed->policy.evb_mode); +-} +- +-static void set_rka(struct evb22_data *ed, int value) +-{ +- ed->policy.rl_rka = evb_maskoff_rka(ed->policy.rl_rka) +- | evb_set_rka(value); +-} +- +-static int get_rka(struct evb22_data *ed) +-{ +- return evb_ex_rka(ed->policy.rl_rka); +-} +- +-static int scan_31bit(struct cmd *cmd, char *arg, const char *argvalue, +- bool test, void (*fct)(struct evb22_data *, int), +- int limit) +-{ +- char arg_path[EVB_BUF_SIZE]; +- struct evb22_data *ed; +- int value; +- char *endp; +- cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); +- +- if (good_cmd != cmd_success) +- return good_cmd; +- value = strtoul(argvalue, &endp, 0); +- if (*endp != '\0' || value > limit) +- return cmd_bad_params; +- ed = evb22_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (test) +- return cmd_success; +- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", +- TLVID_PREFIX, cmd->tlvid, arg); +- if (set_cfg(ed->ifname, cmd->type, arg_path, &value, +- CONFIG_TYPE_INT)){ +- LLDPAD_ERR("%s: error saving EVB %s (%d)\n", ed->ifname, arg, +- value); +- return cmd_failed; +- } +- LLDPAD_INFO("%s: changed EVB %s (%s)\n", ed->ifname, arg, argvalue); +- (*fct)(ed, value); +- somethingChangedLocal(cmd->ifname, cmd->type); +- return cmd_success; +-} +- +-static int show_31bit(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len, +- int (*fct)(struct evb22_data *)) +-{ +- struct evb22_data *ed; +- char s[EVB_BUF_SIZE]; +- cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); +- +- if (good_cmd != cmd_success) +- return good_cmd; +- ed = evb22_data((char *) &cmd->ifname, cmd->type); +- if (!ed) +- return cmd_invalid; +- if (sprintf(s, "%i", (*fct)(ed)) <= 0) +- return cmd_invalid; +- snprintf(obuf, obuf_len, "%02x%s%04x%s", +- (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); +- return cmd_success; +-} +- +-static int get_arg_retries(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_retries); +-} +- +-static int set_arg_retries(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_31bit(cmd, arg, argvalue, false, set_retries, 7); +-} +- +-static int test_arg_retries(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_31bit(cmd, arg, argvalue, true, 0, 7); +-} +- +-static int get_arg_rte(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rte); +-} +- +-static int set_arg_rte(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_31bit(cmd, arg, argvalue, false, set_rte, 31); +-} +- +-static int test_arg_rte(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_31bit(cmd, arg, argvalue, true, 0, 31); +-} +- +-static int get_arg_rwd(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rwd); +-} +- +-static int set_arg_rwd(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_31bit(cmd, arg, argvalue, false, set_rwd, 31); +-} +- +-static int test_arg_rwd(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_31bit(cmd, arg, argvalue, true, 0, 31); +-} +- +-static int get_arg_rka(struct cmd *cmd, char *arg, UNUSED char *argvalue, +- char *obuf, int obuf_len) +-{ +- return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rka); +-} +- +-static int set_arg_rka(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_31bit(cmd, arg, argvalue, false, set_rka, 31); +-} +- +-static int test_arg_rka(struct cmd *cmd, char *arg, char *argvalue, +- UNUSED char *obuf, UNUSED int obuf_len) +-{ +- return scan_31bit(cmd, arg, argvalue, true, 0, 31); +-} +- +-static struct arg_handlers arg_handlers[] = { +- { +- .arg = EVB_CONF_RKA, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_rka, +- .handle_set = set_arg_rka, +- .handle_test = test_arg_rka +- }, +- { +- .arg = EVB_CONF_RWD, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_rwd, +- .handle_set = set_arg_rwd, +- .handle_test = test_arg_rwd +- }, +- { +- .arg = EVB_CONF_RTE, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_rte, +- .handle_set = set_arg_rte, +- .handle_test = test_arg_rte +- }, +- { +- .arg = EVB_CONF_RETRIES, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_retries, +- .handle_set = set_arg_retries, +- .handle_test = test_arg_retries +- }, +- { +- .arg = EVB_CONF_RRREQ, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_rrreq, +- .handle_set = set_arg_rrreq, +- .handle_test = test_arg_rrreq +- }, +- { +- .arg = EVB_CONF_RRCAP, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_rrcap, +- .handle_set = set_arg_rrcap, +- .handle_test = test_arg_rrcap +- }, +- { +- .arg = EVB_CONF_GPID, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_gpid, +- .handle_set = set_arg_gpid, +- .handle_test = test_arg_gpid +- }, +- { +- .arg = EVB_CONF_MODE, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_evbmode, +- .handle_set = set_arg_evbmode, +- .handle_test = test_arg_evbmode +- }, +- { +- .arg = ARG_TLVTXENABLE, +- .arg_class = TLV_ARG, +- .handle_get = get_arg_tlvtxenable, +- .handle_set = set_arg_tlvtxenable, +- .handle_test = test_arg_tlvtxenable +- }, +- { +- .arg = 0 +- } +-}; +- +-struct arg_handlers *evb22_get_arg_handlers() +-{ +- return &arg_handlers[0]; +-} +diff --git a/qbg/lldp_vdp22.c b/qbg/lldp_vdp22.c +deleted file mode 100644 +index 1d151ea..0000000 +--- a/qbg/lldp_vdp22.c ++++ /dev/null +@@ -1,287 +0,0 @@ +-/****************************************************************************** +- +- Implementation of EVB TLVs for LLDP +- (c) Copyright IBM Corp. 2013 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-#define _GNU_SOURCE +-#include +-#include +-#include +- +-#include +- +-#include "messages.h" +-#include "config.h" +- +-#include "lldp_vdpnl.h" +-#include "lldp_qbg22.h" +-#include "lldp_vdp22.h" +- +-/* +- * VDP22 helper functions +- */ +-/* +- * Find the vdp data associated with an interface. +- * Return pointer or NULL if not found. +- */ +-static struct vdp22 *vdp22_findif(const char *ifname, +- struct vdp22_user_data *ud) +-{ +- struct vdp22 *vdp = 0; +- +- if (ud) { +- LIST_FOREACH(vdp, &ud->head, entry) +- if (!strncmp(ifname, vdp->ifname, IFNAMSIZ)) +- break; +- } +- return vdp; +-} +- +-/* +- * Update data exchanged via ECP protocol. +- * Returns true when data update succeeded. +- */ +-static int data_from_ecp(char *ifname, struct ecp22_to_ulp *ptr) +-{ +- struct vdp22_user_data *vud; +- struct vdp22 *vdp; +- +- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); +- vdp = vdp22_findif(ifname, vud); +- if (vdp) { +- memcpy(vdp->input, ptr->data, ptr->len); +- vdp->input_len = ptr->len; +- return 0; +- } +- return -ENOENT; +-} +- +-/* +- * Update data exchanged via EVB protocol. +- * Returns true when data update succeeded. +- */ +-static int data_from_evb(char *ifname, struct evb22_to_vdp22 *ptr) +-{ +- struct vdp22_user_data *vud; +- struct vdp22 *vdp; +- +- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); +- vdp = vdp22_findif(ifname, vud); +- if (vdp) { +- vdp->max_rwd = ptr->max_rwd; +- vdp->max_rka = ptr->max_rka; +- vdp->gpid = ptr->gpid; +- return 0; +- } +- return -ENOENT; +-} +- +-/* +- * Handle notifications from other modules. Check if sender-id and data type +- * indicator match. Return false when data could not be delivered. +- */ +-static int vdp22_notify(int sender_id, char *ifname, void *data) +-{ +- struct qbg22_imm *qbg = (struct qbg22_imm *)data; +- +- LLDPAD_DBG("%s:%s sender-id:%#x data_type:%d\n", __func__, ifname, +- sender_id, qbg->data_type); +- if (sender_id == LLDP_MOD_EVB22 && qbg->data_type == EVB22_TO_VDP22) +- return data_from_evb(ifname, &qbg->u.b); +- if (sender_id == LLDP_MOD_ECP22 && qbg->data_type == ECP22_TO_ULP) +- return data_from_ecp(ifname, &qbg->u.c); +- return 0; +-} +- +-/* +- * Remove a vdp22 element and delete the chain of active profiles. +- */ +-static void vdp22_free_elem(struct vdp22 *vdp) +-{ +- while (!LIST_EMPTY(&vdp->prof22_head)) { +- struct vsi22_profile *prof = LIST_FIRST(&vdp->prof22_head); +- +- free(prof); +- } +- LIST_REMOVE(vdp, entry); +- free(vdp); +-} +- +-/* +- * Disable the interface for VDP protocol support. +- */ +-void vdp22_stop(char *ifname) +-{ +- struct vdp22_user_data *vud; +- struct vdp22 *vdp; +- +- LLDPAD_DBG("%s:%s stop vdp\n", __func__, ifname); +- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); +- if (!vud) { +- LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); +- return; +- } +- vdp = vdp22_findif(ifname, vud); +- if (!vdp) { +- LLDPAD_ERR("%s:%s no VDP22 data\n", __func__, ifname); +- return; +- } +- vdp22_free_elem(vdp); +-} +- +-/* +- * vdp22_create - create data structure and initialize vdp protocol +- * @ifname: interface for which the vdp protocol is initialized +- * +- * returns NULL on error and an pointer to the vdp22 structure on success. +- * +- * finds the port to the interface name, sets up the receive handle for +- * incoming vdp frames and initializes the vdp rx and tx state machines. +- * To be called when a successful exchange of EVB TLVs has been +- * made and ECP protocols are supported by both sides. +- */ +-static struct vdp22 *vdp22_create(const char *ifname, +- struct vdp22_user_data *eud) +-{ +- struct vdp22 *vdp; +- +- vdp = calloc(1, sizeof *vdp); +- if (!vdp) { +- LLDPAD_ERR("%s:%s unable to allocate vdp protocol\n", __func__, +- ifname); +- return NULL; +- } +- strncpy(vdp->ifname, ifname, sizeof vdp->ifname); +- LIST_INIT(&vdp->prof22_head); +- LIST_INSERT_HEAD(&eud->head, vdp, entry); +- LLDPAD_DBG("%s:%s create vdp data\n", __func__, ifname); +- return vdp; +-} +- +-/* +- * Query the supported VDP protocol on an interface. +- */ +-static struct vdp22 *vdp22_getvdp(const char *ifname) +-{ +- struct vdp22_user_data *vud; +- struct vdp22 *vdp = NULL; +- +- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); +- if (vud) +- vdp = vdp22_findif(ifname, vud); +- LLDPAD_DBG("%s:%s vdp %p\n", __func__, ifname, vdp); +- return vdp; +-} +- +-int vdp22_query(const char *ifname) +-{ +- int rc = 0; +- +- if (vdp22_getvdp(ifname)) +- rc = 1; +- LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); +- return rc; +-} +- +-/* +- * Enable the interface for VDP protocol support. +- */ +-void vdp22_start(const char *ifname) +-{ +- struct vdp22_user_data *vud; +- struct vdp22 *vdp; +- +- LLDPAD_DBG("%s:%s start vdp\n", __func__, ifname); +- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); +- if (!vud) { +- LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); +- return; +- } +- vdp = vdp22_findif(ifname, vud); +- if (!vdp) +- vdp = vdp22_create(ifname, vud); +-} +- +-/* +- * Handle a VSI request from buddy. +- */ +-int vdp22_request(struct vdpnl_vsi *vsi) +-{ +- int rc = -ENODEV; +- LLDPAD_DBG("%s:%s rc:%d\n", __func__, vsi->ifname, rc); +- return rc; +-} +- +-/* +- * Remove all interface/agent specific vdp data. +- */ +-static void vdp22_free_data(struct vdp22_user_data *ud) +-{ +- if (ud) { +- while (!LIST_EMPTY(&ud->head)) { +- struct vdp22 *vd = LIST_FIRST(&ud->head); +- +- vdp22_free_elem(vd); +- } +- } +-} +- +-void vdp22_unregister(struct lldp_module *mod) +-{ +- if (mod->data) { +- vdp22_free_data((struct vdp22_user_data *)mod->data); +- free(mod->data); +- } +- free(mod); +- LLDPAD_DBG("%s:done\n", __func__); +-} +- +-static const struct lldp_mod_ops vdp22_ops = { +- .lldp_mod_register = vdp22_register, +- .lldp_mod_unregister = vdp22_unregister, +- .lldp_mod_notify = vdp22_notify +-}; +- +-struct lldp_module *vdp22_register(void) +-{ +- struct lldp_module *mod; +- struct vdp22_user_data *ud; +- +- mod = calloc(1, sizeof *mod); +- if (!mod) { +- LLDPAD_ERR("%s: failed to malloc module data\n", __func__); +- return NULL; +- } +- ud = calloc(1, sizeof *ud); +- if (!ud) { +- free(mod); +- LLDPAD_ERR("%s failed to malloc module user data\n", __func__); +- return NULL; +- } +- LIST_INIT(&ud->head); +- mod->id = LLDP_MOD_VDP22; +- mod->ops = &vdp22_ops; +- mod->data = ud; +- LLDPAD_DBG("%s:done\n", __func__); +- return mod; +-} +diff --git a/qbg/lldp_vdpnl.c b/qbg/lldp_vdpnl.c +deleted file mode 100644 +index 4a117d6..0000000 +--- a/qbg/lldp_vdpnl.c ++++ /dev/null +@@ -1,502 +0,0 @@ +-/****************************************************************************** +- +- Implementation of VDP according to IEEE 802.1Qbg +- (c) Copyright IBM Corp. 2013 +- +- Author(s): Thomas Richter +- +- This program is free software; you can redistribute it and/or modify it +- under the terms and conditions of the GNU General Public License, +- version 2, as published by the Free Software Foundation. +- +- This program is distributed in the hope it will be useful, but WITHOUT +- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- more details. +- +- You should have received a copy of the GNU General Public License along with +- this program; if not, write to the Free Software Foundation, Inc., +- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- +- The full GNU General Public License is included in this distribution in +- the file called "COPYING". +- +-******************************************************************************/ +- +-/* +- * Contains netlink message parsing for VDP protocol from libvirtd or other +- * buddies. +- */ +- +-#include +-#include +-#include +- +-#include +- +-#include +-#include +-#include +- +-#include "messages.h" +-#include "lldp_vdp.h" +-#include "lldp_vdp22.h" +-#include "lldp_vdpnl.h" +-#include "lldp_qbg_utils.h" +-#include "lldp_rtnl.h" +- +-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_VF] = { .type = NLA_U32 }, +- [IFLA_PORT_PROFILE] = { .type = NLA_STRING }, +- [IFLA_PORT_VSI_TYPE] = { .minlen = sizeof(struct ifla_port_vsi) }, +- [IFLA_PORT_INSTANCE_UUID] = { .minlen = PORT_UUID_MAX, +- .maxlen = PORT_UUID_MAX, }, +- [IFLA_PORT_HOST_UUID] = { .minlen = PORT_UUID_MAX, +- .maxlen = PORT_UUID_MAX, }, +- [IFLA_PORT_REQUEST] = { .type = NLA_U8 }, +- [IFLA_PORT_RESPONSE] = { .type = NLA_U16 }, +-}; +- +-/* +- * Retrieve name of interface and its index value from the netlink messaage +- * and store it in the data structure. +- * The GETLINK message may or may not contain the IFLA_IFNAME attribute. +- * Return 0 on success and errno on error. +- */ +-static int vdpnl_get(struct nlmsghdr *nlh, struct vdpnl_vsi *p) +-{ +- struct nlattr *tb[IFLA_MAX + 1]; +- struct ifinfomsg *ifinfo; +- +- if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), +- (struct nlattr **)&tb, IFLA_MAX, NULL)) { +- LLDPAD_ERR("%s: error parsing GETLINK request\n", __func__); +- return -EINVAL; +- } +- +- ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh); +- p->ifindex = ifinfo->ifi_index; +- if (tb[IFLA_IFNAME]) { +- memcpy(p->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), +- sizeof p->ifname); +- } else if (!if_indextoname(p->ifindex, p->ifname)) { +- LLDPAD_ERR("%s: ifindex %d without interface name\n", __func__, +- p->ifindex); +- return -EINVAL; +- } +- LLDPAD_DBG("%s: IFLA_IFNAME:%s ifindex:%d\n", __func__, p->ifname, +- p->ifindex); +- return 0; +-} +- +-static void vdpnl_show(struct vdpnl_vsi *vsi) +-{ +- char instance[VDP_UUID_STRLEN + 2]; +- struct vdpnl_mac *mac; +- int i; +- +- LLDPAD_DBG("%s: IFLA_IFNAME=%s index:%d\n", __func__, vsi->ifname, +- vsi->ifindex); +- for (i = 0, mac = vsi->maclist; i < vsi->macsz; ++i, ++mac) { +- LLDPAD_DBG("%s: IFLA_VF_MAC=%2x:%2x:%2x:%2x:%2x:%2x\n", +- __func__, mac->mac[0], mac->mac[1], mac->mac[2], +- mac->mac[3], mac->mac[4], mac->mac[5]); +- LLDPAD_DBG("%s: IFLA_VF_VLAN=%d\n", __func__, mac->vlan); +- } +- LLDPAD_DBG("%s: IFLA_PORT_VSI_TYPE=mgr_id:%d type_id:%ld " +- "typeid_version:%d\n", +- __func__, vsi->vsi_mgrid, vsi->vsi_typeid, +- vsi->vsi_typeversion); +- vdp_uuid2str(vsi->vsi_uuid, instance, sizeof(instance)); +- LLDPAD_DBG("%s: IFLA_PORT_INSTANCE_UUID=%s\n", __func__, instance); +- LLDPAD_DBG("%s: IFLA_PORT_REQUEST=%d\n", __func__, vsi->request); +- LLDPAD_DBG("%s: IFLA_PORT_RESPONSE=%d\n", __func__, vsi->response); +-} +- +-/* +- * Parse the IFLA_IFLA_VF_PORTIFLA_VF_PORTS block of the netlink message. +- * Return zero on success and errno else. +- */ +-static int vdpnl_vfports(struct nlattr *vfports, struct vdpnl_vsi *vsi) +-{ +- char instance[VDP_UUID_STRLEN + 2]; +- struct nlattr *tb_vf_ports, *tb3[IFLA_PORT_MAX + 1]; +- int rem; +- +- if (!vfports) { +- LLDPAD_DBG("%s: FOUND NO IFLA_VF_PORTS\n", __func__); +- return -EINVAL; +- } +- +- nla_for_each_nested(tb_vf_ports, vfports, rem) { +- if (nla_type(tb_vf_ports) != IFLA_VF_PORT) { +- LLDPAD_DBG("%s: not a IFLA_VF_PORT skipping\n", +- __func__); +- continue; +- } +- if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports, +- ifla_port_policy)) { +- LLDPAD_ERR("%s: IFLA_PORT_MAX parsing failed\n", +- __func__); +- return -EINVAL; +- } +- if (tb3[IFLA_PORT_VF]) +- LLDPAD_DBG("%s: IFLA_PORT_VF=%d\n", __func__, +- *(uint32_t *) RTA_DATA(tb3[IFLA_PORT_VF])); +- if (tb3[IFLA_PORT_PROFILE]) +- LLDPAD_DBG("%s: IFLA_PORT_PROFILE=%s\n", __func__, +- (char *)RTA_DATA(tb3[IFLA_PORT_PROFILE])); +- if (tb3[IFLA_PORT_HOST_UUID]) { +- unsigned char *uuid; +- +- uuid = (unsigned char *) +- RTA_DATA(tb3[IFLA_PORT_HOST_UUID]); +- vdp_uuid2str(uuid, instance, sizeof(instance)); +- LLDPAD_DBG("%s: IFLA_PORT_HOST_UUID=%s\n", __func__, +- instance); +- } +- 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]; +- vsi->vsi_mgrid = pvsi->vsi_mgr_id; +- vsi->vsi_typeversion = pvsi->vsi_type_version; +- vsi->vsi_typeid = tid; +- } +- if (tb3[IFLA_PORT_INSTANCE_UUID]) { +- unsigned char *uuid = (unsigned char *) +- RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]); +- memcpy(vsi->vsi_uuid, uuid, sizeof vsi->vsi_uuid); +- } +- if (tb3[IFLA_PORT_REQUEST]) +- vsi->request = +- *(uint8_t *) RTA_DATA(tb3[IFLA_PORT_REQUEST]); +- if (tb3[IFLA_PORT_RESPONSE]) +- vsi->response = +- *(uint16_t *) RTA_DATA(tb3[IFLA_PORT_RESPONSE]); +- } +- return 0; +-} +- +-/* +- * Parse the IFLA_VFINFO_LIST block of the netlink message. +- * Return zero on success and errno else. +- */ +-static int vdpnl_vfinfolist(struct nlattr *vfinfolist, struct vdpnl_vsi *vsi) +-{ +- struct nlattr *le1, *vf[IFLA_VF_MAX + 1]; +- int rem; +- +- if (!vfinfolist) { +- LLDPAD_ERR("%s: IFLA_VFINFO_LIST missing\n", __func__); +- return -EINVAL; +- } +- nla_for_each_nested(le1, vfinfolist, rem) { +- if (nla_type(le1) != IFLA_VF_INFO) { +- LLDPAD_ERR("%s: parsing of IFLA_VFINFO_LIST failed\n", +- __func__); +- return -EINVAL; +- } +- if (nla_parse_nested(vf, IFLA_VF_MAX, le1, ifla_vf_policy)) { +- LLDPAD_ERR("%s: parsing of IFLA_VF_INFO failed\n", +- __func__); +- return -EINVAL; +- } +- +- if (vf[IFLA_VF_MAC]) { +- struct ifla_vf_mac *mac = RTA_DATA(vf[IFLA_VF_MAC]); +- +- memcpy(vsi->maclist->mac, mac->mac, ETH_ALEN); +- } +- +- if (vf[IFLA_VF_VLAN]) { +- struct ifla_vf_vlan *vlan = RTA_DATA(vf[IFLA_VF_VLAN]); +- +- vsi->maclist->vlan = vlan->vlan; +- } +- } +- return 0; +-} +- +-/* +- * Convert the SETLINK message into internal data structure. +- */ +-static int vdpnl_set(struct nlmsghdr *nlh, struct vdpnl_vsi *vsi) +-{ +- struct nlattr *tb[IFLA_MAX + 1]; +- struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh); +- int rc; +- +- if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), +- (struct nlattr **)&tb, IFLA_MAX, NULL)) { +- LLDPAD_ERR("%s: error parsing SETLINK request\n", __func__); +- return -EINVAL; +- } +- +- vsi->ifindex = ifinfo->ifi_index; +- if (tb[IFLA_IFNAME]) +- strncpy(vsi->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), +- sizeof vsi->ifname); +- else { +- if (!if_indextoname(ifinfo->ifi_index, vsi->ifname)) { +- LLDPAD_ERR("%s: can not find name for interface %i\n", +- __func__, ifinfo->ifi_index); +- return -ENXIO; +- } +- } +- vsi->req_pid = nlh->nlmsg_pid; +- vsi->req_seq = nlh->nlmsg_seq; +- rc = vdpnl_vfinfolist(tb[IFLA_VFINFO_LIST], vsi); +- if (!rc) { +- rc = vdpnl_vfports(tb[IFLA_VF_PORTS], vsi); +- if (!rc) +- vdpnl_show(vsi); +- } +- return rc; +-} +- +-/* +- * Return the error code (can be zero) to the sender. Assume buffer is +- * large enough to hold the information. +- * Construct the netlink response on the input buffer. +- */ +-static int vdpnl_error(int err, struct nlmsghdr *from, size_t len) +-{ +- struct nlmsgerr nlmsgerr; +- +- LLDPAD_DBG("%s: error %d\n", __func__, err); +- nlmsgerr.error = err; +- nlmsgerr.msg = *from; +- memset(from, 0, len); +- from->nlmsg_type = NLMSG_ERROR; +- from->nlmsg_seq = nlmsgerr.msg.nlmsg_seq; +- from->nlmsg_pid = nlmsgerr.msg.nlmsg_pid; +- from->nlmsg_flags = 0; +- from->nlmsg_len = NLMSG_SPACE(sizeof nlmsgerr); +- memcpy(NLMSG_DATA(from), &nlmsgerr, sizeof nlmsgerr); +- return from->nlmsg_len; +-} +- +-/* +- * Build the first part of the netlink reply message for status inquiry. +- * It contains the header and the ifinfo data structure. +- */ +-static void vdpnl_reply1(struct vdpnl_vsi *p, struct nlmsghdr *nlh, size_t len) +-{ +- struct nlmsghdr to; +- struct ifinfomsg ifinfo; +- +- to.nlmsg_type = NLMSG_DONE; +- to.nlmsg_seq = nlh->nlmsg_seq; +- to.nlmsg_pid = nlh->nlmsg_pid; +- to.nlmsg_flags = 0; +- to.nlmsg_len = NLMSG_SPACE(sizeof ifinfo); +- +- memset(&ifinfo, 0, sizeof ifinfo); +- ifinfo.ifi_index = p->ifindex; +- memset(nlh, 0, len); +- memcpy(nlh, &to, sizeof to); +- memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof ifinfo); +-} +- +-/* +- * Build the variable part of the netlink reply message for status inquiry. +- * It contains the UUID and the response field for the VSI profile. +- */ +-static void vdpnl_reply2(struct vdpnl_vsi *p, struct nlmsghdr *nlh) +-{ +- char instance[VDP_UUID_STRLEN + 2]; +- +- mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, sizeof p->vsi_uuid, +- p->vsi_uuid); +- vdp_uuid2str(p->vsi_uuid, instance, sizeof instance); +- LLDPAD_DBG("%s: IFLA_PORT_INSTANCE_UUID=%s\n", __func__, instance); +- mynla_put_u32(nlh, IFLA_PORT_VF, PORT_SELF_VF); +- LLDPAD_DBG("%s: IFLA_PORT_VF=%d\n", __func__, PORT_SELF_VF); +- if (p->response != VDP_RESPONSE_NO_RESPONSE) { +- mynla_put_u16(nlh, IFLA_PORT_RESPONSE, p->response); +- LLDPAD_DBG("%s: IFLA_PORT_RESPONSE=%d\n", __func__, +- p->response); +- } +-} +- +-/* +- * Extract the interface name and loop over all VSI profile entries. +- * Find UUID and response field for each active profile and construct a +- * netlink response message. +- * +- * Return message size. +- */ +-static int vdpnl_getlink(struct nlmsghdr *nlh, size_t len) +-{ +- struct vdpnl_vsi p; +- int i = 0, rc; +- struct nlattr *vf_ports, *vf_port; +- +- memset(&p, 0, sizeof p); +- rc = vdpnl_get(nlh, &p); +- if (rc) +- return vdpnl_error(rc, nlh, len); +- vdpnl_reply1(&p, nlh, len); +- vf_ports = mynla_nest_start(nlh, IFLA_VF_PORTS); +- vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); +- /* Iterate over all profiles */ +- do { +- rc = vdp_status(++i, &p); +- if (rc == 1) +- vdpnl_reply2(&p, nlh); +- if (rc == 0) { +- mynla_nest_end(nlh, vf_port); +- mynla_nest_end(nlh, vf_ports); +- } +- } while (rc == 1); +- if (rc < 0) +- return vdpnl_error(rc, nlh, len); +- LLDPAD_DBG("%s: message-size:%d\n", __func__, nlh->nlmsg_len); +- return nlh->nlmsg_len; +-} +- +-/* +- * Parse incoming command and create a data structure to store the VSI data. +- */ +-static int vdpnl_setlink(struct nlmsghdr *nlh, size_t len) +-{ +- int rc = -ENOMEM; +- struct vdpnl_mac mac; +- struct vdpnl_vsi p; +- +- memset(&p, 0, sizeof p); +- p.macsz = 1; +- p.maclist = &mac; +- rc = vdpnl_set(nlh, &p); +- if (!rc) +- rc = vdp22_query(p.ifname) ? vdp22_request(&p) +- : vdp_request(&p); +- return vdpnl_error(rc, nlh, len); +-} +- +-/* +- * Process the netlink message. Parameters are the socket, the message and +- * its length in bytes. +- * The message buffer 'buf' is used for parsing the incoming message. +- * After parsing and decoding, the outgoing message is stored in 'buf'. +- * +- * Returns: +- * < 0: Errno number when message parsing failed. +- * == 0: Message ok and no response. +- * > 0: Message ok and response returned in buf parameter. Returns bytes +- * of response. +- */ +-int vdpnl_recv(unsigned char *buf, size_t buflen) +-{ +- struct nlmsghdr *nlh = (struct nlmsghdr *)buf; +- +- LLDPAD_DBG("%s: buflen:%zd nlh.nl_pid:%d nlh_type:%d nlh_seq:%d " +- "nlh_len:%d\n", __func__, buflen, nlh->nlmsg_pid, +- nlh->nlmsg_type, nlh->nlmsg_seq, nlh->nlmsg_len); +- +- switch (nlh->nlmsg_type) { +- case RTM_SETLINK: +- return vdpnl_setlink(nlh, buflen); +- case RTM_GETLINK: +- return vdpnl_getlink(nlh, buflen); +- default: +- LLDPAD_ERR("%s: unknown type %d\n", __func__, nlh->nlmsg_type); +- } +- return -ENODEV; +-} +- +-/* +- * Add one entry in the list of MAC,VLAN pairs. +- */ +-static void add_pair(struct vdpnl_mac *mac, struct nlmsghdr *nlh) +-{ +- struct nlattr *vfinfo; +- struct ifla_vf_mac ifla_vf_mac = { +- .vf = PORT_SELF_VF, +- .mac = { 0, } +- }; +- struct ifla_vf_vlan ifla_vf_vlan = { +- .vf = PORT_SELF_VF, +- .vlan = mac->vlan, +- .qos = mac->qos +- }; +- +- vfinfo = mynla_nest_start(nlh, IFLA_VF_INFO); +- memcpy(ifla_vf_mac.mac, mac->mac, sizeof mac->mac); +- mynla_put(nlh, IFLA_VF_MAC, sizeof ifla_vf_mac, &ifla_vf_mac); +- mynla_put(nlh, IFLA_VF_VLAN, sizeof ifla_vf_vlan, &ifla_vf_vlan); +- mynla_nest_end(nlh, vfinfo); +-} +- +-/* +- * Walk along the MAC,VLAN ID list and add each entry into the message. +- */ +-static void add_mac_vlan(struct vdpnl_vsi *vsi, struct nlmsghdr *nlh) +-{ +- struct nlattr *vfinfolist; +- int i; +- +- vfinfolist = mynla_nest_start(nlh, IFLA_VFINFO_LIST); +- for (i = 0; i < vsi->macsz; ++i) +- add_pair(&vsi->maclist[i], nlh); +- mynla_nest_end(nlh, vfinfolist); +-} +- +-/* +- * Build an unsolicited netlink message to the VSI requestor. The originator +- * is the switch abondoning the VSI profile. +- * Assumes the messages fits into an 4KB buffer. +- * Returns the message size in bytes. +- */ +-int vdpnl_send(struct vdpnl_vsi *vsi) +-{ +- unsigned char buf[MAX_PAYLOAD]; +- struct nlmsghdr *nlh = (struct nlmsghdr *)buf; +- struct nlattr *vf_ports, *vf_port; +- struct ifinfomsg ifinfo; +- struct ifla_port_vsi portvsi; +- +- memset(buf, 0, sizeof buf); +- nlh->nlmsg_pid = getpid(); +- nlh->nlmsg_seq = vsi->req_seq; +- nlh->nlmsg_type = RTM_SETLINK; +- nlh->nlmsg_len = NLMSG_SPACE(sizeof ifinfo); +- +- memset(&ifinfo, 0, sizeof ifinfo); +- ifinfo.ifi_index = vsi->ifindex; +- memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof ifinfo); +- mynla_put(nlh, IFLA_IFNAME, 1 + strlen(vsi->ifname), vsi->ifname); +- +- add_mac_vlan(vsi, nlh); +- portvsi.vsi_mgr_id = vsi->vsi_mgrid; +- portvsi.vsi_type_id[0] = vsi->vsi_typeid & 0xff; +- portvsi.vsi_type_id[1] = (vsi->vsi_typeid >> 8) & 0xff; +- portvsi.vsi_type_id[2] = (vsi->vsi_typeid >> 16) & 0xff; +- portvsi.vsi_type_version = vsi->vsi_typeversion; +- vf_ports = mynla_nest_start(nlh, IFLA_VF_PORTS); +- vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); +- mynla_put(nlh, IFLA_PORT_VSI_TYPE, sizeof portvsi, &portvsi); +- mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsi->vsi_uuid); +- mynla_put_u32(nlh, IFLA_PORT_VF, PORT_SELF_VF); +- mynla_put_u16(nlh, IFLA_PORT_REQUEST, vsi->request); +- mynla_nest_end(nlh, vf_port); +- mynla_nest_end(nlh, vf_ports); +- vdpnl_show(vsi); +- LLDPAD_DBG("%s: nlh.nl_pid:%d nlh_type:%d nlh_seq:%d nlh_len:%d\n", +- __func__, nlh->nlmsg_pid, nlh->nlmsg_type, nlh->nlmsg_seq, +- nlh->nlmsg_len); +- return event_trigger(nlh, vsi->req_pid); +-} +diff --git a/qbg/vdp.c b/qbg/vdp.c +new file mode 100644 +index 0000000..074a1e1 +--- /dev/null ++++ b/qbg/vdp.c +@@ -0,0 +1,1916 @@ ++/****************************************************************************** ++ ++ Implementation of VDP according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Jens Osterkamp ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "lldp.h" ++#include "qbg_vdp.h" ++#include "qbg_vdpnl.h" ++#include "eloop.h" ++#include "lldp_evb.h" ++#include "messages.h" ++#include "config.h" ++#include "lldp_tlv.h" ++#include "qbg_vdp_cmds.h" ++#include "qbg_utils.h" ++#include "lldp_mand_clif.h" ++ ++/* Define Module id. Must match with value in lldp_vdp_clif.c */ ++#define LLDP_MOD_VDP02 ((LLDP_MOD_VDP << 8) | LLDP_VDP_SUBTYPE) ++ ++static const char * const vsi_responses[] = { ++ [VDP_RESPONSE_SUCCESS] = "success", ++ [VDP_RESPONSE_INVALID_FORMAT] = "invalid format", ++ [VDP_RESPONSE_INSUFF_RESOURCES] = "insufficient resources", ++ [VDP_RESPONSE_UNUSED_VTID] = "unused VTID", ++ [VDP_RESPONSE_VTID_VIOLATION] = "VTID violation", ++ [VDP_RESPONSE_VTID_VER_VIOLATION] = "VTID version violation", ++ [VDP_RESPONSE_OUT_OF_SYNC] = "out of sync", ++ [VDP_RESPONSE_UNKNOWN] = "unknown response", ++ [VDP_RESPONSE_NO_RESPONSE] = "no response", ++}; ++ ++const char * const vsi_states[] = { ++ [VSI_UNASSOCIATED] = "VSI_UNASSOCIATED", ++ [VSI_ASSOC_PROCESSING] = "VSI_ASSOC_PROCESSING", ++ [VSI_ASSOCIATED] = "VSI_ASSOCIATED", ++ [VSI_PREASSOC_PROCESSING] = "VSI_PREASSOC_PROCESSING", ++ [VSI_PREASSOCIATED] = "VSI_PREASSOCIATED", ++ [VSI_DEASSOC_PROCESSING] = "VSI_DEASSOC_PROCESSING", ++ [VSI_EXIT] = "VSI_EXIT", ++}; ++ ++int vdp_start_localchange_timer(struct vsi_profile *p); ++int vdp_remove_profile(struct vsi_profile *profile); ++int vdp_trigger(struct vsi_profile *profile); ++ ++void vdp_trace_profile(struct vsi_profile *p) ++{ ++ char instance[VDP_UUID_STRLEN + 2]; ++ struct mac_vlan *mac_vlan; ++ ++ vdp_uuid2str(p->instance, instance, sizeof(instance)); ++ ++ LLDPAD_DBG("profile:%p mode:%d response:%d state:%d (%s) no_nlmsg:%d" ++ " txmit:%i" ++ " mgrid:%d id:%d(%#x) version:%d %s format:%d entries:%d\n", ++ p, p->mode, p->response, p->state, vsi_states[p->state], ++ p->no_nlmsg, p->txmit, ++ p->mgrid, p->id, p->id, p->version, instance, p->format, ++ p->entries); ++ LIST_FOREACH(mac_vlan, &p->macvid_head, entry) { ++ char macbuf[MAC_ADDR_STRLEN + 1]; ++ ++ mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); ++ LLDPAD_DBG("profile:%p mac:%s vlan:%d qos:%d pid:%d seq:%d\n", ++ p, macbuf, mac_vlan->vlan, mac_vlan->qos, ++ mac_vlan->req_pid, mac_vlan->req_seq); ++ } ++} ++ ++struct vsi_profile *vdp_alloc_profile() ++{ ++ struct vsi_profile *prof; ++ ++ prof = calloc(1, sizeof *prof); ++ if (prof) ++ LIST_INIT(&prof->macvid_head); ++ return prof; ++} ++ ++/* ++ * vdp_remove_macvlan - remove all mac/vlan pairs in the profile ++ * @profile: profile to remove ++ * ++ * Remove all allocated pairs on the profile. ++ */ ++static void vdp_remove_macvlan(struct vsi_profile *profile) ++{ ++ struct mac_vlan *p; ++ ++ while ((p = LIST_FIRST(&profile->macvid_head))) { ++ LIST_REMOVE(p, entry); ++ free(p); ++ } ++} ++ ++void vdp_delete_profile(struct vsi_profile *prof) ++{ ++ vdp_remove_macvlan(prof); ++ free(prof); ++} ++ ++/* vdp_profile_equal - checks for equality of 2 profiles ++ * @p1: profile 1 ++ * @p2: profile 2 ++ * ++ * returns true if equal, false if not ++ * ++ * compares mgrid, id, version, instance 2 vsi profiles to find ++ * out if they are equal. ++ */ ++static bool vdp_profile_equal(struct vsi_profile *p1, struct vsi_profile *p2) ++{ ++ if (p1->mgrid != p2->mgrid) ++ return false; ++ ++ if (p1->id != p2->id) ++ return false; ++ ++ if (p1->version != p2->version) ++ return false; ++ ++ if (memcmp(p1->instance, p2->instance, 16)) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * vdp_find_profile - Find a profile in the list of profiles already allocated ++ * ++ * Returns pointer to already allocated profile in list, 0 if not. ++ */ ++ ++struct vsi_profile *vdp_find_profile(struct vdp_data *vd, ++ struct vsi_profile *thisone) ++{ ++ struct vsi_profile *p; ++ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ if (vdp_profile_equal(p, thisone)) ++ return p; ++ } ++ return 0; ++} ++ ++/* vdp_data - searches vdp_data in the list of modules for this port ++ * @ifname: interface name to search for ++ * ++ * returns vdp_data on success, NULL on error ++ * ++ * searches the list of user_data for the VDP module user_data. ++ */ ++struct vdp_data *vdp_data(char *ifname) ++{ ++ struct vdp_user_data *ud; ++ struct vdp_data *vd = NULL; ++ ++ ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP02); ++ if (ud) { ++ LIST_FOREACH(vd, &ud->head, entry) { ++ if (!strncmp(ifname, vd->ifname, IFNAMSIZ)) ++ return vd; ++ } ++ } ++ return NULL; ++} ++ ++/* vdp_free_tlv - free tlv in vdp_data ++ * @vd: vdp_data ++ * ++ * no return value ++ * ++ * frees up tlv in vdp_data. used in vdp_free_data. ++ */ ++static void vdp_free_tlv(struct vdp_data *vd) ++{ ++ if (vd) { ++ FREE_UNPKD_TLV(vd, vdp); ++ } ++} ++ ++/* vdp_free_data - frees up vdp data ++ * @ud: user data structure ++ * ++ * no return value ++ * ++ * removes vd_structure from the user_data list. frees up tlv in vdp_data. ++ * used in vdp_unregister. ++ */ ++static void vdp_free_data(struct vdp_user_data *ud) ++{ ++ struct vdp_data *vd; ++ if (ud) { ++ while (!LIST_EMPTY(&ud->head)) { ++ vd = LIST_FIRST(&ud->head); ++ LIST_REMOVE(vd, entry); ++ vdp_free_tlv(vd); ++ free(vd); ++ } ++ } ++} ++ ++/* vdp_response2str - map response to string ++ * @response: response received ++ * ++ * no return value ++ * ++ * maps VDP response received for a profile to human readable string for ++ * printing. ++ */ ++const char *vdp_response2str(int response) ++{ ++ if ((response >= VDP_RESPONSE_SUCCESS) && ++ (response <= VDP_RESPONSE_OUT_OF_SYNC)) ++ return vsi_responses[response]; ++ ++ if (response == VDP_RESPONSE_NO_RESPONSE) ++ return vsi_responses[VDP_RESPONSE_NO_RESPONSE]; ++ ++ return vsi_responses[VDP_RESPONSE_UNKNOWN]; ++} ++ ++/* vdp_ack_profiles - clear ackReceived for all profiles with seqnr ++ * @vd: vd for the interface ++ * @seqnr: seqnr the ack has been received with ++ * ++ * no return value ++ * ++ * clear the ackReceived for all profiles which have been sent out with ++ * the seqnr that we now have received the ecp ack for. ++ */ ++void vdp_ack_profiles(struct vdp_data *vd, int seqnr) ++{ ++ struct vsi_profile *p; ++ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ if (p->seqnr == seqnr) { ++ p->ackReceived = false; ++ p->txmit = true; ++ } ++ } ++ ++} ++ ++/* vdp_vsis - find out number of VSIs for this interface ++ * @ifname: interfac name ++ * ++ * returns the number of VSIs ++ * ++ * walk through the list of VSIs and return the count. ++ */ ++int vdp_vsis(char *ifname) ++{ ++ struct vdp_data *vd; ++ struct vsi_profile *p; ++ int count = 0; ++ ++ vd = vdp_data(ifname); ++ ++ if (!vd) ++ return 0; ++ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ count++; ++ } ++ ++ return count; ++} ++ ++/* vdp_vsis_pending - check for pending VSIs ++ * @vd: vdp data for the interface ++ * ++ * returns the number of VSIs found ++ * ++ * walk through the list of VSIs and return the count. ++ */ ++int vdp_vsis_pending(struct vdp_data *vd) ++{ ++ struct vsi_profile *p; ++ int count = 0; ++ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ if (p->localChange && (p->txmit == false)) ++ count++; ++ } ++ ++ return count; ++} ++ ++/* vdp_somethingChangedLocal - set flag if profile has changed ++ * @profile: profile to set the flag for ++ * @flag: set the flag to true or false ++ * ++ * no return value ++ * ++ * set the localChange flag with a mode to indicate a profile has changed. ++ * used next time when a ecpdu with profiles is sent out. ++ */ ++void vdp_somethingChangedLocal(struct vsi_profile *profile, bool flag) ++{ ++ LLDPAD_DBG("%s: setting profile->localChange to %s\n", ++ __func__, (flag == true) ? "true" : "false"); ++ ++ profile->localChange = flag; ++ ++ if (flag == true) ++ vdp_start_localchange_timer(profile); ++} ++ ++/* vdp_keepaliveTimer_expired - checks for expired ack timer ++ * @profile: profile to be checked ++ * ++ * returns true or false ++ * ++ * returns value of profile->keepaliveTimerExpired, true if ack timer has ++ * expired, * false otherwise. ++ */ ++static bool vdp_keepaliveTimer_expired(struct vsi_profile *profile) ++{ ++ return (profile->keepaliveTimer == 0); ++} ++ ++/* vdp_ackTimer_expired - checks for expired ack timer ++ * @profile: profile to be checked ++ * ++ * returns true or false ++ * ++ * returns value of profile->ackTimerExpired, true if ack timer has expired, ++ * false otherwise. ++ */ ++static bool vdp_ackTimer_expired(struct vsi_profile *profile) ++{ ++ return (profile->ackTimer == 0); ++} ++ ++/* vdp_localchange_handler - triggers in case of vdp_ack or on vdp ++ * localchange ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here ++ * ++ * no return value ++ * ++ * called from vdp_somethingchangedlocal or vdp_ack_profiles when a change is ++ * pending. Calls the VDP station state machine. This detour is taken ++ * to not having to call the vdp code from the ecp state machine. Instead, we ++ * return to the event loop, giving other code a chance to do work. ++ */ ++void vdp_localchange_handler(UNUSED void *eloop_data, void *user_ctx) ++{ ++ struct vsi_profile *p; ++ ++ p = (struct vsi_profile *) user_ctx; ++ ++ if ((p->ackReceived) || (p->localChange)) { ++ LLDPAD_DBG("%s: p->localChange %i p->ackReceived %i\n", ++ __func__, p->localChange, p->ackReceived); ++ vdp_vsi_sm_station(p); ++ } ++} ++ ++/* ++ * vdp_stop - cancel the VDP localchange timer ++ * ++ * returns 0 on success, -1 on error ++ * ++ * cancels the VPP localchange timer when a profile has been deleted. ++ */ ++int vdp_stop_localchange_timer(struct vsi_profile *p) ++{ ++ return eloop_cancel_timeout(vdp_localchange_handler, NULL, (void *) p); ++} ++ ++/* vdp_start_localchange_timer - starts the VDP localchange timer ++ * @vd: vdp_data for the interface ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the VPP localchange timer when a localchange has been signaled from ++ * the VDP state machine. ++ */ ++int vdp_start_localchange_timer(struct vsi_profile *p) ++{ ++ unsigned int usecs; ++ ++ usecs = VDP_LOCALCHANGE_TIMEOUT; ++ ++ return eloop_register_timeout(0, usecs, vdp_localchange_handler, NULL, ++ (void *) p); ++} ++ ++/* vdp_ack_timeout_handler - handles the ack timer expiry ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here ++ * ++ * no return value ++ * ++ * called when the VDP ack timer for a profile has expired. ++ * Calls the VDP station state machine for the profile. ++ */ ++void vdp_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) ++{ ++ struct vsi_profile *p = (struct vsi_profile *) user_ctx; ++ ++ if (p->ackTimer > 0) ++ p->ackTimer -= VDP_ACK_TIMER_DEFAULT; ++ ++ if (vdp_ackTimer_expired(p)) { ++ LLDPAD_DBG("%s: profile %#02x vdp_ackTimer_expired %i" ++ " p->ackReceived %i\n", __func__, p->instance[15], ++ vdp_ackTimer_expired(p), p->ackReceived); ++ vdp_vsi_sm_station(p); ++ } ++} ++ ++/* vdp_start_ack_timer - starts the VDP profile ack timer ++ * @profile: vsi_profile ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the VDP profile ack timer when a profile has been handed to ecp for ++ * transmission. ++ */ ++static int vdp_start_ackTimer(struct vsi_profile *profile) ++{ ++ unsigned int usecs; ++ ++ usecs = VDP_ACK_TIMER_DEFAULT; ++ ++ profile->ackTimer = VDP_ACK_TIMER_DEFAULT; ++ ++ LLDPAD_DBG("%s: %s starting ack timer for %#02x (%i)\n", ++ __func__, profile->port->ifname, ++ profile->instance[15], profile->ackTimer); ++ ++ return eloop_register_timeout(0, usecs, vdp_ack_timeout_handler, NULL, ++ (void *)profile); ++} ++ ++/* vdp_stop_ackTimer - stops the VDP profile ack timer ++ * @vd: vdp_data for the interface ++ * ++ * returns the number of removed handlers ++ * ++ * stops the VDP tck imer. Used e.g. when the host interface goes down. ++ */ ++static int vdp_stop_ackTimer(struct vsi_profile *profile) ++{ ++ LLDPAD_DBG("%s: %s stopping ack timer for %#02x (%i)\n", __func__, ++ profile->port->ifname, profile->instance[15], ++ profile->ackTimer); ++ ++ return eloop_cancel_timeout(vdp_ack_timeout_handler, NULL, ++ (void *)profile); ++} ++ ++/* vdp_keepalive_timeout_handler - handles the keepalive timer expiry ++ * @eloop_data: data structure of event loop ++ * @user_ctx: user context, vdp_data here ++ * ++ * no return value ++ * ++ * called when the VDP keepalive timer for a profile has expired. ++ * Calls the VDP station state machine for the profile. ++ */ ++void vdp_keepalive_timeout_handler(UNUSED void *eloop_data, void *user_ctx) ++{ ++ struct vsi_profile *p = (struct vsi_profile *) user_ctx; ++ ++ if (p->keepaliveTimer > 0) ++ p->keepaliveTimer -= VDP_KEEPALIVE_TIMER_DEFAULT; ++ ++ if (vdp_keepaliveTimer_expired(p)) { ++ LLDPAD_DBG("%s: profile %#02x vdp_keepaliveTimer_expired %i" ++ " p->ackReceived %i p->ackReceived %i\n", __func__, ++ p->instance[15], vdp_keepaliveTimer_expired(p), ++ p->ackReceived, p->ackReceived); ++ vdp_vsi_sm_station(p); ++ } ++} ++ ++/* vdp_start_keepalive_timer - starts the VDP profile keepalive timer ++ * @vd: vdp_data for the interface ++ * ++ * returns 0 on success, -1 on error ++ * ++ * starts the VDP profile keepalive timer when a profile has been handed to ++ * ecp for transmission. ++ */ ++static int vdp_start_keepaliveTimer(struct vsi_profile *profile) ++{ ++ unsigned int usecs; ++ ++ usecs = VDP_KEEPALIVE_TIMER_DEFAULT; ++ ++ profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; ++ ++ LLDPAD_DBG("%s: %s starting keepalive timer for %#02x (%i)\n", ++ __func__, profile->port->ifname, profile->instance[15], ++ profile->keepaliveTimer); ++ ++ return eloop_register_timeout(0, usecs, vdp_keepalive_timeout_handler, ++ NULL, (void *) profile); ++} ++ ++/* vdp_stop_keepalive_timer - stops the VDP profile keepalive timer ++ * @vd: vdp_data for the interface ++ * ++ * returns the number of removed handlers ++ * ++ * stops the VDP tck imer. Used e.g. when the host interface goes down. ++ */ ++static int vdp_stop_keepaliveTimer(struct vsi_profile *profile) ++{ ++ profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_STOPPED; ++ ++ LLDPAD_DBG("%s: %s stopping keepalive timer for %#02x (%i)\n", ++ __func__, profile->port->ifname, ++ profile->instance[15], profile->keepaliveTimer); ++ ++ return eloop_cancel_timeout(vdp_keepalive_timeout_handler, NULL, ++ (void *) profile); ++} ++ ++static bool vdp_vsi_negative_response(struct vsi_profile *profile) ++{ ++ if ((profile->response > 0) && (profile->response < 255)) ++ return true; ++ else ++ return false; ++} ++ ++/* vdp_vsi_change_station_state - changes the VDP station sm state ++ * @profile: profile to process ++ * @newstate: new state for the sm ++ * ++ * no return value ++ * ++ * actually changes the state of the profile ++ */ ++void vdp_vsi_change_station_state(struct vsi_profile *profile, u8 newstate) ++{ ++ switch(newstate) { ++ case VSI_UNASSOCIATED: ++ break; ++ case VSI_ASSOC_PROCESSING: ++ assert((profile->state == VSI_PREASSOCIATED) || ++ (profile->state == VSI_ASSOCIATED) || ++ (profile->state == VSI_UNASSOCIATED)); ++ break; ++ case VSI_ASSOCIATED: ++ assert((profile->state == VSI_ASSOC_PROCESSING) || ++ (profile->state == VSI_ASSOCIATED)); ++ break; ++ case VSI_PREASSOC_PROCESSING: ++ assert((profile->state == VSI_PREASSOCIATED) || ++ (profile->state == VSI_ASSOCIATED) || ++ (profile->state == VSI_UNASSOCIATED)); ++ break; ++ case VSI_PREASSOCIATED: ++ assert((profile->state == VSI_PREASSOC_PROCESSING) || ++ (profile->state == VSI_PREASSOCIATED)); ++ break; ++ case VSI_DEASSOC_PROCESSING: ++ assert((profile->state == VSI_PREASSOCIATED) || ++ (profile->state == VSI_UNASSOCIATED) || ++ (profile->state == VSI_ASSOCIATED)); ++ break; ++ case VSI_EXIT: ++ assert((profile->state == VSI_ASSOC_PROCESSING) || ++ (profile->state == VSI_PREASSOC_PROCESSING) || ++ (profile->state == VSI_DEASSOC_PROCESSING) || ++ (profile->state == VSI_PREASSOCIATED) || ++ (profile->state == VSI_ASSOCIATED)); ++ break; ++ default: ++ LLDPAD_ERR("ERROR: The VDP station State Machine is broken\n"); ++ break; ++ } ++ ++ LLDPAD_DBG("%s: %s state change %s -> %s\n", __func__, ++ profile->port->ifname, vsi_states[profile->state], ++ vsi_states[newstate]); ++ ++ profile->state = newstate; ++} ++ ++/* vdp_vsi_set_station_state - sets the vdp sm station state ++ * @profile: profile to process ++ * ++ * returns true or false ++ * ++ * switches the state machine to the next state depending on the input ++ * variables. returns true or false depending on wether the state machine ++ * can be run again with the new state or can stop at the current state. ++ */ ++static bool vdp_vsi_set_station_state(struct vsi_profile *profile) ++{ ++ switch(profile->state) { ++ case VSI_UNASSOCIATED: ++ if ((profile->mode == VDP_MODE_PREASSOCIATE) || ++ (profile->mode == VDP_MODE_PREASSOCIATE_WITH_RR)) { ++ vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); ++ vdp_somethingChangedLocal(profile, true); ++ return true; ++ } else if (profile->mode == VDP_MODE_ASSOCIATE) { ++ vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); ++ vdp_somethingChangedLocal(profile, true); ++ return true; ++ } else if (profile->mode == VDP_MODE_DEASSOCIATE) { ++ vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); ++ vdp_somethingChangedLocal(profile, true); ++ return true; ++ } ++ return false; ++ case VSI_ASSOC_PROCESSING: ++ if (profile->ackReceived) { ++ if (profile->response == 0) ++ vdp_vsi_change_station_state(profile, VSI_ASSOCIATED); ++ else ++ vdp_vsi_change_station_state(profile, VSI_EXIT); ++ return true; ++ } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) { ++ vdp_vsi_change_station_state(profile, VSI_EXIT); ++ return true; ++ } ++ return false; ++ case VSI_ASSOCIATED: ++ if (profile->mode == VDP_MODE_PREASSOCIATE) { ++ vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); ++ return true; ++ } else if (profile->mode == VDP_MODE_DEASSOCIATE) { ++ vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); ++ return true; ++ } else if (vdp_vsi_negative_response(profile)) { ++ vdp_vsi_change_station_state(profile, VSI_EXIT); ++ return true; ++ } else if (vdp_keepaliveTimer_expired(profile)) { ++ vdp_stop_keepaliveTimer(profile); ++ vdp_somethingChangedLocal(profile, true); ++ vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); ++ return true; ++ } ++ return false; ++ case VSI_PREASSOC_PROCESSING: ++ LLDPAD_DBG("%s: profile->ackReceived %i, vdp_ackTimer %i\n", ++ __func__, profile->ackReceived, profile->ackTimer); ++ if (profile->ackReceived) { ++ if (profile->response == 0) ++ vdp_vsi_change_station_state(profile, VSI_PREASSOCIATED); ++ else ++ vdp_vsi_change_station_state(profile, VSI_EXIT); ++ return true; ++ } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) { ++ vdp_vsi_change_station_state(profile, VSI_EXIT); ++ return true; ++ } ++ return false; ++ case VSI_PREASSOCIATED: ++ if (profile->mode == VDP_MODE_ASSOCIATE) { ++ vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); ++ return true; ++ } else if (profile->mode == VDP_MODE_DEASSOCIATE) { ++ vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); ++ return true; ++ } else if (vdp_keepaliveTimer_expired(profile)) { ++ vdp_stop_keepaliveTimer(profile); ++ vdp_somethingChangedLocal(profile, true); ++ vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); ++ return true; ++ } ++ return false; ++ case VSI_DEASSOC_PROCESSING: ++ if ((profile->ackReceived) || vdp_ackTimer_expired(profile) || ++ profile->remoteChange) { ++ vdp_vsi_change_station_state(profile, VSI_EXIT); ++ return true; ++ } ++ return false; ++ case VSI_EXIT: ++ return false; ++ default: ++ LLDPAD_ERR("%s: VSI state machine in invalid state %d\n", ++ profile->port->ifname, profile->state); ++ return false; ++ } ++} ++ ++/* vdp_vsi_sm_station - state machine for vdp station role ++ * @profile: profile for which the state is processed ++ * ++ * no return value ++ * ++ * runs the state machine for the station role of VDP. ++ */ ++void vdp_vsi_sm_station(struct vsi_profile *profile) ++{ ++ struct vdp_data *vd = vdp_data(profile->port->ifname); ++ int bye = 0; ++ ++ vdp_vsi_set_station_state(profile); ++ do { ++ LLDPAD_DBG("%s: %s station for %#02x - %s\n", ++ __func__, profile->port->ifname, ++ profile->instance[15], vsi_states[profile->state]); ++ ++ switch(profile->state) { ++ case VSI_UNASSOCIATED: ++ break; ++ case VSI_ASSOC_PROCESSING: ++ vdp_stop_keepaliveTimer(profile); ++ profile->response = VDP_RESPONSE_NO_RESPONSE; ++ if (profile->localChange) { ++ ecp_somethingChangedLocal(vd, true); ++ profile->ackReceived = false; ++ vdp_start_ackTimer(profile); ++ } ++ break; ++ case VSI_ASSOCIATED: ++ profile->ackReceived = false; ++ vdp_somethingChangedLocal(profile, false); ++ vdp_stop_ackTimer(profile); ++ vdp_start_keepaliveTimer(profile); ++ break; ++ case VSI_PREASSOC_PROCESSING: ++ vdp_stop_keepaliveTimer(profile); ++ profile->response = VDP_RESPONSE_NO_RESPONSE; ++ if (profile->localChange) { ++ profile->ackReceived = false; ++ ecp_somethingChangedLocal(vd, true); ++ vdp_start_ackTimer(profile); ++ } ++ break; ++ case VSI_PREASSOCIATED: ++ profile->ackReceived = false; ++ vdp_somethingChangedLocal(profile, false); ++ vdp_stop_ackTimer(profile); ++ vdp_start_keepaliveTimer(profile); ++ break; ++ case VSI_DEASSOC_PROCESSING: ++ profile->ackReceived = false; ++ vdp_stop_keepaliveTimer(profile); ++ profile->response = VDP_RESPONSE_NO_RESPONSE; ++ if (profile->localChange) { ++ profile->ackReceived = false; ++ ecp_somethingChangedLocal(vd, true); ++ vdp_start_ackTimer(profile); ++ } ++ break; ++ case VSI_EXIT: ++ if (profile->no_nlmsg && !profile->ackReceived && ++ vdp_ackTimer_expired(profile)) ++ bye = 1; ++ vdp_stop_ackTimer(profile); ++ vdp_stop_keepaliveTimer(profile); ++ vdp_stop_localchange_timer(profile); ++ if (bye) ++ vdp_remove_profile(profile); ++ else ++ vdp_trigger(profile); ++ break; ++ default: ++ LLDPAD_ERR("%s: ERROR VSI state machine in invalid state %d\n", ++ vd->ifname, profile->state); ++ } ++ } while (vdp_vsi_set_station_state(profile) == true); ++ ++} ++ ++/* vdp_advance_sm - advance state machine after update from switch ++ * ++ * no return value ++ */ ++void vdp_advance_sm(struct vdp_data *vd) ++{ ++ struct vsi_profile *p; ++ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ LLDPAD_DBG("%s: %s station for %#02x - %s ackReceived %i\n", ++ __func__, p->port->ifname, ++ p->instance[15], vsi_states[p->state], ++ p->ackReceived); ++ if (p->ackReceived) { ++ vdp_vsi_sm_station(p); ++ p->ackReceived = false; ++ } ++ } ++} ++ ++/* vdp_vsi_change_bridge_state - changes the VDP bridge sm state ++ * @profile: profile to process ++ * @newstate: new state for the sm ++ * ++ * no return value ++ * ++ * actually changes the state of the profile ++ */ ++static void vdp_vsi_change_bridge_state(struct vsi_profile *profile, ++ u8 newstate) ++{ ++ switch(newstate) { ++ case VSI_UNASSOCIATED: ++ break; ++ case VSI_ASSOC_PROCESSING: ++ assert((profile->state == VSI_UNASSOCIATED) || ++ (profile->state == VSI_PREASSOCIATED) || ++ (profile->state == VSI_ASSOCIATED)); ++ break; ++ case VSI_ASSOCIATED: ++ assert(profile->state == VSI_ASSOC_PROCESSING); ++ break; ++ case VSI_PREASSOC_PROCESSING: ++ assert((profile->state == VSI_UNASSOCIATED) || ++ (profile->state == VSI_PREASSOCIATED) || ++ (profile->state == VSI_ASSOCIATED)); ++ break; ++ case VSI_PREASSOCIATED: ++ assert(profile->state == VSI_PREASSOC_PROCESSING); ++ break; ++ case VSI_DEASSOC_PROCESSING: ++ assert((profile->state == VSI_UNASSOCIATED) || ++ (profile->state == VSI_PREASSOCIATED) || ++ (profile->state == VSI_ASSOCIATED)); ++ break; ++ case VSI_EXIT: ++ assert((profile->state == VSI_DEASSOC_PROCESSING) || ++ (profile->state == VSI_PREASSOC_PROCESSING) || ++ (profile->state == VSI_ASSOC_PROCESSING)); ++ break; ++ default: ++ LLDPAD_ERR("ERROR: The VDP bridge State Machine is broken\n"); ++ break; ++ } ++ profile->state = newstate; ++} ++ ++/* vdp_vsi_set_bridge_state - sets the vdp sm bridge state ++ * @profile: profile to process ++ * ++ * returns true or false ++ * ++ * switches the state machine to the next state depending on the input ++ * variables. returns true or false depending on wether the state machine ++ * can be run again with the new state or can stop at the current state. ++ */ ++static bool vdp_vsi_set_bridge_state(struct vsi_profile *profile) ++{ ++ switch(profile->state) { ++ case VSI_UNASSOCIATED: ++ if ((profile->mode == VDP_MODE_DEASSOCIATE)) /* || (INACTIVE)) */ { ++ vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); ++ return true; ++ } else if (profile->mode == VDP_MODE_ASSOCIATE) { ++ vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); ++ return true; ++ } else if (profile->mode == VDP_MODE_PREASSOCIATE) { ++ vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); ++ return true; ++ } ++ return false; ++ case VSI_ASSOC_PROCESSING: ++ /* TODO: handle error case ++ if (!vsiError) || ++ (vsiError && vsiState == Assoc) { ++ */ ++ if (profile->mode == VDP_MODE_ASSOCIATE) { ++ vdp_vsi_change_bridge_state(profile, VSI_ASSOCIATED); ++ return true; ++ } ++ return false; ++ case VSI_ASSOCIATED: ++ if (profile->mode == VDP_MODE_ASSOCIATE) /* || ( INACTIVE )*/ { ++ vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); ++ return true; ++ } else if (profile->mode == VDP_MODE_PREASSOCIATE) { ++ vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); ++ return true; ++ } else if (profile->mode == VDP_MODE_ASSOCIATE) { ++ vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); ++ return true; ++ } ++ return false; ++ case VSI_PREASSOC_PROCESSING: ++ if (profile->response != VDP_RESPONSE_SUCCESS) { ++ vdp_vsi_change_bridge_state(profile, VSI_EXIT); ++ return true; ++ } ++ vdp_vsi_change_bridge_state(profile, VSI_PREASSOCIATED); ++ return false; ++ case VSI_PREASSOCIATED: ++ if (profile->mode == VDP_MODE_ASSOCIATE) { ++ vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); ++ return true; ++ } else if (profile->mode == VDP_MODE_DEASSOCIATE ) { ++ vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); ++ return true; ++ } else if (profile->mode == VDP_MODE_PREASSOCIATE ) { ++ vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); ++ return true; ++ } ++ return false; ++ case VSI_DEASSOC_PROCESSING: ++ vdp_vsi_change_bridge_state(profile, VSI_EXIT); ++ return false; ++ case VSI_EXIT: ++ return false; ++ default: ++ LLDPAD_ERR("%s: ERROR VSI state machine (bridge) in invalid state %d\n", ++ profile->port->ifname, profile->state); ++ return false; ++ } ++} ++ ++/* vdp_vsi_sm_bridge - state machine for vdp bridge role ++ * @profile: profile for which the state is processed ++ * ++ * no return value ++ * ++ * runs the state machine for the bridge role of VDP. ++ */ ++static void vdp_vsi_sm_bridge(struct vsi_profile *profile) ++{ ++ struct vdp_data *vd = vdp_data(profile->port->ifname); ++ ++ vdp_vsi_set_bridge_state(profile); ++ do { ++ LLDPAD_DBG("%s: %s bridge - %s\n", __func__, ++ profile->port->ifname, vsi_states[profile->state]); ++ switch(profile->state) { ++ case VSI_UNASSOCIATED: ++ break; ++ case VSI_ASSOC_PROCESSING: ++ /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate); ++ * if (vsiError) ++ * txTLV(Assoc NACK) ++ * else ++ * txTLV(Assoc ACK) ++ */ ++ break; ++ case VSI_ASSOCIATED: ++ break; ++ case VSI_PREASSOC_PROCESSING: ++ /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate); ++ * if (vsiError) ++ * txTLV(PreAssoc NACK) ++ * else ++ * txTLV(PreAssoc ACK) ++ */ ++ /* for now, we always succeed */ ++ profile->response = VDP_RESPONSE_SUCCESS; ++ ecp_rx_send_ack_frame(vd); ++ break; ++ case VSI_PREASSOCIATED: ++ LLDPAD_DBG("%s: %s\n", __func__, profile->port->ifname); ++ break; ++ case VSI_DEASSOC_PROCESSING: ++ /* TODO: txTLV(DeAssoc ACK) */ ++ break; ++ case VSI_EXIT: ++ vdp_remove_profile(profile); ++ break; ++ default: ++ LLDPAD_ERR("%s: ERROR VSI state machine in invalid state %d\n", ++ vd->ifname, profile->state); ++ } ++ } while (vdp_vsi_set_bridge_state(profile) == true); ++ ++} ++ ++/* ++ * vdp_validate_tlv - validates vsi tlvs ++ * @vdp: decoded vsi tlv ++ * ++ * Returns 0 on success, 1 on error ++ * ++ * checks the contents of an already decoded vsi tlv for inconsistencies ++ */ ++static int vdp_validate_tlv(struct tlv_info_vdp *vdp, struct unpacked_tlv *tlv) ++{ ++ int pairs = (tlv->length - sizeof *vdp) / sizeof(struct mac_vlan_p); ++ ++ if (ntoh24(vdp->oui) != OUI_IEEE_8021Qbg) { ++ LLDPAD_DBG("vdp->oui %#06x\n", ntoh24(vdp->oui)); ++ goto out_err; ++ } ++ ++ if (vdp->sub != LLDP_VDP_SUBTYPE) { ++ LLDPAD_DBG("vdp->sub %#02x\n", vdp->sub); ++ goto out_err; ++ } ++ ++ if (vdp->mode > VDP_MODE_DEASSOCIATE) { ++ LLDPAD_DBG("unknown mode %#02x in vsi tlv\n", vdp->mode); ++ goto out_err; ++ } ++ ++ if (vdp->response > VDP_RESPONSE_OUT_OF_SYNC) { ++ LLDPAD_DBG("unknown response %#02x\n", vdp->response); ++ goto out_err; ++ } ++ ++ if (vdp->format != VDP_FILTER_INFO_FORMAT_MACVID) { ++ LLDPAD_DBG("unknown format %#02x in vsi tlv\n", vdp->format); ++ goto out_err; ++ } ++ ++ if (ntohs(vdp->entries) < 1) { ++ LLDPAD_DBG("invalid # of entries %#02x in vsi tlv\n", ++ ntohs(vdp->entries)); ++ goto out_err; ++ } ++ ++ /* Check for number of entries of MAC,VLAN pairs */ ++ if (ntohs(vdp->entries) != pairs) { ++ LLDPAD_DBG("mismatching # of entries %#x/%#x in vsi tlv\n", ++ ntohs(vdp->entries), pairs); ++ goto out_err; ++ } ++ return 0; ++ ++out_err: ++ return 1; ++} ++ ++/* ++ * Create a VSI profile structure from switch response. ++ */ ++static void make_profile(struct vsi_profile *new, struct tlv_info_vdp *vdp, ++ struct unpacked_tlv *tlv) ++{ ++ int i; ++ u8 *pos = tlv->info + sizeof *vdp; ++ ++ new->mode = vdp->mode; ++ new->response = vdp->response; ++ new->mgrid = vdp->mgrid; ++ new->id = ntoh24(vdp->id); ++ new->version = vdp->version; ++ memcpy(&new->instance, &vdp->instance, sizeof new->instance); ++ new->format = vdp->format; ++ new->entries = ntohs(vdp->entries); ++ LLDPAD_DBG("%s: MAC/VLAN filter info format %u, # of entries %u\n", ++ __func__, new->format, new->entries); ++ ++ /* Add MAC,VLAN to list */ ++ for (i = 0; i < new->entries; ++i) { ++ struct mac_vlan *mac_vlan = calloc(1, sizeof(struct mac_vlan)); ++ u16 vlan; ++ char macbuf[MAC_ADDR_STRLEN + 1]; ++ ++ if (!mac_vlan) { ++ new->entries = i; ++ return; ++ } ++ memcpy(&mac_vlan->mac, pos, ETH_ALEN); ++ pos += ETH_ALEN; ++ mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); ++ memcpy(&vlan, pos, 2); ++ pos += 2; ++ mac_vlan->vlan = ntohs(vlan); ++ LLDPAD_DBG("%s: mac %s vlan %d\n", __func__, macbuf, ++ mac_vlan->vlan); ++ LIST_INSERT_HEAD(&new->macvid_head, mac_vlan, entry); ++ } ++} ++ ++/* ++ * vdp_indicate - receive VSI TLVs from ECP ++ * @port: the port on which the tlv was received ++ * @tlv: the unpacked tlv to receive ++ * ++ * Returns 0 on success ++ * ++ * receives a vsi tlv and creates a profile. Take appropriate action ++ * depending on the role of the (receive) port ++ */ ++int vdp_indicate(struct vdp_data *vd, struct unpacked_tlv *tlv) ++{ ++ struct tlv_info_vdp vdp; ++ struct vsi_profile *p, *profile; ++ struct port *port = port_find_by_ifindex(get_ifidx(vd->ifname)); ++ ++ LLDPAD_DBG("%s: indicating vdp of length %u (%zu) for %s\n", ++ __func__, tlv->length, sizeof(struct tlv_info_vdp), ++ vd->ifname); ++ ++ if (!port) { ++ LLDPAD_ERR("%s: port not found for %s\n", __func__, ++ vd->ifname); ++ goto out_err; ++ } ++ ++ memset(&vdp, 0, sizeof vdp); ++ /* copy only vdp header w/o list of mac/vlan/groupid pairs */ ++ memcpy(&vdp, tlv->info, sizeof vdp); ++ ++ if (vdp_validate_tlv(&vdp, tlv)) { ++ LLDPAD_ERR("%s: invalid TLV received\n", __func__); ++ goto out_err; ++ } ++ ++ profile = vdp_alloc_profile(); ++ if (!profile) { ++ LLDPAD_ERR("%s: unable to allocate profile\n", __func__); ++ goto out_err; ++ } ++ make_profile(profile, &vdp, tlv); ++ ++ profile->port = port; ++ ++ if (vd->role == VDP_ROLE_STATION) { ++ /* do we have the profile already ? */ ++ p = vdp_find_profile(vd, profile); ++ if (p) { ++ LLDPAD_DBG("%s: station profile found localChange %i " ++ "ackReceived %i no_nlmsg:%d\n", ++ __func__, p->localChange, p->ackReceived, ++ p->no_nlmsg); ++ ++ if (profile->mode == VDP_MODE_DEASSOCIATE && ++ (p->response == VDP_RESPONSE_NO_RESPONSE || ++ p->response == VDP_RESPONSE_SUCCESS) && ++ p->mode == VDP_MODE_PREASSOCIATE) { ++ LLDPAD_DBG("%s: ignore dis-associate request " ++ "in pre-association\n", __func__); ++ vdp_delete_profile(profile); ++ return 0; ++ } ++ ++ p->ackReceived = true; ++ p->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; ++ if (profile->mode != p->mode) { ++ p->mode = profile->mode; ++ p->remoteChange = true; ++ if (profile->mode == VDP_MODE_DEASSOCIATE) ++ p->no_nlmsg = 0; ++ } else ++ p->remoteChange = false; ++ p->response = profile->response; ++ LLDPAD_DBG("%s: remoteChange %i no_nlmsg %d mode %d\n", ++ __func__, p->remoteChange, p->no_nlmsg, ++ p->mode); ++ if (vdp_vsi_negative_response(p)) ++ p->mode = VDP_MODE_DEASSOCIATE; ++ ++ LLDPAD_DBG("%s: profile response: %s (%i) " ++ "for profile %#02x at state %s\n", ++ __func__, ++ vdp_response2str(p->response), ++ p->response, p->instance[15], ++ vsi_states[p->state]); ++ } else { ++ LLDPAD_DBG("%s: station profile not found\n", __func__); ++ } ++ vdp_delete_profile(profile); ++ } ++ ++ if (vd->role == VDP_ROLE_BRIDGE) { ++ /* do we have the profile already ? */ ++ p = vdp_find_profile(vd, profile); ++ if (p) { ++ LLDPAD_DBG("%s: bridge profile found\n", __func__); ++ vdp_delete_profile(profile); ++ } else { ++ LLDPAD_DBG("%s: bridge profile not found\n", __func__); ++ /* put it in the list */ ++ profile->state = VSI_UNASSOCIATED; ++ LIST_INSERT_HEAD(&vd->profile_head, profile, profile); ++ } ++ ++ vdp_vsi_sm_bridge(profile); ++ } ++ ++ return 0; ++ ++out_err: ++ return 1; ++} ++ ++/* ++ * vdp_bld_vsi_tlv - build the VDP VSI TLV ++ * @vd: vdp_data structure for this port ++ * @profile: profile the vsi tlv is created from ++ * ++ * Returns 0 on success, ENOMEM otherwise ++ * ++ * creates a vdp structure from an existing profile ++ */ ++static int vdp_bld_vsi_tlv(struct vdp_data *vd, struct vsi_profile *profile) ++{ ++ struct mac_vlan *mv; ++ struct mac_vlan_p *mv_p; ++ struct tlv_info_vdp *vdp; ++ int rc = 0; ++ struct unpacked_tlv *tlv = NULL; ++ int size = sizeof(struct tlv_info_vdp) + ++ profile->entries * sizeof(struct mac_vlan_p); ++ ++ vdp = malloc(size); ++ ++ if (!vdp) { ++ LLDPAD_DBG("%s: unable to allocate memory for VDP TLV\n", ++ __func__); ++ rc = ENOMEM; ++ goto out_err; ++ } ++ ++ memset(vdp, 0, size); ++ ++ hton24(vdp->oui, OUI_IEEE_8021Qbg); ++ vdp->sub = LLDP_VDP_SUBTYPE; ++ vdp->mode = profile->mode; ++ vdp->response = 0; ++ vdp->mgrid = profile->mgrid; ++ hton24(vdp->id, profile->id); ++ vdp->version = profile->version; ++ memcpy(&vdp->instance, &profile->instance, 16); ++ vdp->format = VDP_FILTER_INFO_FORMAT_MACVID; ++ vdp->entries = htons(profile->entries); ++ ++ mv_p = (struct mac_vlan_p *)(vdp + 1); ++ ++ LIST_FOREACH(mv, &profile->macvid_head, entry) { ++ memcpy(mv_p->mac, mv->mac, MAC_ADDR_LEN); ++ mv_p->vlan = htons(mv->vlan); ++ mv_p++; ++ } ++ ++ tlv = create_tlv(); ++ if (!tlv) { ++ rc = ENOMEM; ++ goto out_free; ++ } ++ ++ tlv->type = ORG_SPECIFIC_TLV; ++ tlv->length = size; ++ tlv->info = (u8 *)malloc(tlv->length); ++ if(!tlv->info) { ++ free(tlv); ++ tlv = NULL; ++ rc = ENOMEM; ++ goto out_free; ++ } ++ ++ FREE_UNPKD_TLV(vd, vdp); ++ ++ memcpy(tlv->info, vdp, tlv->length); ++ ++ vd->vdp = tlv; ++ ++out_free: ++ free(vdp); ++ ++out_err: ++ return rc; ++} ++ ++/* vdp_bld_tlv - builds a tlv from a profile ++ * @vd: vdp_data structure for this port ++ * @profile: profile the vsi tlv is created from ++ * ++ * returns 0 on success, != 0 on error ++ * ++ * wrapper function around vdp_bld_vsi_tlv. adds some checks and calls ++ * vdp_bld_vsi_tlv. ++ */ ++ ++static int vdp_bld_tlv(struct vdp_data *vd, struct vsi_profile *profile) ++{ ++ if (!port_find_by_ifindex(get_ifidx(vd->ifname))) ++ return -EEXIST; ++ ++ if (vdp_bld_vsi_tlv(vd, profile)) { ++ LLDPAD_ERR("%s: %s vdp_bld_vsi_tlv() failed\n", ++ __func__, vd->ifname); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/* vdp_gettlv - get the tlv for a profile ++ * @port: the port on which the tlv was received ++ * @profile: profile the vsi tlv is created from ++ * ++ * returns 0 on success ++ * ++ * this is the interface function called from ecp_build_ECPDU. It returns the ++ * packed tlv for a profile. ++ */ ++struct packed_tlv *vdp_gettlv(struct vdp_data *vd, struct vsi_profile *profile) ++{ ++ int size; ++ struct packed_tlv *ptlv = NULL; ++ ++ /* frees the unpacked_tlv in vdp_data ++ * also done in vdp_bld_vsi_tlv */ ++ vdp_free_tlv(vd); ++ ++ if (vdp_bld_tlv(vd, profile)) { ++ LLDPAD_ERR("%s: %s vdp_bld_tlv failed\n", ++ __func__, vd->ifname); ++ goto out_err; ++ } ++ ++ size = TLVSIZE(vd->vdp); ++ ++ if (!size) { ++ LLDPAD_ERR("%s: size %i of unpacked_tlv not correct\n", ++ __func__, size); ++ goto out_err; ++ } ++ ++ ptlv = create_ptlv(); ++ if (!ptlv) ++ goto out_err; ++ ++ ptlv->tlv = malloc(size); ++ if (!ptlv->tlv) ++ goto out_free; ++ ++ ptlv->size = 0; ++ PACK_TLV_AFTER(vd->vdp, ptlv, size, out_free); ++ ++ return ptlv; ++ ++out_free: ++ ptlv = free_pkd_tlv(ptlv); ++out_err: ++ LLDPAD_ERR("%s: %s failed\n", __func__, vd->ifname); ++ return NULL; ++} ++ ++/* vdp_macvlan_equal - checks for equality of 2 mac/vlan pairs ++ * @mv1: mac/vlan pair 1 ++ * @mv2: mac/vlan pair 2 ++ * ++ * returns true if equal, false if not ++ * ++ * compares mac address and vlan if they are equal. ++ */ ++bool vdp_macvlan_equal(struct mac_vlan *mv1, struct mac_vlan *mv2) ++{ ++ if (memcmp(mv1->mac, mv2->mac, MAC_ADDR_LEN)) ++ return false; ++ ++ if (mv1->vlan != mv2->vlan) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * Check if the current profile already has this entry. If so take over ++ * PID and other fields. If not add this MAC,VLAN to our list. ++ * ++ * Returns 1 it the entry already exist, 0 if not. ++ */ ++static int have_macvlan(struct vsi_profile *p1, struct mac_vlan *new) ++{ ++ struct mac_vlan *mv1; ++ ++ LIST_FOREACH(mv1, &p1->macvid_head, entry) ++ if (vdp_macvlan_equal(mv1, new) == true) { ++ mv1->req_pid = new->req_pid; ++ mv1->req_seq = new->req_seq; ++ mv1->qos = new->qos; ++ return 1; ++ } ++ LIST_INSERT_HEAD(&p1->macvid_head, new, entry); ++ p1->entries++; ++ return 0; ++} ++ ++/* vdp_takeover_macvlans - take over macvlan pairs from p2 into p1 ++ * @p1: profile 1 ++ * @p2: profile 2 ++ * ++ * returns number of mac/vlan pairs taken over ++ * ++ * loops over all mac/vlan pairs in profile 2 and looks for them in profile 1. ++ * If the mac/vlan pair does not yet exist in profile 1, it adds the new pair to ++ * the list in profile 1. ++ */ ++void vdp_takeover_macvlans(struct vsi_profile *p1, struct vsi_profile *p2) ++{ ++ struct mac_vlan *mv2; ++ int count = 0; ++ ++ LLDPAD_DBG("%s: taking over mac/vlan pairs\n", __func__); ++ ++ while ((mv2 = LIST_FIRST(&p2->macvid_head))) { ++ LIST_REMOVE(mv2, entry); ++ p2->entries--; ++ if (have_macvlan(p1, mv2)) ++ free(mv2); ++ else ++ count++; ++ } ++ ++ LLDPAD_DBG("%s: %u mac/vlan pairs taken over\n", __func__, count); ++} ++ ++/* vdp_add_profile - adds a profile to a per port list ++ * @profile: profile to add ++ * ++ * returns the profile that has been found or added, NULL otherwise. ++ * ++ * main interface function which adds a profile to a list kept on a per-port ++ * basis. Checks if the profile is already in the list, adds it if necessary. ++ */ ++struct vsi_profile *vdp_add_profile(struct vdp_data *vd, ++ struct vsi_profile *profile) ++{ ++ struct vsi_profile *p; ++ ++ LLDPAD_DBG("%s: adding vdp profile for %s\n", __func__, ++ profile->port->ifname); ++ vdp_trace_profile(profile); ++ ++ /* ++ * Search this profile. If found check, ++ * if the MAC/VLAN pair already exists. If not, add it. ++ */ ++ p = vdp_find_profile(vd, profile); ++ if (p) { ++ LLDPAD_DBG("%s: profile already exists\n", __func__); ++ ++ vdp_takeover_macvlans(p, profile); ++ ++ if (p->mode != profile->mode) { ++ LLDPAD_DBG("%s: new mode %i\n", ++ __func__, profile->mode); ++ p->mode = profile->mode; ++ p->response = VDP_RESPONSE_NO_RESPONSE; ++ } ++ profile = p; ++ } else { ++ ++ /* ++ * Libvirt sends dis-assoc command and no profile active. ++ * Add to list with successful status to return the success ++ * to libvirtd when it queries for results. ++ */ ++ if (profile->mode == VDP_MODE_DEASSOCIATE) { ++ profile->response = VDP_RESPONSE_SUCCESS; ++ LLDPAD_DBG("%s: dis-assoc without profile\n", __func__); ++ } else ++ profile->response = VDP_RESPONSE_NO_RESPONSE; ++ ++ LIST_INSERT_HEAD(&vd->profile_head, profile, profile); ++ } ++ ++ if (profile->response != VDP_RESPONSE_SUCCESS) ++ vdp_somethingChangedLocal(profile, true); ++ ++ return profile; ++} ++ ++/* vdp_remove_profile - remove a profile from a per port list ++ * @profile: profile to remove ++ * ++ * returns 0 if removal was successful, -1 if removal failed ++ * ++ * function used in the state machines to remove a profile from a list kept on ++ * a per-port basis. Checks if the profile is in the list, removes it if there. ++ */ ++int vdp_remove_profile(struct vsi_profile *profile) ++{ ++ struct vsi_profile *p; ++ struct vdp_data *vd; ++ ++ LLDPAD_DBG("%s: removing vdp profile on %s\n", __func__, ++ profile->port->ifname); ++ vdp_trace_profile(profile); ++ ++ vd = vdp_data(profile->port->ifname); ++ if (!vd) { ++ LLDPAD_ERR("%s: could not find vdp_data for %s\n", __func__, ++ profile->port->ifname); ++ return -1; ++ } ++ /* Check if profile exists. If yes, remove it. */ ++ p = vdp_find_profile(vd, profile); ++ if (p) { ++ LIST_REMOVE(p, profile); ++ vdp_delete_profile(p); ++ return 0; ++ } ++ return -1; /* Not found */ ++} ++ ++/* vdp_ifdown - tear down vdp structures for a interface ++ * @ifname: name of the interface ++ * ++ * no return value ++ * ++ * interface function to lldpad. tears down vdp specific structures if ++ * interface "ifname" goes down. ++ */ ++void vdp_ifdown(char *ifname, UNUSED struct lldp_agent *agent) ++{ ++ struct vdp_data *vd; ++ struct vsi_profile *p; ++ ++ LLDPAD_DBG("%s: called on interface %s\n", __func__, ifname); ++ ++ vd = vdp_data(ifname); ++ if (!vd) ++ goto out_err; ++ ++ if (ecp_deinit(ifname)) ++ goto out_err; ++ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ if (p->ackTimer > 0) ++ vdp_stop_ackTimer(p); ++ if (p->keepaliveTimer > 0) ++ vdp_stop_keepaliveTimer(p); ++ } ++ ++ LLDPAD_INFO("%s: %s vdp data removed\n", __func__, ifname); ++ return; ++out_err: ++ LLDPAD_INFO("%s: %s vdp data remove failed\n", __func__, ifname); ++ ++ return; ++} ++ ++/* vdp_ifup - build up vdp structures for a interface ++ * @ifname: name of the interface ++ * ++ * no return value ++ * ++ * interface function to lldpad. builds up vdp specific structures if ++ * interface "ifname" goes up. ++ */ ++void vdp_ifup(char *ifname, struct lldp_agent *agent) ++{ ++ char *role; ++ char config_path[16]; ++ struct vdp_data *vd; ++ struct vdp_user_data *ud; ++ struct vsi_profile *p; ++ int enabletx = false; ++ ++ LLDPAD_DBG("%s: %s agent:%d start VDP\n", ++ __func__, ifname, agent->type); ++ ++ snprintf(config_path, sizeof(config_path), "%s.%s", ++ VDP_PREFIX, ARG_TLVTXENABLE); ++ ++ if (get_config_setting(ifname, agent->type, config_path, ++ (void *)&enabletx, CONFIG_TYPE_BOOL)) ++ enabletx = false; ++ ++ if (enabletx == false) { ++ LLDPAD_DBG("%s: %s not enabled for VDP\n", __func__, ifname); ++ return; ++ } ++ ++ vd = vdp_data(ifname); ++ if (vd) { ++ vd->enabletx = enabletx; ++ ++ LLDPAD_WARN("%s: %s vdp data already exists\n", ++ __func__, ifname); ++ goto out_start_again; ++ } ++ ++ /* not found, alloc/init per-port module data */ ++ vd = (struct vdp_data *) calloc(1, sizeof(struct vdp_data)); ++ if (!vd) { ++ LLDPAD_ERR("%s: %s malloc %zu failed\n", ++ __func__, ifname, sizeof(*vd)); ++ goto out_err; ++ } ++ strncpy(vd->ifname, ifname, IFNAMSIZ); ++ ++ vd->role = VDP_ROLE_STATION; ++ vd->enabletx = enabletx; ++ ++ if (!get_cfg(ifname, NEAREST_CUSTOMER_BRIDGE, "vdp.role", (void *)&role, ++ CONFIG_TYPE_STRING)) { ++ if (!strcasecmp(role, VAL_BRIDGE)) { ++ vd->role = VDP_ROLE_BRIDGE; ++ } ++ } ++ ++ LLDPAD_DBG("%s: configured for %s mode\n", ifname, ++ (vd->role ==VDP_ROLE_BRIDGE) ? "bridge" : "station"); ++ ++ LIST_INIT(&vd->profile_head); ++ ++ ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP02); ++ LIST_INSERT_HEAD(&ud->head, vd, entry); ++ ++out_start_again: ++ if (ecp_init(ifname)) { ++ LLDPAD_ERR("%s: %s unable to init ecp\n", __func__, ifname); ++ vdp_ifdown(ifname, agent); ++ goto out_err; ++ } ++ ++ vd->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; ++ vd->ackTimer = VDP_ACK_TIMER_DEFAULT; ++ ++ LLDPAD_DBG("%s: %s starting vdp timer (%i)\n", __func__, ++ vd->ifname, vd->nroftimers); ++ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ if (p->ackTimer > 0) { ++ vdp_somethingChangedLocal(p, true); ++ vdp_start_ackTimer(p); ++ } ++ if (p->keepaliveTimer > 0) ++ vdp_start_keepaliveTimer(p); ++ } ++ ++ LLDPAD_DBG("%s: %s agent:%d vdp added\n", __func__, ifname, ++ agent->type); ++ return; ++ ++out_err: ++ LLDPAD_ERR("%s: %s agent:%d vdp adding failed\n", ++ __func__, ifname, agent->type); ++} ++ ++static int vdp_client_cmd(UNUSED void *data, UNUSED struct sockaddr_un *from, ++ UNUSED socklen_t fromlen, char *ibuf, int ilen, ++ char *rbuf, int rlen) ++{ ++ return vdp_clif_cmd(ibuf, ilen, rbuf, rlen); ++} ++ ++static const struct lldp_mod_ops vdp_ops = { ++ .lldp_mod_register = vdp_register, ++ .lldp_mod_unregister = vdp_unregister, ++ .get_arg_handler = vdp_get_arg_handlers, ++ .client_cmd = vdp_client_cmd ++}; ++ ++/* vdp_register - register vdp module to lldpad ++ * @none ++ * ++ * returns lldp_module struct on success, NULL on error ++ * ++ * allocates a module structure with vdp module information and returns it ++ * to lldpad. ++ */ ++struct lldp_module *vdp_register(void) ++{ ++ struct lldp_module *mod; ++ struct vdp_user_data *ud; ++ ++ mod = malloc(sizeof(*mod)); ++ if (!mod) { ++ LLDPAD_ERR("%s: failed to start - vdp data\n", __func__); ++ return NULL; ++ } ++ ud = malloc(sizeof(struct vdp_user_data)); ++ if (!ud) { ++ free(mod); ++ LLDPAD_ERR("%s: failed to start - vdp user data\n", __func__); ++ return NULL; ++ } ++ LIST_INIT(&ud->head); ++ mod->id = LLDP_MOD_VDP02; ++ mod->ops = &vdp_ops; ++ mod->data = ud; ++ LLDPAD_DBG("%s: done\n", __func__); ++ return mod; ++} ++ ++/* vdp_unregister - unregister vdp module from lldpad ++ * @none ++ * ++ * no return value ++ * ++ * frees vdp module structure. ++ */ ++void vdp_unregister(struct lldp_module *mod) ++{ ++ if (mod->data) { ++ vdp_free_data((struct vdp_user_data *) mod->data); ++ free(mod->data); ++ } ++ free(mod); ++ LLDPAD_DBG("%s: done\n", __func__); ++} ++ ++void vdp_update(char *ifname, u8 ccap) ++{ ++ struct vdp_data *vdp = vdp_data(ifname); ++ ++ if (vdp) { ++ vdp->vdpbit_on = ccap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP; ++ LLDPAD_DBG("%s:%s vdpbit_on %d\n", __func__, ifname, ++ vdp->vdpbit_on); ++ } ++} ++ ++/* ++ * Handle a VSI request from buddy. ++ */ ++int vdp_request(struct vdpnl_vsi *vsi) ++{ ++ struct vdp_data *vd; ++ struct vsi_profile *profile, *p; ++ struct port *port = port_find_by_ifindex(get_ifidx(vsi->ifname)); ++ struct mac_vlan *mac_vlan; ++ int ret = 0; ++ ++ vd = vdp_data(vsi->ifname); ++ if (!vd) { ++ LLDPAD_ERR("%s: %s has not yet been configured\n", __func__, ++ vsi->ifname); ++ return -ENXIO; ++ } ++ if (!vd->vdpbit_on) { ++ LLDPAD_ERR("%s: %s has VDP disabled\n", __func__, vsi->ifname); ++ return -ENXIO; ++ } ++ ++ if (!port) { ++ LLDPAD_ERR("%s: %s can not find port\n", __func__, vsi->ifname); ++ return -ENODEV; ++ } ++ /* If the link is down, reject request */ ++ if (!port->portEnabled && vsi->request != VDP_MODE_DEASSOCIATE) { ++ LLDPAD_WARN("%s: %s not enabled, unable to associate\n", ++ __func__, vsi->ifname); ++ return -ENXIO; ++ } ++ ++ profile = vdp_alloc_profile(); ++ if (!profile) ++ return -ENOMEM; ++ mac_vlan = calloc(1, sizeof(struct mac_vlan)); ++ if (!mac_vlan) { ++ ret = -ENOMEM; ++ goto out_err; ++ } ++ ++ profile->port = port; ++ memcpy(&mac_vlan->mac, vsi->maclist->mac, sizeof mac_vlan->mac); ++ mac_vlan->vlan = vsi->maclist->vlan; ++ mac_vlan->qos = vsi->maclist->qos; ++ mac_vlan->req_pid = vsi->req_pid; ++ mac_vlan->req_seq = vsi->req_seq; ++ LIST_INSERT_HEAD(&profile->macvid_head, mac_vlan, entry); ++ profile->entries = 1; ++ ++ profile->mgrid = vsi->vsi_mgrid; ++ profile->id = vsi->vsi_typeid; ++ profile->version = vsi->vsi_typeversion; ++ profile->mode = vsi->request; ++ profile->response = vsi->response; ++ memcpy(profile->instance, vsi->vsi_uuid, sizeof vsi->vsi_uuid); ++ p = vdp_add_profile(vd, profile); ++ p->no_nlmsg = 1; ++ p->txmit = false; ++ vdp_trace_profile(p); ++ if (p != profile) ++ goto out_err; ++ return ret; ++ ++out_err: ++ vdp_delete_profile(profile); ++ return ret; ++} ++ ++/* ++ * Query a VSI request from buddy and report its progress. Use the interface ++ * name to determine the VSI profile list. Return one entry in parameter 'vsi' ++ * use the structure members response and vsi_uuid. ++ * Returns ++ * 1 valid VSI data returned ++ * 0 end of queue (no VSI data returned) ++ * <0 errno ++ */ ++int vdp_status(int number, struct vdpnl_vsi *vsi) ++{ ++ struct vdp_data *vd; ++ struct vsi_profile *p; ++ int i = 0, ret = 0; ++ ++ vd = vdp_data(vsi->ifname); ++ if (!vd) { ++ LLDPAD_ERR("%s: %s has not yet been configured\n", __func__, ++ vsi->ifname); ++ return -ENODEV; ++ } ++ /* Interate to queue element number */ ++ LIST_FOREACH(p, &vd->profile_head, profile) { ++ if (++i == number) { ++ ret = 1; ++ break; ++ } ++ } ++ if (ret) { ++ vdp_trace_profile(p); ++ vsi->macsz = 0; ++ vsi->response = p->response; ++ memcpy(vsi->vsi_uuid, p->instance, sizeof vsi->vsi_uuid); ++ if (p->response != VDP_RESPONSE_NO_RESPONSE ++ && p->state == VSI_EXIT) ++ vdp_remove_profile(p); ++ } ++ LLDPAD_DBG("%s: entry:%d more:%d\n", __func__, number, ret); ++ return ret; ++} ++ ++/* ++ * Copy MAC-VLAN list from profile to vdpnl structure. ++ */ ++static void copy_maclist(struct vsi_profile *p, struct vdpnl_mac *macp) ++{ ++ struct mac_vlan *mv1; ++ ++ LIST_FOREACH(mv1, &p->macvid_head, entry) { ++ macp->vlan = mv1->vlan; ++ macp->qos = mv1->qos; ++ memcpy(macp->mac, mv1->mac, sizeof macp->mac); ++ ++macp; ++ } ++} ++ ++/* ++ * Prepare data for a netlink message to originator of VSI. ++ * Forward a notification from switch. ++ */ ++int vdp_trigger(struct vsi_profile *profile) ++{ ++ struct vdpnl_vsi vsi; ++ struct vdp_data *vd; ++ struct mac_vlan *macp = 0; ++ int rc = -EINVAL; ++ struct vdpnl_mac maclist[profile->entries]; ++ ++ vsi.macsz = profile->entries; ++ vsi.maclist = maclist; ++ LLDPAD_DBG("%s: no_nlmsg:%d\n", __func__, profile->no_nlmsg); ++ vdp_trace_profile(profile); ++ if (profile->no_nlmsg) ++ return 0; ++ if (LIST_EMPTY(&profile->macvid_head)) ++ return 0; ++ macp = LIST_FIRST(&profile->macvid_head); ++ if (!macp->req_pid) ++ return 0; ++ sleep(1); /* Delay message notification */ ++ if (!profile->port || !profile->port->ifname) { ++ LLDPAD_ERR("%s: no ifname found for profile %p:\n", __func__, ++ profile); ++ goto error_exit; ++ } ++ memcpy(vsi.ifname, profile->port->ifname, sizeof vsi.ifname); ++ vd = vdp_data(vsi.ifname); ++ if (!vd) { ++ LLDPAD_ERR("%s: %s could not find vdp_data\n", __func__, ++ vsi.ifname); ++ goto error_exit; ++ } ++ vsi.ifindex = if_nametoindex(vsi.ifname); ++ if (vsi.ifindex == 0) { ++ LLDPAD_ERR("%s: %s could not find index for ifname\n", ++ __func__, vsi.ifname); ++ goto error_exit; ++ } ++ vsi.macsz = profile->entries; ++ copy_maclist(profile, vsi.maclist); ++ vsi.req_pid = macp->req_pid; ++ vsi.req_seq = macp->req_seq; ++ vsi.vsi_mgrid = profile->mgrid; ++ vsi.vsi_typeid = profile->id; ++ vsi.vsi_typeversion = profile->version; ++ memcpy(vsi.vsi_uuid, profile->instance, sizeof vsi.vsi_uuid); ++ vsi.request = VDP_MODE_DEASSOCIATE; ++ rc = vdpnl_send(&vsi); ++error_exit: ++ vdp_remove_profile(profile); ++ return rc; ++} +diff --git a/qbg/vdp22.c b/qbg/vdp22.c +new file mode 100644 +index 0000000..a3cb7c9 +--- /dev/null ++++ b/qbg/vdp22.c +@@ -0,0 +1,1081 @@ ++/****************************************************************************** ++ ++ Implementation of VDP22 protocol for IEEE 802.1 Qbg ratified standard ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "messages.h" ++#include "config.h" ++ ++#include "lldp_mod.h" ++#include "lldp_util.h" ++#include "qbg_vdpnl.h" ++#include "qbg22.h" ++#include "qbg_vdp22.h" ++#include "qbg_utils.h" ++#include "qbg_vdp22_cmds.h" ++ ++/* ++ * VDP22 helper functions ++ */ ++ ++/* ++ * Convert IPv4 address to string. ++ */ ++int vdp22_ipv42str(const u8 *p, char *dst, size_t size) ++{ ++ if (dst && size > VDP_UUID_STRLEN) { ++ snprintf(dst, size, "%02x%02x:%02x%02x:%02x%02x", ++ p[10], p[11], p[12], p[13], p[14], p[15]); ++ return 0; ++ } ++ return -1; ++} ++ ++/* ++ * Convert IPv6 address to string. ++ * TODO ++ * - compression of 16 bits zero fields ++ * - omit leading zeroes ++ */ ++int vdp22_ipv62str(const u8 *p, char *dst, size_t size) ++{ ++ if (dst && size > VDP_UUID_STRLEN) { ++ snprintf(dst, size, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" ++ "%02x%02x:%02x%02x:%02x%02x:%02x%02x", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], ++ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ return 0; ++ } ++ return -1; ++} ++ ++static int vdp22_local2str(const u8 *p, char *dst, size_t size) ++{ ++ if (dst && size > VDP_UUID_STRLEN) { ++ snprintf(dst, size, "%02x%02x%02x%02x%02x%02x%02x%02x" ++ "%02x%02x%02x%02x%02x%02x%02x%02x", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], ++ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ return 0; ++ } ++ return -1; ++} ++ ++/* ++ * Print VSI filter information data. ++ */ ++static void showvsifid(char *txt, unsigned char fif, unsigned short no, ++ struct fid22 *fe) ++{ ++ char idbuf[VDP_UUID_STRLEN + 2]; ++ int i; ++ ++ for (i = 0; i < no; ++i, ++fe) { ++ switch (fif) { ++ case VDP22_FFMT_GROUPVID: ++ LLDPAD_DBG("%s:grpid:%ld vlan:%d qos:%d" ++ " pid:%d seq:%ld\n", txt, fe->grpid, ++ vdp22_get_vlanid(fe->vlan), ++ vdp22_get_qos(fe->vlan), ++ fe->requestor.req_pid, ++ fe->requestor.req_seq); ++ break; ++ case VDP22_FFMT_GROUPMACVID: ++ mac2str(fe->mac, idbuf, sizeof idbuf); ++ LLDPAD_DBG("%s:mac:%s grpid:%ld vlan:%d" ++ " qos:%d pid:%d seq:%ld\n", txt, idbuf, ++ fe->grpid, vdp22_get_vlanid(fe->vlan), ++ vdp22_get_qos(fe->vlan), ++ fe->requestor.req_pid, ++ fe->requestor.req_seq); ++ break; ++ case VDP22_FFMT_VID: ++ LLDPAD_DBG("%s:vlan:%d qos:%d pid:%d seq:%ld\n", ++ txt, vdp22_get_vlanid(fe->vlan), ++ vdp22_get_qos(fe->vlan), ++ fe->requestor.req_pid, ++ fe->requestor.req_seq); ++ break; ++ case VDP22_FFMT_MACVID: ++ mac2str(fe->mac, idbuf, sizeof idbuf); ++ LLDPAD_DBG("%s:mac:%s vlan:%d qos:%d" ++ " pid:%d seq:%ld\n", txt, idbuf, ++ vdp22_get_vlanid(fe->vlan), ++ vdp22_get_qos(fe->vlan), ++ fe->requestor.req_pid, ++ fe->requestor.req_seq); ++ break; ++ default: ++ LLDPAD_DBG("%s:unsupported filter info format\n", txt); ++ } ++ } ++} ++ ++/* ++ * Convert a mgrid to a printable string. ++ */ ++static void mgrid2str(struct vsi22 *p, char *buf, size_t len) ++{ ++ int i, nul; ++ bool print = false; ++ ++ /* Find last non nul byte */ ++ for (nul = sizeof(p->mgrid) - 1; nul >= 0; --nul) { ++ if (p->mgrid[nul] != '\0') ++ break; ++ } ++ if (nul == 0) { ++ sprintf(buf, "%d", p->mgrid[0]); ++ return; ++ } ++ for (i = 0; i <= nul; ++i) { ++ if (isprint(p->mgrid[i])) ++ print = true; ++ else ++ break; ++ } ++ if (print) ++ strncpy(buf, (char *)p->mgrid, len); ++ else ++ vdp22_local2str(p->mgrid, buf, len); ++} ++ ++/* ++ * Print VSI data ++ */ ++void vdp22_showvsi(struct vsi22 *p) ++{ ++ char idbuf[VDP_UUID_STRLEN + 2]; ++ char mgridbuf[VDP_UUID_STRLEN + 2]; ++ ++ switch (p->vsi_fmt) { ++ case VDP22_ID_UUID: ++ vdp_uuid2str(p->vsi, idbuf, sizeof(idbuf)); ++ break; ++ case VDP22_ID_MAC: ++ mac2str(p->vsi + 10, idbuf, sizeof(idbuf)); ++ break; ++ case VDP22_ID_IP4: ++ vdp22_ipv42str(p->vsi, idbuf, sizeof(idbuf)); ++ break; ++ case VDP22_ID_IP6: ++ vdp22_ipv62str(p->vsi, idbuf, sizeof(idbuf)); ++ break; ++ case VDP22_ID_LOCAL: ++ vdp22_local2str(p->vsi, idbuf, sizeof(idbuf)); ++ break; ++ default: ++ strcpy(idbuf, "unsupported format"); ++ break; ++ } ++ ++ mgrid2str(p, mgridbuf, sizeof(mgridbuf)); ++ LLDPAD_DBG("vsi:%p flags:%#lx vsi_mode:%d,%d status:%#x" ++ " mgrid:%s id:%ld(%#lx) version:%d" ++ " id_fmt:%d %s format:%d no:%d\n", ++ p, p->flags, p->vsi_mode, p->cc_vsi_mode, p->status, ++ mgridbuf, p->type_id, ++ p->type_id, p->type_ver, p->vsi_fmt, idbuf, ++ p->fif, p->no_fdata); ++ if (p->fdata) ++ showvsifid("fid", p->fif, p->no_fdata, p->fdata); ++ LLDPAD_DBG("smi:state:%d kato:%d ackreceived:%d acktimeout:%d" ++ " localchg:%d deassoc:%d txmit:%d resp_ok:%d" ++ " txmit_error:%d\n", p->smi.state, p->smi.kato, ++ p->smi.ackreceived, p->smi.acktimeout, p->smi.localchg, ++ p->smi.deassoc, p->smi.txmit, p->smi.resp_ok, ++ p->smi.txmit_error); ++} ++ ++/* ++ * Delete a complete VSI node not on queue. ++ */ ++static void vdp22_delete_vsi(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, ++ p->vsi[0]); ++ free(p->fdata); ++ free(p); ++} ++ ++/* ++ * Remove a VSI node from list and delete it. ++ */ ++void vdp22_listdel_vsi(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, ++ p->vsi[0]); ++ LIST_REMOVE(p, node); ++ vdp22_delete_vsi(p); ++} ++ ++/* Check for valid VSI request mode, filter info format and VSI ID */ ++/* ++ * Return true if data consists completely of zeroes. ++ */ ++static bool is_zeroes(unsigned char *cp, size_t len) ++{ ++ size_t x; ++ ++ for (x = 0; x < len; ++x) ++ if (*cp++) ++ return false; ++ return true; ++} ++ ++/* ++ * IPV4 address right aligned with leading zeros. ++ */ ++static bool is_ipv4(unsigned char *cp) ++{ ++ if (!is_zeroes(cp, 10)) ++ return false; ++ if (cp[10] != 0xff && cp[11] != 0xff) ++ return false; ++ if (is_zeroes(cp + 12, 4)) ++ return false; ++ return true; ++} ++ ++/* ++ * MAC address right aligned with leading zeros. ++ */ ++static bool is_mac(unsigned char *cp) ++{ ++ if (!is_zeroes(cp, 10)) ++ return false; ++ return is_valid_mac(cp + 10); ++} ++ ++/* ++ * IPV6 address. ++ */ ++static bool is_ipv6(unsigned char *cp) ++{ ++ if (is_zeroes(cp, 16)) ++ return false; ++ return true; ++} ++ ++/* ++ * Check if VSI request is valid. ++ */ ++static bool check_vsirequest(unsigned char request) ++{ ++ bool rc = true; ++ ++ switch (request) { ++ case VDP22_PREASSOC: ++ case VDP22_PREASSOC_WITH_RR: ++ case VDP22_ASSOC: ++ case VDP22_DEASSOC: ++ case VDP22_MGRID: ++ case VDP22_OUI: ++ break; ++ default: ++ rc = false; ++ } ++ LLDPAD_DBG("%s rc:%d\n", __func__, rc); ++ return rc; ++} ++ ++/* ++ * Check if VSI filter information format is valid. ++ */ ++static bool check_filterfmt(unsigned char filter_fmt) ++{ ++ bool rc = true; ++ ++ switch (filter_fmt) { ++ case VDP22_FFMT_VID: ++ case VDP22_FFMT_MACVID: ++ case VDP22_FFMT_GROUPVID: ++ case VDP22_FFMT_GROUPMACVID: ++ break; ++ default: ++ rc = false; ++ } ++ LLDPAD_DBG("%s rc:%d\n", __func__, rc); ++ return rc; ++} ++ ++/* ++ * Check if VSI identifier is valid. ++ */ ++static bool check_vsiid(unsigned char fmt, unsigned char *vsi_uuid) ++{ ++ bool rc = true; ++ ++ switch (fmt) { ++ case VDP22_ID_IP4: ++ if (!is_ipv4(vsi_uuid)) ++ rc = false; ++ break; ++ case VDP22_ID_IP6: ++ if (!is_ipv6(vsi_uuid)) ++ rc = false; ++ break; ++ case VDP22_ID_MAC: ++ if (!is_mac(vsi_uuid)) ++ rc = false; ++ break; ++ case VDP22_ID_UUID: ++ if (is_zeroes(vsi_uuid, sizeof(vsi_uuid))) ++ rc = false; ++ break; ++ case VDP22_ID_LOCAL: ++ /* Anything goes */ ++ break; ++ default: ++ rc = false; ++ } ++ LLDPAD_DBG("%s rc:%d\n", __func__, rc); ++ return rc; ++} ++ ++/* ++ * Check if VSI information received via netlink message is valid. ++ */ ++static bool check_vsinl(struct vdpnl_vsi *vsi) ++{ ++ bool rc; ++ ++ rc = check_vsiid(vsi->vsi_idfmt, vsi->vsi_uuid) ++ && check_vsirequest(vsi->request) ++ && check_filterfmt(vsi->filter_fmt); ++ LLDPAD_DBG("%s:%s request:%d filter_fmt:%d vsi_fmt:%d rc:%d\n", ++ __func__, vsi->ifname, vsi->request, vsi->filter_fmt, ++ vsi->vsi_idfmt, rc); ++ return rc; ++} ++ ++/* ++ * Check if VSI information received via TLV message is valid. ++ */ ++static bool check_vsi(struct vsi22 *vsi) ++{ ++ bool rc; ++ ++ rc = check_vsiid(vsi->vsi_fmt, vsi->vsi) ++ && check_vsirequest(vsi->vsi_mode) && check_filterfmt(vsi->fif); ++ LLDPAD_DBG("%s:%s vsi_mode:%d filter_fmt:%d vsi_fmt:%d rc:%d\n", ++ __func__, vsi->vdp->ifname, vsi->vsi_mode, vsi->fif, ++ vsi->vsi_fmt, rc); ++ return rc; ++} ++ ++/* ++ * Copy filter information data. ++ */ ++static void copy_filter(unsigned char fif, struct fid22 *fp, ++ struct vdpnl_mac *from) ++{ ++ switch (fif) { ++ case VDP22_FFMT_GROUPMACVID: ++ case VDP22_FFMT_GROUPVID: ++ fp->grpid = from->gpid; ++ if (fif == VDP22_FFMT_GROUPVID) ++ goto vid; ++ /* Fall through intended */ ++ case VDP22_FFMT_MACVID: ++ memcpy(fp->mac, from->mac, sizeof(fp->mac)); ++ /* Fall through intended */ ++ case VDP22_FFMT_VID: ++vid: ++ fp->vlan = vdp22_set_vlanid(from->vlan) ++ | vdp22_set_qos(from->qos); ++ break; ++ } ++} ++ ++/* ++ * Check supplied filter information. ++ */ ++static bool check_mac(struct fid22 *fp) ++{ ++ if (!is_valid_mac(fp->mac)) ++ return false; ++ return true; ++} ++ ++static bool check_vid(struct fid22 *fp) ++{ ++ unsigned short num = vdp22_get_vlanid(fp->vlan); ++ ++ if (num > 0 && (num < 2 || num > 4094)) ++ return false; ++ return true; ++} ++ ++static bool check_group(struct fid22 *fp) ++{ ++ return fp->grpid ? true : false; ++} ++ ++/* ++ * Check for filter information consistency. ++ */ ++static bool filter_ok(unsigned char ffmt, struct fid22 *fp, ++ unsigned char gpid_on) ++{ ++ bool rc = false; ++ ++ switch (ffmt) { ++ case VDP22_FFMT_VID: ++ rc = check_vid(fp); ++ break; ++ case VDP22_FFMT_MACVID: ++ rc = check_vid(fp) && check_mac(fp); ++ break; ++ case VDP22_FFMT_GROUPVID: ++ if (gpid_on) ++ rc = check_vid(fp) && check_group(fp); ++ else ++ rc = false; ++ break; ++ case VDP22_FFMT_GROUPMACVID: ++ if (gpid_on) ++ rc = check_vid(fp) && check_mac(fp) && ++ check_group(fp); ++ else ++ rc = false; ++ } ++ LLDPAD_DBG("%s:rc:%d\n", __func__, rc); ++ return rc; ++} ++ ++/* ++ * Allocate a VSI node with filter information data. ++ * Check if input data is valid. ++ */ ++static struct vsi22 *vdp22_alloc_vsi(struct vdpnl_vsi *vsi, struct vdp22 *vdp, ++ int *rc) ++{ ++ struct vsi22 *p; ++ int i; ++ ++ *rc = -EINVAL; ++ if (!check_vsinl(vsi)) ++ return NULL; ++ p = calloc(1, sizeof(*p)); ++ if (!p) { ++ *rc = -ENOMEM; ++ return p; ++ } ++ ++ p->no_fdata = vsi->macsz; ++ p->fdata = calloc(vsi->macsz, sizeof(struct fid22)); ++ if (!p->fdata) { ++ free(p); ++ *rc = -ENOMEM; ++ return NULL; ++ } ++ ++ p->vdp = vdp; ++ p->vsi_mode = vsi->request; ++ p->cc_vsi_mode = VDP22_DEASSOC; ++ p->hints = vsi->hints; ++ p->status = VDP22_RESP_NONE; ++ p->flags = VDP22_BUSY | VDP22_NLCMD; ++ if (vsi->nl_version == vdpnl_nlf2) ++ memcpy(p->mgrid, vsi->vsi_mgrid2, sizeof(p->mgrid)); ++ else ++ p->mgrid[0] = vsi->vsi_mgrid; ++ p->type_ver = vsi->vsi_typeversion; ++ p->type_id = vsi->vsi_typeid; ++ p->vsi_fmt = VDP22_ID_UUID; ++ memcpy(p->vsi, vsi->vsi_uuid, sizeof(p->vsi)); ++ p->fif = vsi->filter_fmt; ++ ++ /* Copy filter info and do some sanity checks based on format */ ++ for (i = 0; i < vsi->macsz; ++i) { ++ struct vdpnl_mac *from = &vsi->maclist[i]; ++ struct fid22 *fp = &p->fdata[i]; ++ ++ copy_filter(p->fif, fp, from); ++ if (from->vlan == 0) { ++ /* Only one filter member with null vlan id */ ++ if (vsi->macsz > 1 && p->fif == VDP22_FFMT_VID) { ++ *rc = -EINVAL; ++ goto error1; ++ } ++ p->flags |= VDP22_RETURN_VID; ++ } ++ if (!filter_ok(p->fif, fp, vdp->gpid)) { ++ *rc = -EINVAL; ++ goto error1; ++ } ++ fp->requestor.req_pid = vsi->req_pid; ++ fp->requestor.req_seq = vsi->req_seq; ++ } ++ *rc = 0; ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, vsi->ifname, p, p->vsi[0]); ++ return p; ++error1: ++ vdp22_showvsi(p); ++ vdp22_delete_vsi(p); ++ return NULL; ++} ++ ++/* ++ * Allocate a VSI node with filter information data. ++ * Check if input data is valid. Data was received by bridge from unknown ++ * counterpart and might be invalid. ++ */ ++struct vsi22 *vdp22_copy_vsi(struct vsi22 *old) ++{ ++ struct vsi22 *p; ++ int i; ++ ++ if (!check_vsi(old)) ++ return NULL; ++ p = calloc(1, sizeof(*p)); ++ if (!p) ++ return p; ++ *p = *old; ++ p->flags = 0; ++ p->cc_vsi_mode = VDP22_DEASSOC; ++ p->fdata = calloc(p->no_fdata, sizeof(struct fid22)); ++ if (!p->fdata) ++ goto error1; ++ ++ /* Copy filter info and do some sanity checks based on format */ ++ for (i = 0; i < p->no_fdata; ++i) { ++ p->fdata[i] = old->fdata[i]; ++ /* Only one filter member with wildcard vlan id */ ++ if (p->fdata[i].vlan == 0) { ++ if (p->no_fdata > 1 && p->fif == VDP22_FFMT_VID) ++ goto error1; ++ } ++ if (!filter_ok(p->fif, &p->fdata[i], p->vdp->gpid)) ++ goto error1; ++ } ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, ++ p->vsi[0]); ++ return p; ++error1: ++ vdp22_delete_vsi(p); ++ return NULL; ++} ++ ++/* ++ * Find the vdp data associated with an interface. ++ * Parameter 'ud' may be zero, then search for the module first. ++ * ++ * Return pointer or NULL if not found. ++ */ ++static struct vdp22 *vdp22_findif(const char *ifname, ++ struct vdp22_user_data *ud) ++{ ++ struct vdp22 *vdp = 0; ++ ++ if (!ud) { ++ ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); ++ if (!ud) ++ LLDPAD_DBG("%s:%s no VDP22 module\n", __func__, ++ ifname); ++ } ++ if (ud) { ++ LIST_FOREACH(vdp, &ud->head, node) ++ if (!strncmp(ifname, vdp->ifname, IFNAMSIZ)) ++ break; ++ } ++ return vdp; ++} ++ ++/* ++ * Update data exchanged via ECP protocol. ++ * Returns true when data update succeeded. ++ */ ++static int data_from_ecp(char *ifname, struct ecp22_to_ulp *ptr) ++{ ++ int rc = -ENOENT; ++ struct vdp22 *vdp; ++ ++ vdp = vdp22_findif(ifname, NULL); ++ if (vdp) { ++ memcpy(vdp->input, ptr->data, ptr->len); ++ vdp->input_len = ptr->len; ++ rc = vdp22_from_ecp22(vdp); ++ LLDPAD_DBG("%s:%s rc:%d ", __func__, ifname, rc); ++ } ++ return rc; ++} ++ ++/* ++ * Update data exchanged via EVB protocol. ++ * Calculate the various time out values based in input parameters. ++ * See IEEE 802.1Qbg ratified standard 41.5.5.7 + 41.5.5.9 ++ * Returns true when data update succeeded. ++ */ ++static int data_from_evb(char *ifname, struct evb22_to_vdp22 *ptr) ++{ ++ int rc = -ENOENT; ++ struct vdp22 *vdp; ++ ++ vdp = vdp22_findif(ifname, NULL); ++ if (vdp) { ++ vdp->ecp_retries = ptr->max_retry; ++ vdp->ecp_rte = ptr->max_rte; ++ vdp->vdp_rka = ptr->max_rka; ++ vdp->vdp_rwd = ptr->max_rwd; ++ vdp->gpid = ptr->gpid; ++ vdp->evbon = ptr->evbon; ++ LLDPAD_DBG("%s:%s rwd:%d rka:%d gpid:%d retry:%d rte:%d evb:%d\n", ++ __func__, ifname, ptr->max_rwd, ptr->max_rka, ++ ptr->gpid, ptr->max_retry, ptr->max_rte, ptr->evbon); ++ rc = 0; ++ } ++ return rc; ++} ++ ++/* ++ * Handle notifications from other modules. Check if sender-id and data type ++ * indicator match. Return false when data could not be delivered. ++ */ ++static int vdp22_notify(int sender_id, char *ifname, void *data) ++{ ++ struct qbg22_imm *qbg = (struct qbg22_imm *)data; ++ ++ LLDPAD_DBG("%s:%s sender-id:%#x data_type:%d\n", __func__, ifname, ++ sender_id, qbg->data_type); ++ if (sender_id == LLDP_MOD_EVB22 && qbg->data_type == EVB22_TO_VDP22) ++ return data_from_evb(ifname, &qbg->u.b); ++ if (sender_id == LLDP_MOD_ECP22 && qbg->data_type == ECP22_TO_ULP) ++ return data_from_ecp(ifname, &qbg->u.c); ++ return 0; ++} ++ ++/* ++ * Remove a vdp22 element and delete the chain of active VSIs ++ */ ++static void vdp22_free_elem(struct vdp22 *vdp) ++{ ++ while (!LIST_EMPTY(&vdp->vsi22_que)) { ++ struct vsi22 *p = LIST_FIRST(&vdp->vsi22_que); ++ ++ vdp22_listdel_vsi(p); ++ } ++ LIST_REMOVE(vdp, node); ++ free(vdp); ++} ++ ++/* ++ * Disable the interface for VDP protocol support. ++ */ ++void vdp22_stop(char *ifname) ++{ ++ struct vdp22_user_data *vud; ++ struct vdp22 *vdp; ++ struct vsi22 *vsi; ++ ++ LLDPAD_DBG("%s:%s stop vdp\n", __func__, ifname); ++ vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); ++ if (!vud) { ++ LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); ++ return; ++ } ++ vdp = vdp22_findif(ifname, vud); ++ if (!vdp) { ++ LLDPAD_ERR("%s:%s no VDP22 data\n", __func__, ifname); ++ return; ++ } ++ ++ LIST_FOREACH(vsi, &vdp->vsi22_que, node) { ++ vdp22_stop_timers(vsi); ++ } ++} ++ ++/* ++ * vdp22_create - create data structure and initialize vdp protocol ++ * @ifname: interface for which the vdp protocol is initialized ++ * ++ * returns NULL on error and an pointer to the vdp22 structure on success. ++ * ++ * Finds the port to the interface name, sets up the receive handle for ++ * incoming vdp frames and initializes the vdp rx and tx state machines. ++ * To be called when a successful exchange of EVB TLVs has been ++ * made and ECP protocols are supported by both sides. ++ * ++ * Read the role (station vs bridge) from the configuration file. ++ */ ++static struct vdp22 *vdp22_create(const char *ifname, ++ struct vdp22_user_data *eud, int role) ++{ ++ struct vdp22 *vdp; ++ ++ vdp = calloc(1, sizeof *vdp); ++ if (!vdp) { ++ LLDPAD_ERR("%s:%s unable to allocate vdp protocol\n", __func__, ++ ifname); ++ return NULL; ++ } ++ strncpy(vdp->ifname, ifname, sizeof vdp->ifname); ++ vdp->myrole = role; ++ LIST_INIT(&vdp->vsi22_que); ++ LIST_INSERT_HEAD(&eud->head, vdp, node); ++ LLDPAD_DBG("%s:%s role:%d\n", __func__, ifname, role); ++ return vdp; ++} ++ ++/* ++ * Query the supported VDP protocol on an interface. ++ */ ++static struct vdp22 *vdp22_getvdp(const char *ifname) ++{ ++ struct vdp22 *vdp; ++ ++ vdp = vdp22_findif(ifname, NULL); ++ LLDPAD_DBG("%s:%s vdp %p\n", __func__, ifname, vdp); ++ return vdp; ++} ++ ++int vdp22_query(const char *ifname) ++{ ++ int rc = 0; ++ ++ if (vdp22_getvdp(ifname)) ++ rc = 1; ++ LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); ++ return rc; ++} ++ ++/* ++ * Enable the interface for VDP protocol support. ++ */ ++void vdp22_start(const char *ifname, int role) ++{ ++ struct vdp22_user_data *vud; ++ struct vdp22 *vdp; ++ struct vsi22 *vsi; ++ ++ LLDPAD_DBG("%s:%s start vdp\n", __func__, ifname); ++ vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); ++ if (!vud) { ++ LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); ++ return; ++ } ++ vdp = vdp22_findif(ifname, vud); ++ ++ if (!vdp) { ++ vdp = vdp22_create(ifname, vud, role); ++ } else { ++ LIST_FOREACH(vsi, &vdp->vsi22_que, node) { ++ vsi->smi.localchg = true; ++ vdp22_showvsi(vsi); ++ vdp22_start_localchange_timer(vsi); ++ } ++ } ++} ++ ++/* ++ * Handle a VSI request from buddy. ++ */ ++int vdp22_request(struct vdpnl_vsi *vsi, int clif) ++{ ++ int rc; ++ struct vsi22 *p; ++ struct vdp22 *vdp; ++ ++ LLDPAD_DBG("%s:%s clif:%d\n", __func__, vsi->ifname, clif); ++ vdp = vdp22_findif(vsi->ifname, NULL); ++ if (vdp) { ++ if (!vdp->evbon) { ++ rc = -EPROTONOSUPPORT; ++ goto out; ++ } ++ if (vdp->myrole == VDP22_BRIDGE) { ++ rc = -EOPNOTSUPP; ++ goto out; ++ } ++ /* Adjust numbering for VDP 0.2 protocol from netlink */ ++ if (!clif) ++ vsi->request += 1; ++ p = vdp22_alloc_vsi(vsi, vdp, &rc); ++ if (p) { ++ rc = vdp22_addreq(p, vdp); ++ if (rc) ++ vdp22_delete_vsi(p); ++ } ++ } else ++ rc = -ENODEV; ++out: ++ LLDPAD_DBG("%s:%s rc:%d\n", __func__, vsi->ifname, rc); ++ return rc; ++} ++ ++/* ++ * Remove all interface/agent specific vdp data. ++ */ ++static void vdp22_free_data(struct vdp22_user_data *ud) ++{ ++ if (ud) { ++ while (!LIST_EMPTY(&ud->head)) { ++ struct vdp22 *vd = LIST_FIRST(&ud->head); ++ ++ vdp22_free_elem(vd); ++ } ++ } ++} ++ ++void vdp22_unregister(struct lldp_module *mod) ++{ ++ if (mod->data) { ++ vdp22_free_data((struct vdp22_user_data *)mod->data); ++ free(mod->data); ++ } ++ free(mod); ++ LLDPAD_DBG("%s:done\n", __func__); ++} ++ ++static int clnt(void *data, struct sockaddr_un *from, socklen_t fromlen, ++ char *ibuf, int ilen, char *rbuf, int rlen) ++{ ++ return vdp22_clif_cmd(data, from, fromlen, ibuf, ilen, rbuf, rlen); ++} ++ ++static const struct lldp_mod_ops vdp22_ops = { ++ .lldp_mod_register = vdp22_register, ++ .lldp_mod_unregister = vdp22_unregister, ++ .lldp_mod_notify = vdp22_notify, ++ .get_arg_handler = vdp22_arg_handlers, ++ .client_cmd = clnt, ++}; ++ ++struct lldp_module *vdp22_register(void) ++{ ++ struct lldp_module *mod; ++ struct vdp22_user_data *ud; ++ ++ mod = calloc(1, sizeof *mod); ++ if (!mod) { ++ LLDPAD_ERR("%s: failed to malloc module data\n", __func__); ++ return NULL; ++ } ++ ud = calloc(1, sizeof *ud); ++ if (!ud) { ++ free(mod); ++ LLDPAD_ERR("%s failed to malloc module user data\n", __func__); ++ return NULL; ++ } ++ LIST_INIT(&ud->head); ++ mod->id = LLDP_MOD_VDP22; ++ mod->ops = &vdp22_ops; ++ mod->data = ud; ++ LLDPAD_DBG("%s:done\n", __func__); ++ return mod; ++} ++ ++static void copy_fid(struct vdpnl_vsi *vsi, struct vsi22 *p) ++{ ++ int i; ++ ++ vsi->maclist = calloc(p->no_fdata, sizeof(*vsi->maclist)); ++ if (!vsi->maclist) ++ return; ++ vsi->macsz = p->no_fdata; ++ vsi->filter_fmt = p->fif; ++ for (i = 0; i < p->no_fdata; ++i) { ++ vsi->maclist[i].gpid = p->fdata[i].grpid; ++ vsi->maclist[i].vlan = vdp22_get_vlanid(p->fdata[i].vlan); ++ vsi->maclist[i].qos = vdp22_get_qos(p->fdata[i].vlan); ++ vsi->maclist[i].changed = 1; ++ memcpy(vsi->maclist[i].mac, p->fdata[i].mac, ++ sizeof(vsi->maclist[i].mac)); ++ } ++} ++ ++/* ++ * Fill the VSI data to return to caller. Currently returned data depends ++ * on requestor: ++ * 1. Via netlink message from libvirtd and vdptest: ++ * Return UUID, Response when available. changed FID. ++ * 2. Via lldptool: ++ * All data. ++ */ ++static void copy_vsi(struct vdpnl_vsi *vsi, struct vsi22 *p, int clif) ++{ ++ /* For netlink reply */ ++ vsi->response = p->status; ++ memcpy(vsi->vsi_uuid, p->vsi, sizeof(vsi->vsi_uuid)); ++ /* For client interface reply */ ++ vsi->request = p->vsi_mode; ++ vsi->vsi_typeid = p->type_id; ++ vsi->vsi_typeversion = p->type_ver; ++ memcpy(vsi->vsi_mgrid2, p->mgrid, sizeof(vsi->vsi_mgrid2)); ++ vsi->vsi_idfmt = p->vsi_fmt; ++ vsi->hints = p->cc_vsi_mode; ++ p->flags &= ~VDP22_NLCMD; ++ if (clif || (p->flags & VDP22_RETURN_VID)) { ++ copy_fid(vsi, p); ++ p->flags &= ~VDP22_RETURN_VID; ++ } ++} ++ ++/* ++ * Query a VSI request from buddy and report its progress. Use the interface ++ * name to determine the VSI profile list. Return one entry in parameter 'vsi' ++ * use the structure members response and vsi_uuid. ++ * Returns ++ * 1 valid VSI data returned ++ * 0 end of queue (no VSI data returned) ++ * <0 errno ++ */ ++int vdp22_status(int number, struct vdpnl_vsi *vsi, int clif) ++{ ++ struct vdp22 *vdp; ++ struct vsi22 *p; ++ int i = 0, ret = 0; ++ ++ LLDPAD_DBG("%s:%s clif:%d\n", __func__, vsi->ifname, clif); ++ vdp = vdp22_findif(vsi->ifname, NULL); ++ if (!vdp) { ++ LLDPAD_ERR("%s:%s has not yet been configured\n", __func__, ++ vsi->ifname); ++ return -ENODEV; ++ } ++ /* Iterate to queue element number */ ++ LIST_FOREACH(p, &vdp->vsi22_que, node) { ++ if (++i == number) { ++ ret = 1; ++ break; ++ } ++ } ++ if (ret) { ++ vdp22_showvsi(p); ++ copy_vsi(vsi, p, clif); ++ if (vsi->response != VDP22_RESP_NONE && ++ (p->flags & VDP22_DELETE_ME)) ++ vdp22_listdel_vsi(p); ++ } ++ LLDPAD_DBG("%s:%s entry:%d more:%d\n", __func__, vsi->ifname, ++ number, ret); ++ return ret; ++} ++ ++/* ++ * Find out if vsi command was received via netlink interface or via ++ * attached control interface. Pid equals zero means control interface. ++ */ ++static pid_t havepid(struct vsi22 *vsi) ++{ ++ pid_t mypid = 0; ++ int i; ++ ++ for (i = 0; i < vsi->no_fdata; ++i) ++ mypid = vsi->fdata[i].requestor.req_pid; ++ return mypid; ++} ++ ++/* ++ * Convert and VSI22 to VDP netlink format and send it back to the originator. ++ */ ++static int vdp22_back(struct vsi22 *vsi, pid_t to, ++ int (*fct)(struct vdpnl_vsi *)) ++{ ++ int i; ++ struct vdpnl_vsi nl; ++ struct vdpnl_mac nlmac[vsi->no_fdata]; ++ ++ LLDPAD_DBG("%s:%s to:%d\n", __func__, vsi->vdp->ifname, to); ++ memset(&nl, 0, sizeof(nl)); ++ memset(nlmac, 0, sizeof(nlmac)); ++ nl.maclist = nlmac; ++ nl.macsz = vsi->no_fdata; ++ memcpy(nl.ifname, vsi->vdp->ifname, sizeof(nl.ifname)); ++ nl.request = vsi->vsi_mode; ++ nl.response = vsi->status; ++ nl.vsi_mgrid = vsi->mgrid[0]; ++ memcpy(nl.vsi_mgrid2, vsi->mgrid, sizeof(nl.vsi_mgrid2)); ++ nl.vsi_typeversion = vsi->type_ver; ++ nl.vsi_typeid = vsi->type_id; ++ nl.vsi_idfmt = VDP22_ID_UUID; ++ memcpy(nl.vsi_uuid, vsi->vsi, sizeof(nl.vsi_uuid)); ++ nl.filter_fmt = vsi->fif; ++ for (i = 0; i < nl.macsz; ++i) { ++ nlmac[i].vlan = vdp22_get_vlanid(vsi->fdata[i].vlan); ++ nlmac[i].qos = vdp22_get_qos(vsi->fdata[i].vlan); ++ memcpy(nlmac[i].mac, vsi->fdata[i].mac, sizeof(nlmac[i].mac)); ++ nl.req_pid = vsi->fdata[i].requestor.req_pid; ++ nl.req_seq = vsi->fdata[i].requestor.req_seq; ++ } ++ if (to) ++ nl.request -= 1; /* Maintain old number */ ++ (*fct)(&nl); ++ if (vsi->flags & VDP22_DELETE_ME) ++ vdp22_listdel_vsi(vsi); ++ return 0; ++} ++ ++/* ++ * Send information back to netlink clients. When command was received via ++ * control interface do not send back anything. ++ */ ++int vdp22_nlback(struct vsi22 *vsi) ++{ ++ pid_t nl_pid = havepid(vsi); ++ ++ LLDPAD_DBG("%s:%s vsi:%p(%#2x) nl_pid:%d\n", __func__, vsi->vdp->ifname, ++ vsi, vsi->vsi[0], nl_pid); ++ return (nl_pid) ? vdp22_back(vsi, nl_pid, vdpnl_send) : 0; ++} ++ ++/* ++ * Send information back to attached clients. When command was received via ++ * netlink message do not send back anything. ++ */ ++int vdp22_clntback(struct vsi22 *vsi) ++{ ++ pid_t nl_pid = havepid(vsi); ++ ++ LLDPAD_DBG("%s:%s vsi:%p(%#2x) nl_pid:%d\n", __func__, vsi->vdp->ifname, ++ vsi, vsi->vsi[0], nl_pid); ++ return (!nl_pid) ? vdp22_back(vsi, 0, vdp22_sendevent) : 0; ++} ++ ++/* ++ * Query role. Return error when interface not available or interface is ++ * running in bridge mode. ++ */ ++int vdp22_info(const char *ifname) ++{ ++ int rc = 0; ++ struct vdp22 *vdp = vdp22_findif(ifname, NULL); ++ ++ if (!vdp) ++ rc = -ENODEV; ++ else if (vdp->myrole == VDP22_BRIDGE) ++ rc = -EOPNOTSUPP; ++ LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); ++ return rc; ++ ++} +diff --git a/qbg/vdp22_cmds.c b/qbg/vdp22_cmds.c +new file mode 100644 +index 0000000..a75c02d +--- /dev/null ++++ b/qbg/vdp22_cmds.c +@@ -0,0 +1,489 @@ ++/******************************************************************************* ++ ++ Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2014 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++/* ++ * Command line interface for vdp22 module. Handle argument parsing and ++ * setting. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lldp.h" ++#include "lldpad.h" ++#include "lldp_mod.h" ++#include "clif_msgs.h" ++#include "libconfig.h" ++#include "config.h" ++#include "messages.h" ++#include "qbg22.h" ++#include "qbg_vdp22def.h" ++#include "qbg_vdp22.h" ++#include "qbg_vdpnl.h" ++#include "qbg_vdp22_cmds.h" ++#include "qbg_vdp22_clif.h" ++ ++/* ++ * Find module we are called for. ++ */ ++static struct lldp_module *get_my_module(int thisid) ++{ ++ struct lldp_module *np = NULL; ++ ++ LIST_FOREACH(np, &lldp_head, lldp) ++ if (thisid == np->id) ++ break; ++ return np; ++} ++ ++/* ++ * Find argument handlers for module we are called for. ++ */ ++static struct arg_handlers *get_my_arghndl(int thisid) ++{ ++ struct lldp_module *np; ++ struct arg_handlers *ah = NULL; ++ ++ np = get_my_module(thisid); ++ if (np) ++ if (np->ops && np->ops->get_arg_handler) ++ ah = np->ops->get_arg_handler(); ++ return ah; ++} ++ ++static int handle_get_arg(struct cmd *cmd, char *arg, char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ struct arg_handlers *ah; ++ int rval, status = cmd_not_applicable; ++ ++ ah = get_my_arghndl(cmd->module_id); ++ if (!ah) ++ return status; ++ for (; ah->arg; ++ah) { ++ if (!ah->handle_get) ++ continue; ++ if (!strncasecmp(ah->arg, arg, strlen(ah->arg))) { ++ rval = ah->handle_get(cmd, arg, argvalue, ++ obuf, obuf_len); ++ if (rval != cmd_success && ++ rval != cmd_not_applicable) ++ return rval; ++ else if (rval == cmd_success) ++ status = rval; ++ break; ++ } ++ } ++ return status; ++} ++ ++static int handle_get(struct cmd *cmd, UNUSED char *arg, char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ struct arg_handlers *ah; ++ int rval; ++ char *nbuf; ++ int nbuf_len; ++ ++ memset(obuf, 0, obuf_len); ++ nbuf = obuf + 12; ++ nbuf_len = obuf_len - 12; ++ ++ ah = get_my_arghndl(cmd->module_id); ++ if (!ah) ++ return cmd_not_applicable; ++ for (; ah->arg; ++ah) { ++ if (strcmp(ah->arg, ARG_VDP22_VSI)) ++ continue; ++ if (ah->handle_get && (ah->arg_class == TLV_ARG)) { ++ rval = ah->handle_get(cmd, ah->arg, argvalue, ++ nbuf, nbuf_len); ++ if (rval != cmd_success && rval != cmd_not_applicable) ++ return rval; ++ ++ nbuf_len -= strlen(nbuf); ++ nbuf = nbuf + strlen(nbuf); ++ } ++ } ++ return cmd_success; ++} ++ ++static int handle_test_arg(struct cmd *cmd, char *arg, char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ struct arg_handlers *ah; ++ int rval, status = cmd_not_applicable; ++ ++ ah = get_my_arghndl(cmd->module_id); ++ if (!ah) ++ return status; ++ for (; ah->arg; ++ah) { ++ if (!strcasecmp(ah->arg, arg) && ah->handle_test) { ++ rval = ah->handle_test(cmd, ah->arg, argvalue, ++ obuf, obuf_len); ++ if (rval != cmd_not_applicable && ++ rval != cmd_success) ++ return rval; ++ else if (rval == cmd_success) ++ status = rval; ++ break; ++ } ++ } ++ return status; ++} ++ ++static int handle_set_arg(struct cmd *cmd, char *arg, char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ struct arg_handlers *ah; ++ int rval, status = cmd_not_applicable; ++ ++ ah = get_my_arghndl(cmd->module_id); ++ if (!ah) ++ return status; ++ for (; ah->arg; ++ah) { ++ if (!strcasecmp(ah->arg, arg) && ah->handle_set) { ++ rval = ah->handle_set(cmd, ah->arg, argvalue, ++ obuf, obuf_len); ++ if (rval != cmd_not_applicable && ++ rval != cmd_success) ++ return rval; ++ else if (rval == cmd_success) ++ status = rval; ++ break; ++ } ++ } ++ return status; ++} ++ ++/* ++ * Interface function called from attached client. This client can receive ++ * events from lldpad. ++ * ++ * The command string has the following format in ascii: ++ * M000080c4C3020000001c05veth0020080c40003vsi004btext ++ * aaaaaaaabbccddddddddeefffffgghhhhhhhhiijjjkkkkllll ++ * ++ * with ++ * aaaaaaaa: 8 hex digits module identifier (which has been stripped already) ++ * bb: C for command and 2 or 3 for message version number ++ * cc: 1 for get command and 2 for set command ++ * dddddddd: 8 hex digits options, supported are op_arg, op_argval, op_conifg ++ * and op_local ++ * ee: 2 hex digit length of interface name ++ * ffff: string for interface name ++ * gg: 2 hex digit for bridge type (nearest customer bridge only) ++ * hhhhhhhh: 8 hex digit TLV identifier ++ * ii: 2 hex digit length of argument name ++ * jjj: string for argument name ++ * kkkk: 4 hex digits for length of argument value ++ * llll: argument value ++ * ++ * Note the kkkk and llll fields may show up more than once. It depends. ++ * The total input length can be used to determine the number of arguaments. ++ * ++ * The member ops of struct cmd settings depends on the invoked with ++ * -T (cmd_gettlv) -a assoc: ++ * -c key --> ops=(0x15) op_config,op_arg,op_local), numargs > 0 ++ * -c key=abc --> ops=(0x1d) op_config,op_arg,op_argval,op_local), numargs > 0 ++ * -c --> ops=0x11 (op_config,op_local), numargs = 0 ++ * without -c --> ops=0x1 (op_local), numargs = 0 ++ * ++ * Without flag op_config being set invoke a function which retrieves all ++ * TLVs for pretty printing. This is currently not supported. ++ * ++ * With flag op_config being set return all currently active VSI associations. ++ */ ++int vdp22_clif_cmd(UNUSED void *data, UNUSED struct sockaddr_un *from, ++ UNUSED socklen_t fromlen, ++ char *ibuf, int ilen, char *rbuf, int rlen) ++{ ++ struct cmd cmd; ++ u8 len, version; ++ int ioff, roff; ++ int rstatus = cmd_invalid; ++ char **args; ++ char **argvals; ++ bool test_failed = false; ++ int numargs = 0; ++ int i, offset; ++ ++ memset(&cmd, 0, sizeof(cmd)); ++ cmd.module_id = LLDP_MOD_VDP22; ++ /* Pull out the command elements of the command message */ ++ hexstr2bin(ibuf + MSG_VER, (u8 *)&version, sizeof(u8)); ++ version = version >> 4; ++ hexstr2bin(ibuf + CMD_CODE, (u8 *)&cmd.cmd, sizeof(cmd.cmd)); ++ hexstr2bin(ibuf + CMD_OPS, (u8 *)&cmd.ops, sizeof(cmd.ops)); ++ cmd.ops = ntohl(cmd.ops); ++ hexstr2bin(ibuf + CMD_IF_LEN, &len, sizeof(len)); ++ ioff = CMD_IF; ++ if (len < sizeof(cmd.ifname)) ++ memcpy(cmd.ifname, ibuf+CMD_IF, len); ++ else ++ return rstatus; ++ ++ cmd.ifname[len] = '\0'; ++ ioff += len; ++ ++ if (version == CLIF_MSG_VERSION) { ++ hexstr2bin(ibuf+ioff, &cmd.type, sizeof(cmd.type)); ++ ioff += 2 * sizeof(cmd.type); ++ } else { ++ return cmd_not_applicable; ++ } ++ ++ if (cmd.cmd == cmd_gettlv || cmd.cmd == cmd_settlv) { ++ hexstr2bin(ibuf + ioff, (u8 *)&cmd.tlvid, sizeof(cmd.tlvid)); ++ cmd.tlvid = ntohl(cmd.tlvid); ++ ioff += 2 * sizeof(cmd.tlvid); ++ if (cmd.tlvid != VDP22_ASSOC && cmd.tlvid != VDP22_DEASSOC ++ && cmd.tlvid != VDP22_PREASSOC ++ && cmd.tlvid != VDP22_PREASSOC_WITH_RR) ++ return cmd_invalid; ++ } else { ++ return cmd_not_applicable; ++ } ++ ++ if (!(cmd.ops & op_config)) ++ return cmd_invalid; ++ ++ /* Count args and argvalues */ ++ offset = ioff; ++ for (numargs = 0; (ilen - offset) > 2; numargs++) { ++ offset += 2; ++ if (ilen - offset > 0) { ++ offset++; ++ if (ilen - offset > 4) ++ offset += 4; ++ } ++ } ++ ++ args = calloc(numargs, sizeof(char *)); ++ if (!args) ++ return cmd_failed; ++ ++ argvals = calloc(numargs, sizeof(char *)); ++ if (!argvals) { ++ free(args); ++ return cmd_failed; ++ } ++ ++ if ((cmd.ops & op_arg) && (cmd.ops & op_argval)) ++ numargs = get_arg_val_list(ibuf, ilen, &ioff, args, argvals); ++ else if (cmd.ops & op_arg) ++ numargs = get_arg_list(ibuf, ilen, &ioff, args); ++ ++ snprintf(rbuf, rlen, "%c%1x%02x%08x%02x%s", ++ CMD_REQUEST, CLIF_MSG_VERSION, ++ cmd.cmd, cmd.ops, ++ (unsigned int)strlen(cmd.ifname), cmd.ifname); ++ roff = strlen(rbuf); ++ ++ /* Confirm port is a valid LLDP port */ ++ if (!get_ifidx(cmd.ifname) || !is_valid_lldp_device(cmd.ifname)) { ++ free(argvals); ++ free(args); ++ return cmd_device_not_found; ++ } ++ ++ snprintf(rbuf + roff, rlen - roff, "%08x", cmd.tlvid); ++ roff += 8; ++ if (cmd.cmd == cmd_gettlv) { ++ if (!numargs) ++ rstatus = handle_get(&cmd, NULL, NULL, ++ rbuf + strlen(rbuf), ++ rlen - strlen(rbuf)); ++ else ++ for (i = 0; i < numargs; i++) ++ rstatus = handle_get_arg(&cmd, args[i], NULL, ++ rbuf + strlen(rbuf), ++ rlen - strlen(rbuf)); ++ } else { ++ for (i = 0; i < numargs; i++) { ++ rstatus = handle_test_arg(&cmd, args[i], argvals[i], ++ rbuf + strlen(rbuf), ++ rlen - strlen(rbuf)); ++ if (rstatus != cmd_not_applicable && ++ rstatus != cmd_success) ++ test_failed = true; ++ } ++ if (!test_failed) ++ for (i = 0; i < numargs; i++) ++ rstatus = handle_set_arg(&cmd, args[i], ++ argvals[i], ++ rbuf + strlen(rbuf), ++ rlen - strlen(rbuf)); ++ } ++ ++ free(argvals); ++ free(args); ++ return rstatus; ++} ++ ++/* ++ * Trigger an event to an attached client. ++ */ ++int vdp22_sendevent(struct vdpnl_vsi *p) ++{ ++ char msg[MAX_CLIF_MSGBUF]; ++ ++ vdp_vdpnl2str(p, msg, sizeof(msg)); ++ LLDPAD_DBG("%s:%s vsi:%p(%#2x), len:%zd msg:%s\n", __func__, ++ p->ifname, p, p->vsi_uuid[0], strlen(msg), msg); ++ send_event(16, LLDP_MOD_VDP22, msg); ++ return 0; ++} ++ ++static int vdp22_cmdok(struct cmd *cmd, cmd_status expected) ++{ ++ if (cmd->cmd != expected) ++ return cmd_invalid; ++ ++ switch (cmd->module_id) { ++ case LLDP_MOD_VDP22: ++ if (cmd->type != NEAREST_CUSTOMER_BRIDGE) ++ return cmd_agent_not_supported; ++ ++ return cmd_success; ++ case INVALID_TLVID: ++ return cmd_invalid; ++ default: ++ return cmd_not_applicable; ++ } ++} ++ ++/* ++ * Test if role is station and VDP protocol supported for this interface. ++ * Needed to enable testing of possible command failure. ++ */ ++static int ifok(struct cmd *cmd) ++{ ++ cmd_status good_cmd = cmd_success; ++ ++ switch (vdp22_info(cmd->ifname)) { ++ case -ENODEV: ++ good_cmd = cmd_device_not_found; ++ break; ++ case -EOPNOTSUPP: ++ good_cmd = cmd_not_applicable; ++ break; ++ } ++ return good_cmd; ++} ++ ++static int set_arg_vsi3(struct cmd *cmd, char *argvalue, bool test, int size) ++{ ++ cmd_status good_cmd = vdp22_cmdok(cmd, cmd_settlv); ++ int rc; ++ struct vdpnl_vsi vsi; ++ struct vdpnl_mac mac[size]; ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ++ memset(&vsi, 0, sizeof(vsi)); ++ memset(&mac, 0, sizeof(mac)); ++ vsi.maclist = mac; ++ vsi.macsz = size; ++ rc = vdp_str2vdpnl(argvalue, &vsi, cmd->ifname); ++ if (rc) { ++ good_cmd = cmd_bad_params; ++ goto out; ++ } ++ if (!port_find_by_ifindex(get_ifidx(cmd->ifname))) { ++ good_cmd = cmd_device_not_found; ++ goto out; ++ } ++ good_cmd = ifok(cmd); ++ if (good_cmd != cmd_success || test) ++ goto out; ++ rc = vdp22_request(&vsi, 1); ++ if (!rc) ++ good_cmd = cmd_success; ++ else if (rc == -ENODEV) ++ good_cmd = cmd_device_not_found; ++ else ++ good_cmd = cmd_failed; ++out: ++ return good_cmd; ++} ++ ++/* ++ * Count the number of fid data fields in the argument value. ++ */ ++#define VDP22_FID_IDX 6 /* Min index of fid data */ ++static int count_fid(char *argvalue) ++{ ++ char *p = argvalue; ++ int i; ++ ++ for (i = 0; (p = strchr(p, ',')); ++i, ++p) ++ ; ++ return i + 1 - VDP22_FID_IDX; ++} ++ ++static int set_arg_vsi2(struct cmd *cmd, char *argvalue, bool test) ++{ ++ int no = count_fid(argvalue); ++ ++ if (no <= 0) ++ return -EINVAL; ++ return set_arg_vsi3(cmd, argvalue, test, no); ++} ++ ++static int set_arg_vsi(struct cmd *cmd, UNUSED char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return set_arg_vsi2(cmd, argvalue, false); ++} ++ ++static int test_arg_vsi(struct cmd *cmd, UNUSED char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return set_arg_vsi2(cmd, argvalue, true); ++} ++ ++static struct arg_handlers arg_handlers[] = { ++ { ++ .arg = ARG_VDP22_VSI, ++ .arg_class = TLV_ARG, ++ .handle_set = set_arg_vsi, ++ .handle_test = test_arg_vsi ++ }, ++ { ++ .arg = 0 ++ } ++}; ++ ++struct arg_handlers *vdp22_arg_handlers() ++{ ++ return &arg_handlers[0]; ++} +diff --git a/qbg/vdp22br.c b/qbg/vdp22br.c +new file mode 100644 +index 0000000..03bb00b +--- /dev/null ++++ b/qbg/vdp22br.c +@@ -0,0 +1,190 @@ ++/****************************************************************************** ++ ++ Implementation of VDP 2.2 bridge resource allocation simulator for LLDP ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++/* ++ * VDP22 bridge simulation code. For now return true all the time. ++ * When configured with --enable-debug option ++ * special combination of input parameters trigger errors decribed ++ * below. ++ * ++ * TODO ++ * Will be replaced by lldpad configuration file section to allow ++ * rejection and acception of VSI profiles on a configurable bases. ++ * For now this is good enough for basic state machine testing. ++ */ ++ ++#define _GNU_SOURCE ++#include ++ ++#include ++#include ++ ++#include "messages.h" ++#include "config.h" ++#include "eloop.h" ++ ++#include "qbg22.h" ++#include "qbg_vdp22.h" ++#include "qbg_utils.h" ++ ++#ifdef BUILD_DEBUG ++static unsigned char deassoc_buf[256]; ++static unsigned char ifname_buf[16]; ++static struct qbg22_imm deassoc_qbg; ++ ++static void deassoc(void *ctx, void *parm) ++{ ++ struct qbg22_imm *qbg = (struct qbg22_imm *)parm; ++ char *ifname = (char *)ctx; ++ int rc; ++ ++ rc = modules_notify(LLDP_MOD_ECP22, LLDP_MOD_VDP22, ifname, qbg); ++ LLDPAD_DBG("%s:%s leave rc:%d\n", __func__, ifname, rc); ++} ++ ++static void trigger_deassoc(struct vdp22 *vdp) ++{ ++ deassoc_qbg.data_type = VDP22_TO_ECP22; ++ deassoc_qbg.u.c.len = vdp->input_len; ++ deassoc_qbg.u.c.data = deassoc_buf; ++ memcpy(deassoc_buf, vdp->input, vdp->input_len); ++ deassoc_buf[18] = VDP22_DEASSOC << 1; /* Offset of TLV */ ++ deassoc_buf[18 + 2] = 0; ++ memcpy(ifname_buf, vdp->ifname, sizeof(ifname_buf)); ++ eloop_register_timeout(35, 0, deassoc, ifname_buf, &deassoc_qbg); ++ LLDPAD_DBG("%s:%s vdp->input_len:%d\n", __func__, vdp->ifname, ++ vdp->input_len); ++} ++ ++static void change_vlan0(struct vsi22 *p, unsigned short idx, int with_qos) ++{ ++ if (p->fif == VDP22_FFMT_MACVID) ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->type_id); ++ else ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid); ++ if (with_qos) ++ p->fdata[idx].vlan |= vdp22_set_qos(8 + (p->type_ver & 7)); ++} ++ ++static int change_fid(struct vsi22 *p) ++{ ++ unsigned short idx = p->type_ver >> 4 & 0xf; ++ ++ if (idx >= p->no_fdata) ++ return VDP22_RESP_NOADDR; ++ if (p->type_id == 204) { ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid) ++ | vdp22_set_qos(8 + (p->type_ver & 7)); ++ } else if (p->type_id == 205) { ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->type_id); ++ } else if (p->type_id == 206) { ++ p->fdata[idx].vlan = vdp22_get_vlanid(p->fdata[idx].vlan) ++ | vdp22_set_qos(8 + (p->type_ver & 7)); ++ } else if (p->type_id == 207) { ++ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid); ++ } else if (p->type_id == 208 && p->fif != VDP22_FFMT_VID) { ++ int i; ++ ++ for (i = 0; i < p->no_fdata; ++i) ++ if (!vdp22_get_vlanid(p->fdata[i].vlan)) ++ change_vlan0(p, i, idx); ++ } ++ return 0; ++} ++#endif ++ ++int vdp22br_resources(struct vsi22 *p, int *error) ++{ ++ int rc = VDP22_RESP_SUCCESS; ++ static unsigned long called; ++ ++ *error = 0; ++ ++called; ++ LLDPAD_DBG("%s:%s vsi:%p(%02x) called:%ld id:%ld\n", __func__, ++ p->vdp->ifname, p, p->vsi[0], called, p->type_id); ++ rc = (p->vsi_mode == VDP22_DEASSOC) ? VDP22_RESP_DEASSOC : ++ VDP22_RESP_SUCCESS; ++#ifdef BUILD_DEBUG ++ /* ++ * Trigger errors ++ * Typeid 199 trigger delayed bridge resource availability ++ * Typeid 200 trigger de-assoc ++ * Typeid 201 trigger de-assoc error response ++ * Typeid 202 trigger keep error response with keep bit set ++ * Typeid 203 trigger de-assoc error response with hard bit set ++ * Typeid 199-202 type_ver determines when fired. ++ * ++ * Typeid 204 replace VLAN with groupid as VLAN ID and type_ver as QoS ++ * Typeid 205 replace VLAN 0 with typeid as VLAN ID ++ * Typeid 206 replace QoS 0 with type_ver as QoS ++ * Typeid 207 replace VLAN with groupid as VLAN ID ++ * For typeid 204-207 use upper nipple of type_ver as index into fid ++ * array. ++ * ++ * Typeid 208 replace all VLAN 0 ++ * - with typeid as VLAN ID (filter format MAC/VID) ++ * - with group identifier as VLAN ID (filter format GROUP/[MAC/]VID) ++ * - use upper nibble of type_ver to indicate a QoS change (true), ++ * lower nibble of type_ver is QoS value. ++ */ ++ switch (p->type_id) { ++ case 199: ++ if (called == p->type_ver) { ++ rc = VDP22_RESP_TIMEOUT; ++ } ++ break; ++ case 200: ++ trigger_deassoc(p->vdp); ++ break; ++ case 201: ++ case 203: ++ if (called == p->type_ver) { ++ *error = VDP22_RESP_NO_RESOURCES; ++ rc = VDP22_RESP_DEASSOC; ++ if (p->type_id == 203) ++ *error |= 0x10; ++ } ++ break; ++ case 202: ++ if (called == p->type_ver) { ++ *error = VDP22_RESP_NO_VSIMGR; ++ rc = VDP22_RESP_KEEP; ++ } ++ break; ++ case 204: ++ case 205: ++ case 206: ++ case 207: ++ case 208: ++ *error = change_fid(p); ++ if (*error == VDP22_RESP_NOADDR) ++ rc = VDP22_RESP_DEASSOC; ++ break; ++ } ++#endif ++ LLDPAD_DBG("%s:%s resp_vsi_mode:%d rc:%d error:%d\n", __func__, ++ p->vdp->ifname, p->resp_vsi_mode, rc, *error); ++ return rc; ++} +diff --git a/qbg/vdp22sm.c b/qbg/vdp22sm.c +new file mode 100644 +index 0000000..d1f65b4 +--- /dev/null ++++ b/qbg/vdp22sm.c +@@ -0,0 +1,1752 @@ ++/****************************************************************************** ++ ++ Implementation of VDP 2.2 bridge and station state machines for ++ IEEE 802.1 Qbg ratified standard. ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++/* ++ * Implement the IEEE 802.1Qbg ratified standard VDP Protocol state machines. ++ */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "messages.h" ++#include "config.h" ++#include "eloop.h" ++ ++#include "qbg22.h" ++#include "qbg_vdp22.h" ++#include "qbg_utils.h" ++ ++struct vdp22_ptlv { /* Packed TLV for VDP data exchange */ ++ unsigned short head; /* TLV 16 bit header */ ++ unsigned char data[]; /* TLV Data buffer */ ++}; ++ ++enum { /* VDP22 Protocol command responses */ ++ USEC_PER_SEC = 1000000, /* Microseconds per second */ ++ VDP22_RESBIT = 0x80, /* VSI reserved bit */ ++ VDP22_ACKBIT = 0x40, /* VSI Acknowledgement bit */ ++ VDP22_KEEPBIT = 0x20, /* VSI keep error bit */ ++ VDP22_HARDBIT = 0x10, /* VSI hard error bit */ ++ VDP22_STATUS_MASK = 0x0f, /* Status mask */ ++ VDP22_STATUS_SHIFT = 0, /* Status offset */ ++}; ++ ++/* ++ * Set status code ++ */ ++static inline unsigned char make_status(int x) ++{ ++ return (x << VDP22_STATUS_SHIFT) & VDP22_STATUS_MASK; ++} ++ ++enum vdp22br_states { /* State for VDP22 bridge processing */ ++ VDP22_BR_START = 100, /* Start state */ ++ VDP22_BR_BEGIN, /* Begin state */ ++ VDP22_BR_INIT, /* Init state */ ++ VDP22_BR_PROCESS, /* Process command from station */ ++ VDP22_BR_SEND, /* Send result to station */ ++ VDP22_BR_WAITCMD, /* Wait for cmd from station */ ++ VDP22_BR_WAITCMD_2, /* End of wait for cmd from station */ ++ VDP22_BR_KEEP, /* Send keep result to station */ ++ VDP22_BR_DEASSOC, /* Send de-assoc result to station */ ++ VDP22_BR_ALIVE, /* Process keep alive from station state */ ++ VDP22_BR_DEASSOCIATED, /* Deassoc state */ ++ VDP22_BR_END /* End state */ ++}; ++ ++/* VDP22 bridge states verbatim */ ++static const char *const vdp22br_states_n[] = { ++ "unknown", ++ "VDP22_BR_BEGIN", ++ "VDP22_BR_INIT", ++ "VDP22_BR_PROCESS", ++ "VDP22_BR_SEND", ++ "VDP22_BR_WAITCMD", ++ "VDP22_BR_WAITCMD_2", ++ "VDP22_BR_KEEP", ++ "VDP22_BR_DEASSOC", ++ "VDP22_BR_ALIVE", ++ "VDP22_BR_DEASSOCIATED", ++ "VDP22_BR_END" ++}; ++ ++static inline const char *vdp22br_state_name(enum vdp22br_states x) ++{ ++ return vdp22br_states_n[x - VDP22_BR_START]; ++} ++ ++enum vdp22_states { /* VDP22 station states */ ++ VDP22_BEGIN = 1, ++ VDP22_INIT, ++ VDP22_STATION_PROC, /* Station processing */ ++ VDP22_STATION_PROCWAIT, /* Station processing, wait for reply */ ++ VDP22_STATION_PROCWAIT_2, /* Station processing, received reply */ ++ VDP22_ASSOC_NEW, ++ VDP22_ASSOC_COMPL, /* Assoc complete */ ++ VDP22_PREASSOC_NEW, ++ VDP22_WAIT_SYSCMD, ++ VDP22_WAIT_SYSCMD_2, ++ VDP22_TXMIT_KA, /* Transmit keep alive */ ++ VDP22_TXMIT_KAWAIT, /* Transmit keep alive, wait for reply */ ++ VDP22_TXMIT_KAWAIT_2, /* Transmit keep alive, received message */ ++ VDP22_TXMIT_DEASSOC, /* Transmit Deassociation */ ++ VDP22_TXMIT_DEAWAIT, /* Transmit Deassociation, wait for reply */ ++ VDP22_TXMIT_DEAWAIT_2, /* Transmit Deassociation, received reply */ ++ VDP22_END ++}; ++ ++/* VDP22 station states verbatim */ ++static const char *const vdp22_states_n[] = { ++ "unknown", ++ "VDP22_BEGIN", ++ "VDP22_INIT", ++ "VDP22_STATION_PROC", ++ "VDP22_STATION_PROCWAIT", ++ "VDP22_STATION_PROCWAIT_2", ++ "VDP22_ASSOC_NEW", ++ "VDP22_ASSOC_COMPL", ++ "VDP22_PREASSOC_NEW", ++ "VDP22_WAIT_SYSCMD", ++ "VDP22_WAIT_SYSCMD_2", ++ "VDP22_TXMIT_KA", ++ "VDP22_TXMIT_KAWAIT", ++ "VDP22_TXMIT_KAWAIT_2", ++ "VDP22_TXMIT_DEASSOC", ++ "VDP22_TXMIT_DEAWAIT", ++ "VDP22_TXMIT_DEAWAIT_2", ++ "VDP22_END" ++}; ++ ++/* ++ * Forward definition of function prototypes. ++ */ ++static void vdp22st_run(struct vsi22 *); ++static void vdp22br_run(struct vsi22 *); ++static void vdp22_station_info(struct vsi22 *); ++ ++/* ++ * Return size of packed and unpacked VSI tlv. ++ */ ++static inline size_t mgr22_tlv_sz(void) ++{ ++ return 16; ++} ++ ++static inline size_t mgr22_ptlv_sz(void) ++{ ++ return 2 + mgr22_tlv_sz(); ++} ++ ++/* Return size for each filter data format */ ++static inline size_t vsi22_fdata_sz(unsigned char fif) ++{ ++ switch (fif) { ++ case VDP22_FFMT_VID: ++ return 2; ++ case VDP22_FFMT_MACVID: ++ return 8; ++ case VDP22_FFMT_GROUPVID: ++ return 6; ++ case VDP22_FFMT_GROUPMACVID: ++ return 12; ++ } ++ return 0; ++} ++ ++static inline size_t vsi22_tlv_fifsz(struct vsi22 *vp) ++{ ++ return vp->no_fdata * vsi22_fdata_sz(vp->fif); ++} ++ ++static inline size_t vsi22_tlv_sz(struct vsi22 *vp) ++{ ++ return 23 + 2 + vsi22_tlv_fifsz(vp); ++} ++ ++static inline size_t vsi22_ptlv_sz(struct vsi22 *vp) ++{ ++ return 2 + vsi22_tlv_sz(vp); ++} ++ ++/* ++ * Extract 1, 2, 3, 4 byte integers in network byte format. ++ * Extract n bytes. ++ * Assume enough space available. ++ * Return number of bytes extracted. ++ */ ++static inline size_t extract_1o(unsigned char *data, const unsigned char *cp) ++{ ++ *data = *cp; ++ return 1; ++} ++ ++static inline size_t extract_2o(unsigned short *data, const unsigned char *cp) ++{ ++ *data = (*cp << 8) | *(cp + 1); ++ return 2; ++} ++ ++static inline size_t extract_3o(unsigned long *data, const unsigned char *cp) ++{ ++ *data = (*cp << 16) | (*(cp + 1) << 8) | *(cp + 2); ++ return 3; ++} ++ ++static inline size_t extract_4o(unsigned long *data, const unsigned char *cp) ++{ ++ *data = (*cp << 24) | (*(cp + 1) << 16) | (*(cp + 2) << 8) | *(cp + 3); ++ return 4; ++} ++static inline size_t extract_no(unsigned char *data, const unsigned char *cp, ++ const size_t len) ++{ ++ memcpy(data, cp, len); ++ return len; ++} ++ ++/* ++ * Append 1, 2, 3, 4 byte integers in network byte format. ++ * Append n bytes. ++ * Assume enough space available. ++ * Return number of bytes written. ++ */ ++static inline size_t append_1o(unsigned char *cp, const unsigned char data) ++{ ++ *cp = data; ++ return 1; ++} ++ ++static inline size_t append_2o(unsigned char *cp, const unsigned short data) ++{ ++ *cp = (data >> 8) & 0xff; ++ *(cp + 1) = data & 0xff; ++ return 2; ++} ++ ++static inline size_t append_3o(unsigned char *cp, const unsigned long data) ++{ ++ *cp = (data >> 16) & 0xff; ++ *(cp + 1) = (data >> 8) & 0xff; ++ *(cp + 2) = data & 0xff; ++ return 3; ++} ++ ++static inline size_t append_4o(unsigned char *cp, const unsigned long data) ++{ ++ *cp = (data >> 24) & 0xff; ++ *(cp + 1) = (data >> 16) & 0xff; ++ *(cp + 2) = (data >> 8) & 0xff; ++ *(cp + 3) = data & 0xff; ++ return 4; ++} ++ ++static inline size_t append_nb(unsigned char *cp, const unsigned char *data, ++ const size_t nlen) ++{ ++ memcpy(cp, data, nlen); ++ return nlen; ++} ++ ++/* ++ * Packed TLV header manipulation. ++ */ ++static inline unsigned short ptlv_head(unsigned short type, unsigned short len) ++{ ++ return (type & 0x7f) << 9 | (len & 0x1ff); ++} ++ ++static inline unsigned short ptlv_length(unsigned short header) ++{ ++ return 2 + (header & 0x1ff); ++} ++ ++static inline unsigned short ptlv_type(unsigned short header) ++{ ++ return (header >> 9) & 0x7f; ++} ++ ++/* ++ * Build a VSI tlv. ++ */ ++static size_t vsi22_2tlv_fdata(unsigned char *cp, struct fid22 *p, ++ unsigned char fif) ++{ ++ size_t nbytes = 0; ++ ++ switch (fif) { ++ case VDP22_FFMT_VID: ++ nbytes = append_2o(cp, p->vlan); ++ break; ++ case VDP22_FFMT_MACVID: ++ nbytes = append_nb(cp, p->mac, sizeof(p->mac)); ++ nbytes += append_2o(cp + nbytes, p->vlan); ++ break; ++ case VDP22_FFMT_GROUPVID: ++ nbytes = append_4o(cp, p->grpid); ++ nbytes += append_2o(cp + nbytes, p->vlan); ++ break; ++ case VDP22_FFMT_GROUPMACVID: ++ nbytes = append_4o(cp, p->grpid); ++ nbytes += append_nb(cp + nbytes, p->mac, sizeof(p->mac)); ++ nbytes += append_2o(cp + nbytes, p->vlan); ++ break; ++ } ++ return nbytes; ++} ++ ++static void vsi22_2tlv(struct vsi22 *vp, char unsigned *cp, unsigned char stat) ++{ ++ size_t offset = 0, i; ++ unsigned short head = ptlv_head(vp->vsi_mode, vsi22_tlv_sz(vp)); ++ ++ offset = append_2o(cp, head); ++ offset += append_1o(cp + offset, stat); ++ offset += append_3o(cp + offset, vp->type_id); ++ offset += append_1o(cp + offset, vp->type_ver); ++ offset += append_1o(cp + offset, vp->vsi_fmt); ++ offset += append_nb(cp + offset, vp->vsi, sizeof(vp->vsi)); ++ offset += append_1o(cp + offset, vp->fif); ++ offset += append_2o(cp + offset, vp->no_fdata); ++ for (i = 0; i < vp->no_fdata; ++i) ++ offset += vsi22_2tlv_fdata(cp + offset, &vp->fdata[i], vp->fif); ++} ++ ++static void mgr22_2tlv(struct vsi22 *vp, unsigned char *cp) ++{ ++ unsigned short head = ptlv_head(VDP22_MGRID, mgr22_tlv_sz()); ++ size_t offset; ++ ++ offset = append_2o(cp, head); ++ append_nb(cp + offset, vp->mgrid, sizeof(vp->mgrid)); ++} ++ ++/* ++ * Code for VSI station state machine ++ */ ++/* ++ * VSI ACK time out handler ++ */ ++static void vdp22st_handle_kato(UNUSED void *ctx, void *data) ++{ ++ struct vsi22 *p = data; ++ ++ LLDPAD_DBG("%s:%s timeout keep alive timer for %p(%02x)\n", ++ __func__, p->vdp->ifname, p, p->vsi[0]); ++ p->smi.kato = true; ++ vdp22st_run(p); ++} ++ ++/* ++ * Start the VSI station keep alive timer when a VSI state has been agreed upon. ++ */ ++static int vdp22st_start_katimer(struct vsi22 *p) ++{ ++ unsigned long long towait = (1 << p->vdp->vdp_rka) * 10; ++ unsigned int secs, usecs; ++ ++ secs = towait / USEC_PER_SEC; ++ usecs = towait % USEC_PER_SEC; ++ p->smi.kato = false; ++ LLDPAD_DBG("%s:%s start keep alive timer for %p(%02x) [%i,%i]\n", ++ __func__, p->vdp->ifname, p, p->vsi[0], secs, usecs); ++ return eloop_register_timeout(secs, usecs, vdp22st_handle_kato, NULL, ++ (void *)p); ++} ++ ++/* ++ * Stops the VSI ack timer ++ * Returns the number of removed handlers ++ */ ++static int vdp22st_stop_katimer(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s stop keep alive timer for %p(%02x)\n", __func__, ++ p->vdp->ifname, p, p->vsi[0]); ++ return eloop_cancel_timeout(vdp22st_handle_kato, NULL, (void *)p); ++} ++ ++/* ++ * VSI ACK time out handler ++ */ ++static void vdp22st_handle_ackto(UNUSED void *ctx, void *data) ++{ ++ struct vsi22 *p = data; ++ ++ LLDPAD_DBG("%s:%s timeout ack timer for %p(%02x) ackreceived:%d\n", ++ __func__, p->vdp->ifname, p, p->vsi[0], p->smi.ackreceived); ++ if (!p->smi.ackreceived) { ++ p->smi.kato = true; ++ vdp22st_run(p); ++ } ++} ++ ++/* ++ * Calculate VDP22 keep alive/response wait delay timeout. See 41.5.5.9. ++ */ ++static void vdp22_timeout(struct vdp22 *p, unsigned char exp, ++ unsigned int *secs, unsigned int *usecs) ++{ ++ unsigned long long towait; ++ ++ towait = (1 + 2 * p->ecp_retries) * (1 << p->ecp_rte) * 10; ++ towait += (1 << exp) * 10; ++ towait += towait / 2; ++ *secs = towait / USEC_PER_SEC; ++ *usecs = towait % USEC_PER_SEC; ++} ++ ++/* ++ * Starts the VPD22 station response wait delay timer. See 41.5.5.9. ++ */ ++static int vdp22st_start_acktimer(struct vsi22 *p) ++{ ++ unsigned int secs, usecs; ++ ++ p->smi.txmit = true; ++ p->smi.txmit_error = 0; ++ p->smi.ackreceived = false; ++ p->smi.acktimeout = false; ++ p->smi.resp_ok = false; ++ p->smi.localchg = false; ++ vdp22_timeout(p->vdp, p->vdp->vdp_rwd, &secs, &usecs); ++ LLDPAD_DBG("%s:%s start ack timer for %p(%02x) [%i,%i]\n", ++ __func__, p->vdp->ifname, p, p->vsi[0], secs, usecs); ++ return eloop_register_timeout(secs, usecs, vdp22st_handle_ackto, NULL, ++ (void *)p); ++} ++ ++/* ++ % Stops the VSI ack timer ++ * Returns the number of removed handlers ++ */ ++static int vdp22st_stop_acktimer(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s stop ack timer for %p(%02x)\n", __func__, ++ p->vdp->ifname, p, p->vsi[0]); ++ return eloop_cancel_timeout(vdp22st_handle_ackto, NULL, (void *)p); ++} ++ ++/* ++ * Station init state ++ */ ++static void vdp22st_init(struct vsi22 *vsip) ++{ ++ vsip->smi.state = VDP22_INIT; ++ vsip->status = VDP22_RESP_NONE; ++} ++ ++/* ++ * Station association new and complete state ++ */ ++static void vdp22st_assoc_compl(struct vsi22 *vsip) ++{ ++ vsip->flags &= ~VDP22_BUSY; ++ vsip->resp_vsi_mode = 0; ++} ++ ++static void vdp22st_assoc_new(struct vsi22 *vsip, enum vdp22_modes x) ++{ ++ vdp22st_assoc_compl(vsip); ++ vsip->cc_vsi_mode = x; ++} ++ ++/* ++ * Station wait system command state ++ */ ++static void vdp22st_wait_syscmd(struct vsi22 *vsip) ++{ ++ vdp22st_start_katimer(vsip); ++} ++ ++/* ++ * Station processing state, send packed tlvs to bridge. Allocate send buffer ++ * on stack and create packed TLVs. ++ */ ++static void vdp22st_process(struct vsi22 *vsi) ++{ ++ unsigned short len = mgr22_ptlv_sz() + vsi22_ptlv_sz(vsi); ++ unsigned char buf[len]; ++ struct qbg22_imm qbg; ++ ++ qbg.data_type = VDP22_TO_ECP22; ++ qbg.u.c.len = len; ++ qbg.u.c.data = buf; ++ mgr22_2tlv(vsi, buf); ++ vsi22_2tlv(vsi, buf + mgr22_ptlv_sz(), vsi->hints); ++ vsi->smi.txmit_error = modules_notify(LLDP_MOD_ECP22, LLDP_MOD_VDP22, ++ vsi->vdp->ifname, &qbg); ++ if (!vsi->smi.txmit_error) { ++ vdp22st_stop_katimer(vsi); /* Could still be running */ ++ vdp22st_start_acktimer(vsi); ++ } ++ LLDPAD_DBG("%s:%s len:%hd rc:%d\n", __func__, vsi->vdp->ifname, len, ++ vsi->smi.txmit_error); ++} ++ ++/* ++ * Station transmit deassociate state. ++ */ ++static void vdp22st_txdea(struct vsi22 *vsip) ++{ ++ vsip->vsi_mode = VDP22_DEASSOC; ++ vsip->flags |= VDP22_BUSY; ++ vdp22st_process(vsip); ++} ++ ++/* ++ * Station transmit keep alive state. ++ */ ++static void vdp22st_txka(struct vsi22 *vsip) ++{ ++ vdp22st_process(vsip); ++} ++ ++/* ++ * Station remove a VSI from the VDP22 protocol state machine. ++ * Notification of clients depends on the interface used to establish the ++ * association: ++ * 1. When through netlink interface (draft 0.2) the client is polling for some ++ * time. In this case send a netlink message only when no command pending. ++ * 2. When through attached client (draft 2.2) the client is waiting for ++ * response (time out in operation on client side) and does not poll. ++ */ ++static void vdp22st_end(struct vsi22 *vsi) ++{ ++ vdp22st_stop_acktimer(vsi); ++ vdp22st_stop_katimer(vsi); ++ LLDPAD_DBG("%s:%s vsi:%p(%02x) flags:%#lx vsi_mode:%d,%d" ++ " resp_vsi_mode:%d\n", __func__, ++ vsi->vdp->ifname, vsi, vsi->vsi[0], vsi->flags, ++ vsi->vsi_mode, vsi->cc_vsi_mode, vsi->resp_vsi_mode); ++ vsi->vsi_mode = vsi->cc_vsi_mode = VDP22_DEASSOC; ++ vsi->flags |= VDP22_DELETE_ME; ++ vsi->flags &= ~VDP22_BUSY; ++ if (vsi->flags & VDP22_NOTIFY) ++ vdp22_nlback(vsi); /* Notify netlink when no cmd pending */ ++ vdp22_clntback(vsi); /* Notify attached client */ ++} ++ ++/* ++ * Station change into a new state. ++ */ ++static void vdp22st_change_state(struct vsi22 *vsi, enum vdp22_states newstate) ++{ ++ switch (newstate) { ++ case VDP22_INIT: ++ assert(vsi->smi.state == VDP22_BEGIN); ++ break; ++ case VDP22_STATION_PROC: ++ assert(vsi->smi.state == VDP22_INIT ++ || vsi->smi.state == VDP22_WAIT_SYSCMD_2); ++ break; ++ case VDP22_STATION_PROCWAIT: ++ assert(vsi->smi.state == VDP22_STATION_PROC); ++ break; ++ case VDP22_STATION_PROCWAIT_2: ++ assert(vsi->smi.state == VDP22_STATION_PROCWAIT); ++ break; ++ case VDP22_PREASSOC_NEW: ++ assert(vsi->smi.state == VDP22_STATION_PROCWAIT_2); ++ break; ++ case VDP22_ASSOC_NEW: ++ assert(vsi->smi.state == VDP22_STATION_PROCWAIT_2); ++ break; ++ case VDP22_ASSOC_COMPL: ++ assert(vsi->smi.state == VDP22_ASSOC_NEW ++ || vsi->smi.state == VDP22_STATION_PROCWAIT_2); ++ break; ++ case VDP22_WAIT_SYSCMD: ++ assert(vsi->smi.state == VDP22_ASSOC_COMPL ++ || vsi->smi.state == VDP22_PREASSOC_NEW ++ || vsi->smi.state == VDP22_TXMIT_KAWAIT_2); ++ break; ++ case VDP22_WAIT_SYSCMD_2: ++ assert(vsi->smi.state == VDP22_WAIT_SYSCMD); ++ break; ++ case VDP22_TXMIT_KA: ++ assert(vsi->smi.state == VDP22_WAIT_SYSCMD_2); ++ break; ++ case VDP22_TXMIT_KAWAIT: ++ assert(vsi->smi.state == VDP22_TXMIT_KA); ++ break; ++ case VDP22_TXMIT_KAWAIT_2: ++ assert(vsi->smi.state == VDP22_TXMIT_KAWAIT); ++ break; ++ case VDP22_TXMIT_DEASSOC: ++ assert(vsi->smi.state == VDP22_TXMIT_KAWAIT_2); ++ break; ++ case VDP22_TXMIT_DEAWAIT: ++ assert(vsi->smi.state == VDP22_TXMIT_DEASSOC); ++ break; ++ case VDP22_TXMIT_DEAWAIT_2: ++ assert(vsi->smi.state == VDP22_TXMIT_DEAWAIT); ++ break; ++ case VDP22_END: ++ assert(vsi->smi.state == VDP22_STATION_PROCWAIT ++ || vsi->smi.state == VDP22_STATION_PROCWAIT_2 ++ || vsi->smi.state == VDP22_TXMIT_KAWAIT ++ || vsi->smi.state == VDP22_TXMIT_KAWAIT_2 ++ || vsi->smi.state == VDP22_WAIT_SYSCMD_2 ++ || vsi->smi.state == VDP22_TXMIT_DEASSOC ++ || vsi->smi.state == VDP22_TXMIT_DEAWAIT ++ || vsi->smi.state == VDP22_TXMIT_DEAWAIT_2); ++ break; ++ default: ++ LLDPAD_ERR("%s:%s VDP station machine INVALID STATE %d\n", ++ __func__, vsi->vdp->ifname, newstate); ++ } ++ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, ++ vsi->vdp->ifname, vdp22_states_n[vsi->smi.state], ++ vdp22_states_n[newstate]); ++ vsi->smi.state = newstate; ++} ++ ++/* ++ * Check for hard and soft errors. ++ */ ++static inline bool bad_error(unsigned char x) ++{ ++ return (x && (x & VDP22_KEEPBIT) == 0) ? true : false; ++} ++ ++static inline bool keep_error(unsigned char x) ++{ ++ return (x && (x & VDP22_KEEPBIT)) ? true : false; ++} ++ ++/* ++ * Return error code. Check for HARDBIT/KEEPBIT set and no error code. ++ */ ++static inline unsigned char get_error(unsigned char x) ++{ ++ return (x & VDP22_STATUS_MASK) ? x & ~(VDP22_RESBIT|VDP22_ACKBIT) : 0; ++} ++ ++/* ++ * vdp22st_move_state - advances the VDP station state machine state ++ * ++ * Switches the state machine to the next state depending on the input ++ * variables. returns true or false depending on wether the state machine ++ * can be run again with the new state or can stop at the current state. ++ */ ++static bool vdp22st_move_state(struct vsi22 *vsi) ++{ ++ enum vdp22_states newstate; ++ ++ LLDPAD_DBG("%s:%s state %s\n", __func__, vsi->vdp->ifname, ++ vdp22_states_n[vsi->smi.state]); ++ switch (vsi->smi.state) { ++ case VDP22_BEGIN: ++ vdp22st_change_state(vsi, VDP22_INIT); ++ return true; ++ case VDP22_INIT: ++ vdp22st_change_state(vsi, VDP22_STATION_PROC); ++ return true; ++ case VDP22_STATION_PROC: ++ vdp22st_change_state(vsi, VDP22_STATION_PROCWAIT); ++ return true; ++ case VDP22_STATION_PROCWAIT: ++ if (vsi->smi.txmit_error || vsi->smi.acktimeout) { ++ /* Error handover to ECP22 or no VDP22 ack */ ++ vdp22st_change_state(vsi, VDP22_END); ++ return true; ++ } ++ if (vsi->smi.ackreceived) { ++ vdp22st_change_state(vsi, VDP22_STATION_PROCWAIT_2); ++ return true; ++ } ++ return false; ++ case VDP22_STATION_PROCWAIT_2: ++ if (!vsi->smi.resp_ok /* Mismatch in response */ ++ || bad_error(vsi->status)) { /* Error without KEEP */ ++ vdp22st_change_state(vsi, VDP22_END); ++ return true; ++ } ++ if (keep_error(vsi->status)) { /* Error with KEEP on */ ++ if (vsi->resp_vsi_mode == VDP22_ASSOC) ++ newstate = VDP22_ASSOC_COMPL; ++ else ++ newstate = VDP22_END; ++ } else if (vsi->resp_vsi_mode == VDP22_PREASSOC ++ || vsi->resp_vsi_mode == VDP22_PREASSOC_WITH_RR) ++ newstate = VDP22_PREASSOC_NEW; ++ else if (vsi->resp_vsi_mode == VDP22_DEASSOC) ++ newstate = VDP22_END; ++ else ++ newstate = VDP22_ASSOC_NEW; ++ vdp22st_change_state(vsi, newstate); ++ return true; ++ case VDP22_ASSOC_NEW: ++ vdp22st_change_state(vsi, VDP22_ASSOC_COMPL); ++ return true; ++ case VDP22_ASSOC_COMPL: ++ case VDP22_PREASSOC_NEW: ++ vdp22st_change_state(vsi, VDP22_WAIT_SYSCMD); ++ return true; ++ case VDP22_WAIT_SYSCMD: ++ vdp22st_change_state(vsi, VDP22_WAIT_SYSCMD_2); ++ return true; ++ case VDP22_WAIT_SYSCMD_2: ++ if (vsi->smi.kato) { ++ vdp22st_change_state(vsi, VDP22_TXMIT_KA); ++ return true; ++ } ++ if (vsi->smi.localchg) { ++ vdp22st_change_state(vsi, VDP22_STATION_PROC); ++ return true; ++ } ++ if (vsi->smi.deassoc) { ++ vdp22st_change_state(vsi, VDP22_END); ++ return true; ++ } ++ return false; ++ case VDP22_TXMIT_KA: ++ vdp22st_change_state(vsi, VDP22_TXMIT_KAWAIT); ++ return true; ++ case VDP22_TXMIT_KAWAIT: ++ if (vsi->smi.txmit_error || vsi->smi.acktimeout) { ++ /* Error handover to ECP22 or no VDP22 ack */ ++ vdp22st_change_state(vsi, VDP22_END); ++ return true; ++ } ++ if (vsi->smi.ackreceived) { ++ vdp22st_change_state(vsi, VDP22_TXMIT_KAWAIT_2); ++ return true; ++ } ++ return false; ++ case VDP22_TXMIT_KAWAIT_2: ++ if (!vsi->smi.resp_ok /* Mismatch in response */ ++ || bad_error(vsi->status)) { /* Error without KEEP */ ++ vdp22st_change_state(vsi, VDP22_END); ++ return true; ++ } ++ if (keep_error(vsi->status) ++ && vsi->resp_vsi_mode == VDP22_ASSOC) ++ vdp22st_change_state(vsi, VDP22_TXMIT_DEASSOC); ++ else if (vsi->resp_vsi_mode == VDP22_DEASSOC) ++ vdp22st_change_state(vsi, VDP22_END); ++ else ++ vdp22st_change_state(vsi, VDP22_WAIT_SYSCMD); ++ return true; ++ case VDP22_TXMIT_DEASSOC: ++ vdp22st_change_state(vsi, VDP22_TXMIT_DEAWAIT); ++ return true; ++ case VDP22_TXMIT_DEAWAIT: ++ if (vsi->smi.txmit_error || vsi->smi.acktimeout) { ++ /* Error handover to ECP22 or no VDP22 ack */ ++ vdp22st_change_state(vsi, VDP22_END); ++ return true; ++ } ++ if (vsi->smi.ackreceived) { ++ vdp22st_change_state(vsi, VDP22_TXMIT_DEAWAIT_2); ++ return true; ++ } ++ return false; ++ case VDP22_TXMIT_DEAWAIT_2: ++ vdp22st_change_state(vsi, VDP22_END); ++ return true; ++ case VDP22_END: ++ return false; ++ } ++ return false; ++} ++ ++/* ++ * Start state machine for VSI station ++ * @vsi: pointer to currently used vsi data structure ++ * ++ * No return value ++ */ ++static void vdp22st_run(struct vsi22 *vsi) ++{ ++ vdp22st_move_state(vsi); ++ do { ++ LLDPAD_DBG("%s:%s state %s\n", __func__, ++ vsi->vdp->ifname, vdp22_states_n[vsi->smi.state]); ++ ++ switch (vsi->smi.state) { ++ case VDP22_INIT: ++ vdp22st_init(vsi); ++ break; ++ case VDP22_STATION_PROC: ++ vdp22st_process(vsi); ++ break; ++ case VDP22_STATION_PROCWAIT: ++ case VDP22_STATION_PROCWAIT_2: ++ break; ++ case VDP22_ASSOC_NEW: ++ case VDP22_PREASSOC_NEW: ++ vdp22st_assoc_new(vsi, vsi->resp_vsi_mode); ++ vdp22_clntback(vsi); ++ break; ++ case VDP22_ASSOC_COMPL: ++ vdp22st_assoc_compl(vsi); ++ break; ++ case VDP22_WAIT_SYSCMD: ++ vdp22st_wait_syscmd(vsi); ++ break; ++ case VDP22_WAIT_SYSCMD_2: ++ break; ++ case VDP22_TXMIT_KA: ++ vdp22st_txka(vsi); ++ break; ++ case VDP22_TXMIT_KAWAIT: ++ case VDP22_TXMIT_KAWAIT_2: ++ break; ++ case VDP22_TXMIT_DEASSOC: ++ vdp22st_txdea(vsi); ++ break; ++ case VDP22_TXMIT_DEAWAIT: ++ break; ++ case VDP22_TXMIT_DEAWAIT_2: ++ vdp22st_assoc_compl(vsi); ++ break; ++ case VDP22_END: ++ break; ++ default: ++ LLDPAD_DBG("%s:%s state %d unknown\n", __func__, ++ vsi->vdp->ifname, vsi->smi.state); ++ break; ++ } ++ } while (vdp22st_move_state(vsi) == true); ++ if (vsi->smi.state == VDP22_END) ++ vdp22st_end(vsi); ++} ++ ++static void vdp22_localchange_handler(UNUSED void *eloop_data, void *user_ctx) ++{ ++ struct vsi22 *vsi; ++ ++ vsi = (struct vsi22 *) user_ctx; ++ ++ if ((vsi->smi.localchg)) { ++ LLDPAD_DBG("%s:%s p->localChange %i p->ackReceived %i\n", ++ __func__, vsi->vdp->ifname, vsi->smi.localchg, ++ vsi->smi.ackreceived); ++ vdp22st_run(vsi); ++ } ++} ++ ++int vdp22_start_localchange_timer(struct vsi22 *p) ++{ ++ return eloop_register_timeout(0, 100, vdp22_localchange_handler, NULL, ++ (void *) p); ++} ++ ++/* ++ * Checks if 2 VSI records are identical. ++ * ++ * returns true if equal, false if not ++ * ++ * compares mgrid, type id, type version, id format, id and filter info format ++ * returns true if they are equal. ++ */ ++static bool vdp22_vsi_equal(struct vsi22 *p1, struct vsi22 *p2) ++{ ++ if (memcmp(p1->mgrid, p2->mgrid, sizeof(p2->mgrid))) ++ return false; ++ if (p1->type_id != p2->type_id) ++ return false; ++ if (p1->type_ver != p2->type_ver) ++ return false; ++ if (p1->vsi_fmt != p2->vsi_fmt) ++ return false; ++ if (memcmp(p1->vsi, p2->vsi, sizeof(p1->vsi))) ++ return false; ++ if (p1->fif != p2->fif) ++ return false; ++ return true; ++} ++ ++/* ++ * Find a VSI in the list of VSIs already allocated ++ * ++ * Returns pointer to already allocated VSI in list, 0 if not. ++ */ ++static struct vsi22 *vdp22_findvsi(struct vdp22 *vdp, struct vsi22 *me) ++{ ++ struct vsi22 *p; ++ ++ LIST_FOREACH(p, &vdp->vsi22_que, node) { ++ if (vdp22_vsi_equal(p, me)) ++ return p; ++ } ++ return NULL; ++} ++ ++/* ++ * Modify VSI22 information and trigger state machine. ++ * Parameter me identifies the VSI to be modified. ++ */ ++static int vdp22_modvsi(struct vsi22 *me, enum vdp22_modes x) ++{ ++ LLDPAD_DBG("%s:%s me:%p flags:%#lx mode change %d --> %d\n", __func__, ++ me->vdp->ifname, me, me->flags, me->vsi_mode, x); ++ if (me->flags & VDP22_DELETE_ME) ++ return -ENODEV; ++ if (me->vsi_mode > x) ++ return -EINVAL; ++ me->vsi_mode = x; ++ me->smi.localchg = true; ++ me->flags |= VDP22_BUSY | VDP22_NLCMD; ++ vdp22st_run(me); ++ return 0; ++} ++ ++/* ++ * Insert in queue and enter state machine. ++ */ ++static void vdp22_addvsi(struct vsi22 *vsip, struct vdp22 *vdp) ++{ ++ vsip->smi.state = VDP22_BEGIN; ++ LIST_INSERT_HEAD(&vdp->vsi22_que, vsip, node); ++ LLDPAD_DBG("%s:%s vsip:%p\n", __func__, vsip->vdp->ifname, vsip); ++ vdp22st_run(vsip); ++} ++ ++/* ++ * Compare VSI filter data. Return true if they match. ++ * All fields are compared, even if some are not used. Unused field are ++ * initialized to zeros and always match. ++ */ ++static bool cmp_fdata1(struct fid22 *p1, struct fid22 *p2, unsigned char fif) ++{ ++ bool is_good = true; ++ ++ if (fif == VDP22_FFMT_MACVID || fif == VDP22_FFMT_GROUPMACVID) ++ is_good = !memcmp(p1->mac, p2->mac, sizeof(p1->mac)); ++ if (fif == VDP22_FFMT_GROUPVID || fif == VDP22_FFMT_GROUPMACVID) ++ is_good = (p1->grpid == p2->grpid); ++ if (is_good) { ++ if (vdp22_get_vlanid(p1->vlan)) ++ is_good = (vdp22_get_vlanid(p1->vlan) == ++ vdp22_get_vlanid(p2->vlan)); ++ if (is_good && vdp22_get_ps(p1->vlan)) ++ is_good = (p1->vlan == p2->vlan); ++ } ++ return is_good; ++} ++ ++static bool vdp22_cmp_fdata(struct vsi22 *p, struct vsi22 *vsip) ++{ ++ int i; ++ ++ if (p->no_fdata != vsip->no_fdata) ++ return false; ++ for (i = 0; i < p->no_fdata; ++i) { ++ struct fid22 *p1 = &p->fdata[i]; ++ struct fid22 *p2 = &vsip->fdata[i]; ++ ++ if (!cmp_fdata1(p1, p2, p->fif)) { ++ p->status = VDP22_RESP_NOADDR; ++ return false; ++ } ++ } ++ return true; ++} ++ ++/* ++ * Update a current/existing VSI instance. ++ * The next table describes the transition diagram for the VSI instance update: ++ * ++ * Current mode ++ * New Mode | none preassoc preassoc-RR assoc ++ * ===========|================================================================= ++ * preassoc | do_preassoc do_preassoc do_preassoc error ++ * preassoc-RR| do_preassoc-RR do_preassoc-RR do_preassoc-RR error ++ * assoc | do_assoc do_assoc do_assoc do-assoc ++ * deassoc | error do_deassoc do_deassoc do-deassoc ++ * ++ * These operations get more complicated because the filter data may differ: ++ * ============================================================================= ++ * Transitions: ++ * If the filter data of the current VSI node and the new VSI node ++ * matches completely, resend TLVs ++ * ++ * TODO: ++ * If the new mode changes only part of the currently active ++ * filter data, then do: ++ * 1. Clone the filter data which is undergoing a mode change and ++ * create a new VSI node ++ * 2. Delete the filter data in the currently active VSI node. ++ * 3. Search for a VSI node with the same key and new mode: ++ * a. If such a node is found append filter data and resent TLVs ++ * b. If no such node is found, append the new VSI node with ++ * the new mode to the list of cloned VSIs. Send TLV for the ++ * new VSI node. ++ * ++ * If the key matches and the VSI mode is also identical and the filter data ++ * in the new request does not match any filter data element in the current ++ * request, then add the new filter data and resent the TLVs. ++ * ++ * Without the TODO items we currently support an exact match of the ++ * filter data information. This is the same behavior as in the currently ++ * supported IEEE 802.1 QBG draft version 0.2. ++ */ ++ ++/* ++ * Handle a new request. ++ */ ++int vdp22_addreq(struct vsi22 *vsip, struct vdp22 *vdp) ++{ ++ int rc = 0; ++ struct vsi22 *p; ++ ++ LLDPAD_DBG("%s:%s mode:%d\n", __func__, vsip->vdp->ifname, ++ vsip->vsi_mode); ++ if (vsip->vsi_mode > VDP22_DEASSOC || vsip->vsi_mode < VDP22_PREASSOC) ++ return -EINVAL; ++ p = vdp22_findvsi(vdp, vsip); ++ if (!p) { /* New VSI */ ++ if (vsip->vsi_mode == VDP22_DEASSOC) { ++ /* ++ * Disassociate of unknown VSI. Return error. ++ * Nothing to send to switch. ++ */ ++ rc = -EINVAL; ++ LLDPAD_DBG("%s:%s dis-assoc without assoc [%02x]\n", ++ __func__, vsip->vdp->ifname, vsip->vsi[0]); ++ } else ++ vdp22_addvsi(vsip, vdp); /* Add new VSI */ ++ } else { /* Profile on list --> change state */ ++ /* ++ * Request is still busy, do not accept another one. ++ */ ++ if (p->flags & VDP22_BUSY) { ++ rc = -EBUSY; ++ goto out; ++ } ++ /* ++ * Check if filter data is identical. Right now support ++ * for exact filter data is implemented (as in draft 0.2) ++ * ++ * TODO ++ * Support for different filter data information. ++ */ ++ if (!vdp22_cmp_fdata(p, vsip)) { ++ LLDPAD_DBG("%s:%s TODO mismatch filter data [%02x]\n", ++ __func__, vsip->vdp->ifname, vsip->vsi[0]); ++ rc = -EINVAL; ++ } else ++ rc = vdp22_modvsi(p, vsip->vsi_mode); ++ } ++out: ++ LLDPAD_DBG("%s:%s rc:%d\n", __func__, vsip->vdp->ifname, rc); ++ return rc; ++} ++ ++/* ++ * Test for returned filter information. ++ * Set VDP22_RETURN_VID bit in flags when VLAN id or QoS change is detected. ++ */ ++static void vdp22_cpfid(struct vsi22 *hit, struct vsi22 *from) ++{ ++ int i; ++ struct fid22 *hitm = hit->fdata, *fromm = from->fdata; ++ ++ LLDPAD_DBG("%s:%s no_fdata:%hd,%hd\n", __func__, hit->vdp->ifname, ++ from->no_fdata, hit->no_fdata); ++ if (hit->no_fdata != from->no_fdata) ++ return; ++ for (i = 0; i < hit->no_fdata; ++i, ++hitm, ++fromm) { ++ LLDPAD_DBG("%s:%s vlan:%#hx,%#hx\n", __func__, ++ hit->vdp->ifname, hitm->vlan, fromm->vlan); ++ if (hitm->vlan != fromm->vlan) { ++ hitm->vlan = fromm->vlan; ++ hit->flags |= VDP22_RETURN_VID; ++ } ++ } ++ LLDPAD_DBG("%s:%s flags:%#lx\n", __func__, hit->vdp->ifname, ++ hit->flags); ++} ++ ++/* ++ * Input from bridge side. ++ * ++ * NOTE: ++ * - Parameter vsip and associated fid data is on stack memory. ++ */ ++static void vdp22_bridge_info(struct vsi22 *vsip) ++{ ++ struct vsi22 *hit = vdp22_findvsi(vsip->vdp, vsip); ++ ++ if (!hit) { ++ LLDPAD_DBG("%s:%s station received TLV not found:\n", __func__, ++ vsip->vdp->ifname); ++ vdp22_showvsi(vsip); ++ return; ++ } ++ hit->smi.ackreceived = true; ++ hit->smi.deassoc = hit->smi.acktimeout = false; ++ vdp22st_stop_acktimer(hit); ++ hit->status = get_error(vsip->status); ++ if (!(vsip->status & VDP22_ACKBIT) && vsip->vsi_mode == VDP22_DEASSOC) { ++ /* Unsolicited de-assoc request from switch */ ++ hit->smi.deassoc = true; ++ hit->status = 0; ++ } ++ /* ++ * We have already tested some fields of the TLV. Now test the ++ * filter data. ++ */ ++ if (vdp22_cmp_fdata(hit, vsip)) { ++ hit->smi.resp_ok = true; ++ hit->resp_vsi_mode = vsip->vsi_mode; /* Take response */ ++ vdp22_cpfid(hit, vsip); /* Take filter */ ++ if (hit->cc_vsi_mode != VDP22_DEASSOC ++ && (hit->resp_vsi_mode == VDP22_DEASSOC ++ || bad_error(hit->status)) ++ && !(hit->flags & VDP22_NLCMD)) ++ hit->flags |= VDP22_NOTIFY; /* Notify originator */ ++ } ++ LLDPAD_DBG("%s:%s found:%p resp_ok:%d vsi_mode:%d,%d resp_vsi_mode:%d " ++ "flags:%#lx status:%#x deassoc:%d\n", ++ __func__, vsip->vdp->ifname, hit, hit->smi.resp_ok, ++ hit->vsi_mode, hit->cc_vsi_mode, hit->resp_vsi_mode, ++ hit->flags, hit->status, hit->smi.deassoc); ++ vdp22st_run(hit); ++} ++ ++/* ++ * vdp22 input processing from ECP22 received data. Check if data is valid ++ * and do some basic checks. ++ */ ++/* ++ * Advance to next packed tlv location. ++ */ ++static inline struct vdp22_ptlv *next_ptlv(struct vdp22_ptlv *p, ++ const unsigned short len) ++{ ++ return (struct vdp22_ptlv *)((unsigned char *)p + len); ++} ++ ++/* ++ * Convert a VDP22 packed TLV to vsi22 filter data. ++ * Return number of bytes (in input packed TLV) processed. ++ */ ++static size_t ptlv_2_fdata(struct fid22 *fidp, const unsigned char *cp, ++ const unsigned char ffmt) ++{ ++ size_t offset = 0; ++ ++ memset(fidp, 0, sizeof(*fidp)); ++ switch (ffmt) { ++ case VDP22_FFMT_VID: ++ offset = extract_2o(&fidp->vlan, cp); ++ break; ++ case VDP22_FFMT_MACVID: ++ offset = extract_no(fidp->mac, cp, sizeof(fidp->mac)); ++ offset += extract_2o(&fidp->vlan, cp + offset); ++ break; ++ case VDP22_FFMT_GROUPVID: ++ offset = extract_4o(&fidp->grpid, cp); ++ offset += extract_2o(&fidp->vlan, cp + offset); ++ break; ++ case VDP22_FFMT_GROUPMACVID: ++ offset = extract_4o(&fidp->grpid, cp); ++ offset += extract_no(fidp->mac, cp + offset, sizeof(fidp->mac)); ++ offset += extract_2o(&fidp->vlan, cp + offset); ++ break; ++ } ++ return offset; ++} ++ ++/* ++ * Bridge sends replies with ACK bit set or DEASSOC request. ++ * Station sends requests, ignore error bits, ACK bit must be cleared. ++ */ ++static inline bool response_ok(struct vsi22 *vsip) ++{ ++ if (vsip->vdp->myrole == VDP22_BRIDGE) ++ return (vsip->status & VDP22_ACKBIT) ? false : true; ++ if ((vsip->status & VDP22_ACKBIT) || ++ (!(vsip->status & VDP22_ACKBIT) && vsip->vsi_mode == VDP22_DEASSOC)) ++ return true; ++ return false; ++} ++ ++/* ++ * Convert a VDP22 packed TLV to vsi22 to struct vsi22 data format. ++ */ ++static void ptlv_2_vsi22(struct vsi22 *vsip, struct vdp22_ptlv *ptlv) ++{ ++ int i; ++ size_t offset; ++ unsigned char *cp = ptlv->data; ++ ++ offset = extract_1o(&vsip->status, cp); ++ offset += extract_3o(&vsip->type_id, cp + offset); ++ offset += extract_1o(&vsip->type_ver, cp + offset); ++ offset += extract_1o(&vsip->vsi_fmt, cp + offset); ++ offset += extract_no(vsip->vsi, cp + offset, sizeof(vsip->vsi)); ++ offset += extract_1o(&vsip->fif, cp + offset); ++ offset += extract_2o(&vsip->no_fdata, cp + offset); ++ ++ if (ptlv_length(ntohs(ptlv->head)) == vsi22_ptlv_sz(vsip) ++ && vsip->no_fdata && response_ok(vsip)) { ++ struct fid22 fid[vsip->no_fdata]; ++ ++ vsip->fdata = fid; ++ for (i = 0; i < vsip->no_fdata; ++i) ++ offset += ptlv_2_fdata(&fid[i], cp + offset, vsip->fif); ++ if (vsip->vdp->myrole == VDP22_STATION) ++ vdp22_bridge_info(vsip); ++ else ++ vdp22_station_info(vsip); ++ return; ++ } ++ LLDPAD_DBG("%s:%s TLV ignored\n", __func__, vsip->vdp->ifname); ++ vdp22_showvsi(vsip); ++} ++ ++/* ++ * Interate along the packed TLVs and extract information. Packed TLV has ++ * passed basic consistency checking. ++ */ ++static void vdp22_input(struct vdp22 *vdp) ++{ ++ struct vsi22 vsi; ++ struct vdp22_ptlv *ptlv = (struct vdp22_ptlv *)vdp->input; ++ enum vdp22_modes mode; ++ ++ LLDPAD_DBG("%s:%s input_len:%d\n", __func__, vdp->ifname, ++ vdp->input_len); ++ memset(&vsi, 0, sizeof(vsi)); ++ vsi.vdp = vdp; ++ for (; (mode = ptlv_type(ntohs(ptlv->head))) != 0; ++ ptlv = next_ptlv(ptlv, ptlv_length(ntohs(ptlv->head)))) { ++ switch (mode) { ++ default: ++ case VDP22_ENDTLV: ++ break; ++ case VDP22_MGRID: ++ memcpy(&vsi.mgrid, ptlv->data, sizeof(vsi.mgrid)); ++ break; ++ case VDP22_PREASSOC: ++ case VDP22_PREASSOC_WITH_RR: ++ case VDP22_ASSOC: ++ case VDP22_DEASSOC: ++ vsi.vsi_mode = mode; ++ ptlv_2_vsi22(&vsi, ptlv); ++ break; ++ } ++ } ++} ++ ++/* ++ * Receive data from the ECP22 module. Check for valid input data. ++ */ ++static void vdp22_ecp22in(UNUSED void *ctx, void *parm) ++{ ++ struct vdp22 *vdp = (struct vdp22 *)parm; ++ struct vdp22_ptlv *ptlv = (struct vdp22_ptlv *)vdp->input; ++ int total_len = vdp->input_len; ++ unsigned short ptlv_len; ++ ++ if (vdp->myrole == VDP22_BRIDGE && vdp->br_down) { ++ LLDPAD_DBG("%s:%s bridge down\n", __func__, vdp->ifname); ++ return; ++ } ++ /* Verify 1st TLV is a manager id TLV */ ++ if (ptlv_type(ntohs(ptlv->head)) != VDP22_MGRID) { ++ LLDPAD_ERR("%s:%s No Manager ID TLV -- packet dropped\n", ++ __func__, vdp->ifname); ++ return; ++ } ++ ptlv_len = ptlv_length(ntohs(ptlv->head)); ++ if (ptlv_len > total_len) { ++ LLDPAD_ERR("%s:%s Invalid Manager ID TLV length -- " ++ "packet dropped\n", __func__, vdp->ifname); ++ return; ++ } ++ total_len -= ptlv_len; ++ do { /* Iterrate over all packed TLVs */ ++ ptlv = (struct vdp22_ptlv *)((unsigned char *)ptlv + ptlv_len); ++ ptlv_len = ptlv_length(ntohs(ptlv->head)); ++ ++ switch (ptlv_type(ntohs(ptlv->head))) { ++ case VDP22_ENDTLV: ++ total_len = 0; ++ break; ++ case VDP22_MGRID: ++ LLDPAD_ERR("%s:%s Duplicate Manager ID TLV -- " ++ "packet dropped\n", __func__, vdp->ifname); ++ return; ++ case VDP22_PREASSOC: ++ case VDP22_PREASSOC_WITH_RR: ++ case VDP22_ASSOC: ++ case VDP22_DEASSOC: ++ if (ptlv_len > total_len) { ++ LLDPAD_ERR("%s:%s Invalid TLV length -- " ++ "packet dropped\n", __func__, ++ vdp->ifname); ++ return; ++ } ++ total_len -= ptlv_len; ++ break; ++ default: ++ LLDPAD_DBG("%s:%s Unknown TLV ID (%#hx) -- " ++ "ignored\n", __func__, vdp->ifname, ++ ptlv_type(ptlv->head)); ++ if (!ptlv_len) ++ ptlv_len = 2; /* Keep TLVs moving */ ++ total_len -= ptlv_len; ++ } ++ } while (total_len > 0); ++ ++ if (total_len < 0) { ++ LLDPAD_ERR("%s:%s Received packed TLV length error (%d)\n", ++ __func__, vdp->ifname, total_len); ++ return; ++ } ++ return vdp22_input(vdp); ++} ++ ++/* ++ * Called when ECP22 module delivers data. Wait a very short time to allow ++ * the ECP module to return its acknowledgement before data is processed. ++ */ ++int vdp22_from_ecp22(struct vdp22 *vdp) ++{ ++ return eloop_register_timeout(0, 2 * 1000, vdp22_ecp22in, NULL, vdp); ++} ++ ++/* ++ * Bridge state machine code starts here. ++ */ ++static void vdp22br_init(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, ++ p->vsi[0]); ++ p->flags = 0; ++ p->cc_vsi_mode = VDP22_DEASSOC; ++ p->resp_vsi_mode = VDP22_RESP_NONE; ++ p->smi.localchg = true; /* Change triggered by station */ ++ p->smi.kato = false; ++ p->smi.resp_ok = false; /* Response from VSI manager */ ++ /* FOLLOWING MEMBERS NOT USED BY BRIDGE STATE MACHINE */ ++ p->smi.deassoc = p->smi.acktimeout = p->smi.ackreceived = false; ++ p->smi.txmit = false; ++ p->smi.txmit_error = 0; ++} ++ ++/* ++ * VSI bridge time out handler. ++ */ ++static void vdp22br_handle_kato(UNUSED void *ctx, void *data) ++{ ++ struct vsi22 *p = data; ++ ++ LLDPAD_DBG("%s:%s timeout keep alive timer for %#02x\n", ++ __func__, p->vdp->ifname, p->vsi[0]); ++ p->smi.kato = true; ++ vdp22br_run(p); ++} ++ ++/* ++ * Starts the VSI bridge keep alive timer. ++ */ ++static int vdp22br_start_katimer(struct vsi22 *p) ++{ ++ unsigned int usecs, secs; ++ ++ p->smi.kato = false; ++ vdp22_timeout(p->vdp, p->vdp->vdp_rka, &secs, &usecs); ++ LLDPAD_DBG("%s:%s start keep alive timer for %p(%02x) [%i,%i]\n", ++ __func__, p->vdp->ifname, p, p->vsi[0], secs, usecs); ++ return eloop_register_timeout(secs, usecs, vdp22br_handle_kato, NULL, ++ (void *)p); ++} ++ ++/* ++ * Stops the bridge keep alive timer. ++ */ ++static int vdp22br_stop_katimer(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s stop keep alive timer for %p(%02x)\n", __func__, ++ p->vdp->ifname, p, p->vsi[0]); ++ return eloop_cancel_timeout(vdp22br_handle_kato, NULL, (void *)p); ++} ++ ++/* ++ * Bridge resource processing timers. ++ */ ++static void vdp22br_handle_resto(UNUSED void *ctx, void *data) ++{ ++ struct vsi22 *p = data; ++ ++ LLDPAD_DBG("%s:%s timeout resource wait delay for %p(%#02x)\n", ++ __func__, p->vdp->ifname, p, p->vsi[0]); ++ p->smi.resp_ok = true; ++ vdp22br_run(p); ++} ++ ++static int vdp22br_stop_restimer(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s stop resource wait timer for %p(%02x)\n", ++ __func__, p->vdp->ifname, p, p->vsi[0]); ++ return eloop_cancel_timeout(vdp22br_handle_resto, NULL, (void *)p); ++} ++ ++/* ++ * Start resource wait delay timer. ++ */ ++static int vdp22br_start_restimer(struct vsi22 *p) ++{ ++ unsigned long long towait = (1 << p->vdp->vdp_rwd) * 10; ++ unsigned int secs, usecs; ++ ++ p->smi.resp_ok = false; ++ p->resp_vsi_mode = VDP22_RESP_NONE; ++ secs = towait / USEC_PER_SEC; ++ usecs = towait % USEC_PER_SEC; ++ LLDPAD_DBG("%s:%s start resource wait timer for %p(%02x) [%i,%i]\n", ++ __func__, p->vdp->ifname, p, p->vsi[0], secs, usecs); ++ return eloop_register_timeout(secs, usecs, vdp22br_handle_resto, NULL, ++ (void *)p); ++} ++ ++static void vdp22br_process(struct vsi22 *p) ++{ ++ int rc, error = 0; ++ ++ LLDPAD_DBG("%s:%s vsi:%p(%02x) id:%ld\n", __func__, ++ p->vdp->ifname, p, p->vsi[0], p->type_id); ++ vdp22br_start_restimer(p); ++ p->status = 0; ++ p->resp_vsi_mode = VDP22_RESP_SUCCESS; ++ rc = vdp22br_resources(p, &error); ++ switch (rc) { ++ case VDP22_RESP_TIMEOUT: ++ break; ++ case VDP22_RESP_KEEP: ++ p->status = VDP22_KEEPBIT; ++ goto rest; ++ case VDP22_RESP_DEASSOC: ++ if (error > VDP22_STATUS_MASK) ++ p->status = VDP22_HARDBIT; ++ /* Fall through intended */ ++ case VDP22_RESP_SUCCESS: ++rest: ++ p->status |= VDP22_ACKBIT | make_status(error); ++ vdp22br_stop_restimer(p); ++ p->smi.resp_ok = true; ++ break; ++ } ++ p->resp_vsi_mode = rc; ++ LLDPAD_DBG("%s:%s resp_vsi_mode:%d status:%#x\n", __func__, ++ p->vdp->ifname, p->resp_vsi_mode, p->status); ++} ++ ++void vdp22_stop_timers(struct vsi22 *vsi) ++{ ++ vdp22st_stop_acktimer(vsi); ++ vdp22st_stop_katimer(vsi); ++} ++ ++static void vdp22br_end(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, ++ p->vsi[0]); ++ vdp22_listdel_vsi(p); ++} ++ ++/* ++ * Add a VSI to bridge state machine. ++ */ ++static void vdp22br_addvsi(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, ++ p->vsi[0]); ++ p->smi.state = VDP22_BR_BEGIN; ++ p->flags = VDP22_BUSY; ++ LIST_INSERT_HEAD(&p->vdp->vsi22_que, p, node); ++ vdp22br_run(p); ++} ++ ++/* ++ * Send a bridge reply. Allocate send buffer on stack and create packed TLVs. ++ */ ++static void vdp22br_reply(struct vsi22 *vsi) ++{ ++ unsigned short len = mgr22_ptlv_sz() + vsi22_ptlv_sz(vsi); ++ unsigned char buf[len]; ++ struct qbg22_imm qbg; ++ ++ qbg.data_type = VDP22_TO_ECP22; ++ qbg.u.c.len = len; ++ qbg.u.c.data = buf; ++ mgr22_2tlv(vsi, buf); ++ vsi22_2tlv(vsi, buf + mgr22_ptlv_sz(), vsi->status); ++ modules_notify(LLDP_MOD_ECP22, LLDP_MOD_VDP22, vsi->vdp->ifname, &qbg); ++ vsi->flags &= ~VDP22_BUSY; ++ vsi->smi.localchg = false; ++ LLDPAD_DBG("%s:%s len:%hd rc:%d\n", __func__, vsi->vdp->ifname, len, ++ vsi->smi.txmit_error); ++} ++ ++/* ++ * Send a keep status TLV as bridge reply. ++ */ ++static void vdp22br_sendack(struct vsi22 *p, unsigned char status) ++{ ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, ++ p->vsi[0]); ++ p->status = status; ++ vdp22br_reply(p); ++} ++ ++/* ++ * Send a de-associate TLV as bridge reply. ++ */ ++static void vdp22br_deassoc(struct vsi22 *p, unsigned char status) ++{ ++ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, ++ p->vsi[0]); ++ p->vsi_mode = VDP22_DEASSOC; ++ vdp22br_sendack(p, status); ++} ++ ++/* ++ * Change bridge state machine into a new state. ++ */ ++static void vdp22br_change_state(struct vsi22 *p, enum vdp22br_states new) ++{ ++ switch (new) { ++ case VDP22_BR_INIT: ++ assert(p->smi.state == VDP22_BR_BEGIN); ++ break; ++ case VDP22_BR_PROCESS: ++ assert(p->smi.state == VDP22_BR_WAITCMD_2 ++ || p->smi.state == VDP22_BR_INIT); ++ break; ++ case VDP22_BR_SEND: ++ assert(p->smi.state == VDP22_BR_PROCESS); ++ break; ++ case VDP22_BR_KEEP: ++ assert(p->smi.state == VDP22_BR_PROCESS); ++ break; ++ case VDP22_BR_DEASSOC: ++ assert(p->smi.state == VDP22_BR_PROCESS); ++ break; ++ case VDP22_BR_WAITCMD: ++ assert(p->smi.state == VDP22_BR_SEND ++ || p->smi.state == VDP22_BR_KEEP ++ || p->smi.state == VDP22_BR_ALIVE); ++ break; ++ case VDP22_BR_WAITCMD_2: ++ assert(p->smi.state == VDP22_BR_WAITCMD); ++ break; ++ case VDP22_BR_ALIVE: ++ assert(p->smi.state == VDP22_BR_WAITCMD_2); ++ break; ++ case VDP22_BR_DEASSOCIATED: ++ assert(p->smi.state == VDP22_BR_PROCESS ++ || p->smi.state == VDP22_BR_WAITCMD); ++ break; ++ case VDP22_BR_END: ++ assert(p->smi.state == VDP22_BR_DEASSOC ++ || p->smi.state == VDP22_BR_DEASSOCIATED); ++ break; ++ default: ++ LLDPAD_ERR("%s:%s VDP bridge machine INVALID STATE %d\n", ++ __func__, p->vdp->ifname, new); ++ } ++ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, ++ p->vdp->ifname, vdp22br_state_name(p->smi.state), ++ vdp22br_state_name(new)); ++ p->smi.state = new; ++} ++ ++/* ++ * vdp22br_move_state - advances the VDP bridge state machine state ++ * ++ * returns true or false ++ * ++ * Switches the state machine to the next state depending on the input ++ * variables. Returns true or false depending on wether the state machine ++ * can be run again with the new state or has to stop at the current state. ++ */ ++static bool vdp22br_move_state(struct vsi22 *p) ++{ ++ LLDPAD_DBG("%s:%s state %s\n", __func__, p->vdp->ifname, ++ vdp22br_state_name(p->smi.state)); ++ switch (p->smi.state) { ++ case VDP22_BR_BEGIN: ++ vdp22br_change_state(p, VDP22_BR_INIT); ++ return true; ++ case VDP22_BR_INIT: ++ vdp22br_change_state(p, VDP22_BR_PROCESS); ++ return true; ++ case VDP22_BR_PROCESS: ++ if (!p->smi.resp_ok) /* No resource wait response */ ++ return false; ++ /* Assumes status and error bits set accordingly */ ++ if (p->resp_vsi_mode == VDP22_RESP_NONE) { /* Timeout */ ++ if (p->cc_vsi_mode == VDP22_ASSOC) ++ vdp22br_change_state(p, VDP22_BR_KEEP); ++ else ++ vdp22br_change_state(p, VDP22_BR_DEASSOCIATED); ++ } else if (p->resp_vsi_mode == VDP22_RESP_SUCCESS) ++ vdp22br_change_state(p, VDP22_BR_SEND); ++ else if (p->resp_vsi_mode == VDP22_RESP_KEEP) ++ vdp22br_change_state(p, VDP22_BR_KEEP); ++ else ++ vdp22br_change_state(p, VDP22_BR_DEASSOC); ++ return true; ++ case VDP22_BR_SEND: ++ case VDP22_BR_KEEP: ++ vdp22br_change_state(p, VDP22_BR_WAITCMD); ++ return true; ++ case VDP22_BR_DEASSOC: ++ vdp22br_change_state(p, VDP22_BR_END); ++ return true; ++ case VDP22_BR_WAITCMD: ++ if (p->smi.localchg) { /* New station request */ ++ vdp22br_change_state(p, VDP22_BR_WAITCMD_2); ++ return true; ++ } ++ if (p->smi.kato) { /* Keep alive timeout */ ++ vdp22br_change_state(p, VDP22_BR_DEASSOCIATED); ++ return true; ++ } ++ return false; ++ case VDP22_BR_WAITCMD_2: /* Handle station msg */ ++ if (p->cc_vsi_mode == p->vsi_mode) ++ vdp22br_change_state(p, VDP22_BR_ALIVE); ++ else ++ vdp22br_change_state(p, VDP22_BR_PROCESS); ++ return true; ++ case VDP22_BR_DEASSOCIATED: ++ vdp22br_change_state(p, VDP22_BR_END); ++ return true; ++ case VDP22_BR_ALIVE: ++ vdp22br_change_state(p, VDP22_BR_WAITCMD); ++ return true; ++ case VDP22_BR_END: ++ return false; ++ default: ++ LLDPAD_DBG("%s:%s unhandled state %s\n", __func__, ++ p->vdp->ifname, vdp22br_state_name(p->smi.state)); ++ } ++ return false; ++} ++ ++/* ++ * Run bridge state machine. ++ */ ++static void vdp22br_run(struct vsi22 *p) ++{ ++ vdp22br_move_state(p); ++ do { ++ LLDPAD_DBG("%s:%s state %s\n", __func__, ++ p->vdp->ifname, ++ vdp22br_state_name(p->smi.state)); ++ ++ switch (p->smi.state) { ++ case VDP22_BR_INIT: ++ vdp22br_init(p); ++ break; ++ case VDP22_BR_PROCESS: ++ vdp22br_process(p); ++ break; ++ case VDP22_BR_SEND: ++ vdp22br_reply(p); ++ break; ++ case VDP22_BR_KEEP: ++ vdp22br_sendack(p, p->status); ++ break; ++ case VDP22_BR_DEASSOC: ++ vdp22br_deassoc(p, p->status); ++ break; ++ case VDP22_BR_WAITCMD: ++ vdp22br_start_katimer(p); ++ break; ++ case VDP22_BR_WAITCMD_2: ++ break; ++ case VDP22_BR_ALIVE: ++ vdp22br_sendack(p, VDP22_ACKBIT); ++ break; ++ case VDP22_BR_DEASSOCIATED: ++ vdp22br_deassoc(p, 0); ++ break; ++ case VDP22_BR_END: ++ vdp22br_end(p); ++ break; ++ } ++ } while (vdp22br_move_state(p) == true); ++} ++ ++/* ++ * Process the request from the station. ++ * ++ * NOTE: ++ * - Parameter vsip and associated fid data is on stack memory. ++ * - New filter information data assigned to new_fdata/new_no_fdata. ++ */ ++static void vdp22_station_info(struct vsi22 *vsip) ++{ ++ struct vdp22 *vdp = vsip->vdp; ++ struct vsi22 *hit = vdp22_findvsi(vsip->vdp, vsip); ++ ++ LLDPAD_DBG("%s:%s received VSI hit:%p\n", __func__, vdp->ifname, hit); ++ vdp22_showvsi(vsip); ++ if (!hit) { ++ if (vsip->vsi_mode == VDP22_DEASSOC) { ++ /* Nothing allocated and de-assoc --> return ack */ ++ vsip->status = VDP22_ACKBIT; ++ } else { ++ /* Create VSI & enter init state */ ++ struct vsi22 *new = vdp22_copy_vsi(vsip); ++ ++ if (new) ++ return vdp22br_addvsi(new); ++ vsip->status = VDP22_ACKBIT ++ | make_status(VDP22_RESP_NO_RESOURCES); ++ } ++ /* Send back response without state machine resources */ ++ return vdp22br_reply(vsip); ++ } ++ LLDPAD_DBG("%s:%s vsi_mode:%d flags:%#lx\n", __func__, vdp->ifname, ++ hit->vsi_mode, hit->flags); ++ if (hit->flags & VDP22_BUSY) ++ return; ++ vdp22br_stop_katimer(hit); ++ if (!vdp22_cmp_fdata(hit, vsip)) { ++ LLDPAD_DBG("%s:%s TODO mismatch filter data [%02x]\n", ++ __func__, vsip->vdp->ifname, vsip->vsi[0]); ++ return; ++ } ++ hit->smi.localchg = true; ++ hit->vsi_mode = vsip->vsi_mode; /* Take new request */ ++ vdp22br_run(hit); ++} +diff --git a/qbg/vdp_ascii.c b/qbg/vdp_ascii.c +new file mode 100644 +index 0000000..0ace562 +--- /dev/null ++++ b/qbg/vdp_ascii.c +@@ -0,0 +1,479 @@ ++/****************************************************************************** ++ ++ Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2014 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++/* ++ * Convertion function for data exchange between lldptool and lldpad. ++ * Get an ascii string and convert it to a vdpnl_vsi structure. ++ * Get a vdpnl_vsi structure and convert it to an ascii string. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "qbg_vdp22def.h" ++#include "qbg_vdp22.h" ++#include "qbg_vdpnl.h" ++#include "qbg_utils.h" ++ ++/* ++ * Check if it is a UUID and consists of hexadecimal digits and dashes only. ++ * If so convert it to UUID. ++ */ ++int vdp_str2uuid(unsigned char *to, char *buffer, size_t max) ++{ ++ unsigned int i, j = 0; ++ size_t buffer_len = strlen(buffer); ++ ++ if (strspn(buffer, "01234567890AaBbCcDdEeFf-") != buffer_len) ++ return -1; ++ memset(to, 0, max); ++ for (i = 0; i < buffer_len && j < max; i++) { ++ if (buffer[i] == '-') ++ continue; ++ if (sscanf(&buffer[i], "%02hhx", &to[j]) == 1) { ++ i++; ++ j++; ++ } ++ } ++ if (i < buffer_len) ++ return -2; /* Not enough space */ ++ return 0; ++} ++ ++/* ++ * Convert a 16byte uuid to string. Insert dashes for better readability. ++ */ ++int vdp_uuid2str(const unsigned char *p, char *dst, size_t size) ++{ ++ if (dst && size > VDP_UUID_STRLEN) { ++ snprintf(dst, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x" ++ "-%02x%02x-%02x%02x%02x%02x%02x%02x", ++ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], ++ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); ++ return 0; ++ } ++ return -1; ++} ++ ++/* ++ * Return true if string is a number between min and max. ++ */ ++static bool getnumber(char *s, unsigned int min, unsigned int max, ++ unsigned int *no) ++{ ++ char *myend; ++ ++ *no = strtol(s, &myend, 0); ++ if (s && *myend == '\0' && min <= *no && *no <= max) ++ return true; ++ return false; ++} ++ ++/* ++ * Read filter information data. The format is an ascii string: ++ * filter-data filter-format ++ * vlan 1 ++ * vlan-mac 2 ++ * vlan--group 3 ++ * vlan-mac-group 4 ++ */ ++static bool getfid(struct vdpnl_vsi *p, char *value, long idx) ++{ ++ char *delim2 = 0, *delim = strchr(value, '-'); ++ unsigned int vlan, gpid = 0; ++ int fif, i, have_mac = 1, have_gpid = 1; ++ unsigned char x[ETH_ALEN]; ++ ++ memset(x, 0, sizeof(x)); ++ if (!delim) /* No dash --> no mac, no group */ ++ have_gpid = have_mac = 0; ++ else { ++ *delim = '\0'; ++ delim2 = strchr(delim + 1, '-'); ++ if (!delim2) /* No 2nd dash --> have mac but no group */ ++ have_gpid = 0; ++ else { /* 2 dashes --> check for mac */ ++ *delim2 = '\0'; ++ if (delim + 1 == delim2) ++ /* -- means vlan and group without mac */ ++ have_mac = 0; ++ } ++ } ++ if (!getnumber(value, 0, 0xffff, &vlan)) ++ return false; ++ fif = VDP22_FFMT_VID; ++ if (have_mac) { ++ i = sscanf(delim + 1, ++ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", ++ &x[0], &x[1], &x[2], &x[3], &x[4], &x[5]); ++ if (i != ETH_ALEN) ++ return false; ++ fif = VDP22_FFMT_MACVID; ++ } ++ ++ /* Check for optional group identifier */ ++ if (have_gpid && *(delim2 + 1)) { ++ if (!getnumber(delim2 + 1, 1, ~0U, &gpid)) ++ return false; ++ fif += 2; ++ } ++ ++ /* We already have filter information data, filter format must match */ ++ if (p->filter_fmt && p->filter_fmt != fif) ++ return false; ++ p->filter_fmt = fif; ++ ++ /* Check if this mac is already in our list */ ++ for (i = 0; have_mac && i < p->macsz; ++i) { ++ if (!memcmp(x, p->maclist[i].mac, sizeof(p->maclist[i].mac))) ++ return false; ++ } ++ ++ /* Append to end of list */ ++ p->maclist[idx].vlan = vdp22_get_vlanid(vlan); ++ p->maclist[idx].qos = vdp22_get_qos(vlan); ++ p->maclist[idx].gpid = gpid; ++ memcpy(p->maclist[idx].mac, x, sizeof(p->maclist[0].mac)); ++ return true; ++} ++ ++/* ++ * Read manager identifier (max 16 bytes). Check if it is a UUID and consists ++ * of hexadecimal digits only. If so convert it to UUID. ++ */ ++static bool getmgr2id(struct vdpnl_vsi *p, char *s) ++{ ++ bool is_good; ++ size_t cnt = 0, i, slen = strlen(s); ++ char *s_old = s; ++ ++ if (vdp_str2uuid(p->vsi_mgrid2, s, sizeof(p->vsi_mgrid2)) == 0) ++ return true; ++ /* Check for alphanumeric string */ ++ for (i = 0; i < slen; ++i, ++s) ++ if (isalnum(*s)) ++ ++cnt; ++ is_good = cnt == slen && cnt < sizeof(p->vsi_mgrid2); ++ if (is_good) ++ memcpy(p->vsi_mgrid2, s_old, cnt); ++ return is_good; ++} ++ ++/* ++ * Read VSI VM hints. ++ */ ++static bool gethints(struct vdpnl_vsi *p, char *s) ++{ ++ if (!strcasecmp(s, "to")) ++ p->hints = VDP22_MIGTO; ++ else if (!strcasecmp(s, "from")) ++ p->hints = VDP22_MIGFROM; ++ else if (!strcasecmp(s, "none") || !strcasecmp(s, "-")) ++ p->hints = 0; ++ else ++ return false; ++ return true; ++} ++ ++/* ++ * Read VSI association mode. If can be followed by an error code in brackets. ++ * For vdp22 protocol the allowed words are assoc, preassoc, preassoc-rr and ++ * deassoc. ++ * For vdp draft 0.2 the allowed commands are 0, 1, 2 and 3. ++ */ ++static bool getmode(struct vdpnl_vsi *p, char *s) ++{ ++ char *myend, *bracket = strchr(s, '['); ++ int no; ++ ++ if (strlen(s) == 1) { ++ switch (*s) { ++ case '0': p->request = VDP22_PREASSOC; ++ break; ++ case '1': p->request = VDP22_PREASSOC_WITH_RR; ++ break; ++ case '2': p->request = VDP22_ASSOC; ++ break; ++ case '3': p->request = VDP22_DEASSOC; ++ break; ++ default: return false; ++ } ++ p->request -= 1; ++ p->nl_version = vdpnl_nlf1; ++ return true; ++ } ++ ++ if (bracket) { ++ *bracket = '\0'; ++ no = strtol(bracket + 1, &myend, 0); ++ if (*myend != ']') ++ return false; ++ p->response = no; ++ } ++ if (!strcasecmp(s, "assoc")) ++ p->request = VDP22_ASSOC; ++ else if (!strcasecmp(s, "preassoc")) ++ p->request = VDP22_PREASSOC; ++ else if (!strcasecmp(s, "preassoc-rr")) ++ p->request = VDP22_PREASSOC_WITH_RR; ++ else if (!strcasecmp(s, "deassoc")) ++ p->request = VDP22_DEASSOC; ++ else ++ return false; ++ p->nl_version = vdpnl_nlf2; ++ return true; ++} ++ ++/* ++ * Parse the mode parameter to create/change an VSI assoication. ++ * The format is a comma separated list of tokens: ++ * cmd,mgrid,typeid,typeidversion,vsiid,hints,fid[,fid,fid,...] ++ * with ++ * cmd := "assoc" | "deassoc" | "preassoc" | "preassoc-rr" ++ * mgrid := less or equal to 16 byte alphanumeric characters ++ * | UUID (with dashes in between) ++ * typeid := number in range of 1 - 2^24 -1 ++ * typeidversion:= number in range of 1 - 255 ++ * vsiid := UUID (with dashes in between) ++ * hints := varies between input (command) and output (event message) ++ * on input --> dash (-) | "none" | "from" | "to" ++ * on output --> response (number between 0..255) ++ * fid := vlan ++ * | vlan-mac ++ * | vlan--group ++ * | vlan-mac-group ++ * vlan := number in range of 1..2^16 -1 ++ * group := number in range of 1..2^32 - 1 ++ * mac := xx:xx:xx:xx:xx:xx ++ */ ++ ++static int str2vdpnl(char *argvalue, struct vdpnl_vsi *vsi) ++{ ++ int rc = -ENOMEM; ++ unsigned int no; ++ unsigned short idx; ++ char *cmdstring, *token; ++ ++ cmdstring = strdup(argvalue); ++ if (!cmdstring) ++ goto out_free; ++ rc = -EINVAL; ++ /* 1st field is VSI command */ ++ token = strtok(cmdstring, ","); ++ if (!token || !getmode(vsi, token)) ++ goto out_free; ++ ++ /* 2nd field is VSI Manager Identifer (16 bytes maximum) */ ++ token = strtok(NULL, ","); ++ if (!token || !getmgr2id(vsi, token)) ++ goto out_free; ++ ++ /* 3rd field is type identifier */ ++ token = strtok(NULL, ","); ++ if (!token || !getnumber(token, 0, 0xffffff, &no)) ++ goto out_free; ++ vsi->vsi_typeid = no; ++ ++ /* 4th field is type version identifier */ ++ token = strtok(NULL, ","); ++ if (!token || !getnumber(token, 0, 0xff, &no)) ++ goto out_free; ++ vsi->vsi_typeversion = no; ++ ++ /* 5th field is filter VSI UUID */ ++ token = strtok(NULL, ","); ++ if (!token || vdp_str2uuid(vsi->vsi_uuid, token, sizeof(vsi->vsi_uuid))) ++ goto out_free; ++ vsi->vsi_idfmt = VDP22_ID_UUID; ++ ++ /* 6th field is migration hints */ ++ token = strtok(NULL, ","); ++ if (!token || !gethints(vsi, token)) ++ goto out_free; ++ ++ /* ++ * 7th and remaining fields are filter information format data. ++ * All fields must have the same format. The first fid field determines ++ * the format. ++ */ ++ for (idx = 0, token = strtok(NULL, ","); token != NULL; ++ ++idx, token = strtok(NULL, ",")) { ++ if (idx < vsi->macsz && !getfid(vsi, token, idx)) ++ goto out_free; ++ } ++ ++ /* Return error if no filter information provided */ ++ if (idx) ++ rc = 0; ++out_free: ++ free(cmdstring); ++ return rc; ++} ++ ++/* ++ * Fill the vdpnl_vsi structure from the string. ++ * Allocate the maclist. Must be free'ed by caller. ++ */ ++int vdp_str2vdpnl(char *argvalue, struct vdpnl_vsi *vsi, char *ifname) ++{ ++ if (ifname) ++ strncpy(vsi->ifname, ifname, sizeof(vsi->ifname) - 1); ++ return str2vdpnl(argvalue, vsi); ++} ++ ++/* ++ * Convert VSI profile into string. Use the same format as on input. ++ * Return the number of bytes written into buffer. Return zero if not ++ * enough buffer space. This ensures an entry is complete and no partial ++ * entries are in buffer. ++ */ ++ ++/* ++ * Check if snprintf() result completely fits into buffer. ++ */ ++static char *check_and_update(size_t *total, size_t *length, char *s, int c) ++{ ++ if (c < 0) ++ return NULL; ++ *total += c; ++ if ((unsigned)c >= *length) ++ return NULL; ++ *length -= c; ++ return s + c; ++} ++ ++/* ++ * Convert VSI association to string. ++ */ ++static const char *mode2str(unsigned char x) ++{ ++ if (x == VDP22_ASSOC) ++ return "assoc"; ++ else if (x == VDP22_PREASSOC) ++ return "preassoc"; ++ else if (x == VDP22_PREASSOC_WITH_RR) ++ return "preassoc-rr"; ++ else if (x == VDP22_DEASSOC) ++ return "deassoc"; ++ return "unknown"; ++} ++ ++/* ++ * Convert filter information format into vlan[-mac][-group] string. ++ * Return the number of bytes written into buffer. Return 0 if not ++ * enough buffer space. ++ */ ++static int fid2str(char *s, size_t length, int fif, struct vdpnl_mac *p) ++{ ++ int c; ++ size_t total = 0; ++ ++ c = snprintf(s, length, "%d", vdp22_set_qos(p->qos) | ++ vdp22_set_vlanid(p->vlan)); ++ s = check_and_update(&total, &length, s, c); ++ if (!s) ++ goto out; ++ if (fif == VDP22_FFMT_MACVID || fif == VDP22_FFMT_GROUPMACVID) { ++ c = snprintf(s, length, "-%02x:%02x:%02x:%02x:%02x:%02x", ++ p->mac[0], p->mac[1], p->mac[2], p->mac[3], ++ p->mac[4], p->mac[5]); ++ s = check_and_update(&total, &length, s, c); ++ if (!s) ++ goto out; ++ } ++ if (fif == VDP22_FFMT_GROUPVID || fif == VDP22_FFMT_GROUPMACVID) { ++ c = snprintf(s, length, "-%ld", p->gpid); ++ s = check_and_update(&total, &length, s, c); ++ if (!s) ++ goto out; ++ } ++out: ++ return s ? total : 0; ++} ++ ++/* ++ * Mgrid can be a one byte number ranging from 0..255 or a 16byte long ++ * identifier. ++ */ ++static void mgrid2str(char *to, struct vdpnl_vsi *p, size_t to_len) ++{ ++ int c; ++ ++ memset(to, 0, to_len); ++ for (c = sizeof(p->vsi_mgrid2); c > 0; ) ++ if (p->vsi_mgrid2[--c]) ++ break; ++ if (c) ++ memcpy(to, p->vsi_mgrid2, sizeof(p->vsi_mgrid2)); ++ else ++ snprintf(to, to_len, "%d", p->vsi_mgrid2[0]); ++} ++ ++/* ++ * Convert a vdpnl_vsi to string. ++ */ ++int vdp_vdpnl2str(struct vdpnl_vsi *p, char *s, size_t length) ++{ ++ int c, i; ++ size_t total = 0; ++ char instance[VDP_UUID_STRLEN + 2]; ++ ++ mgrid2str(instance, p, sizeof(instance)); ++ c = snprintf(s, length, "%s,%s,%ld,%d,", ++ mode2str(p->request), instance, p->vsi_typeid, ++ p->vsi_typeversion); ++ s = check_and_update(&total, &length, s, c); ++ if (!s) ++ goto out; ++ ++ vdp_uuid2str(p->vsi_uuid, instance, sizeof(instance)); ++ c = snprintf(s, length, "%s,%d,", instance, p->response); ++ s = check_and_update(&total, &length, s, c); ++ if (!s) ++ goto out; ++ ++ /* Add Filter information data */ ++ for (i = 0; i < p->macsz; ++i) { ++ c = fid2str(s, length, p->filter_fmt, &p->maclist[i]); ++ s = check_and_update(&total, &length, s, c); ++ if (!c) ++ goto out; ++ if (p->macsz > 1 && i < p->macsz - 1) { ++ c = snprintf(s, length, ","); ++ s = check_and_update(&total, &length, s, c); ++ if (!s) ++ goto out; ++ } ++ } ++out: ++ return s ? total : 0; ++} +diff --git a/qbg/vdp_clif.c b/qbg/vdp_clif.c +new file mode 100644 +index 0000000..89f0645 +--- /dev/null ++++ b/qbg/vdp_clif.c +@@ -0,0 +1,193 @@ ++/******************************************************************************* ++ ++ Implementation of VDP according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Jens Osterkamp ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++*******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include "lldp_mod.h" ++#include "clif_msgs.h" ++#include "lldp.h" ++#include "qbg_vdp.h" ++#include "qbg_vdp_cmds.h" ++#include "qbg_vdp_clif.h" ++#include "lldp_mand_clif.h" ++ ++static const char *mode_state(int mode) ++{ ++ switch (mode) { ++ case VDP_MODE_PREASSOCIATE_WITH_RR: ++ return "Preassociated with RR"; ++ case VDP_MODE_DEASSOCIATE: ++ return "Disassociated"; ++ case VDP_MODE_ASSOCIATE: ++ return "Associated"; ++ case VDP_MODE_PREASSOCIATE: ++ return "Preassociated"; ++ default: return "unknown"; ++ } ++} ++ ++/* ++ * Print a complete VDP TLV. Data string constructed in function ++ * vdp_clif_profile(). ++ */ ++static void vdp_show_tlv(UNUSED u16 len, char *info) ++{ ++ int rc, role, enabletx, vdpbit, mode, response, mgrid, id, idver; ++ unsigned int x[16]; ++ ++ rc = sscanf(info, "%02x%02x%02x%02x%02x%02x%06x%02x", ++ &role, &enabletx, &vdpbit, &mode, &response, &mgrid, ++ &id, &idver); ++ if (rc != 3 && rc != 8) ++ return; ++ printf("Role:%s\n", role ? VAL_BRIDGE : VAL_STATION); ++ printf("\tEnabled:%s\n", enabletx ? VAL_YES : VAL_NO); ++ printf("\tVDP Bit:%s\n", vdpbit ? VAL_YES : VAL_NO); ++ if (rc == 3) /* No active VSI profile */ ++ return; ++ printf("\tMode:%d (%s)\n", mode, mode_state(mode)); ++ printf("\tMgrid:%d\n", mgrid); ++ printf("\tTypeid:%d\n", id); ++ printf("\tTypeidversion:%d\n", idver); ++ rc = sscanf(info + 20, "%02x%02x%02x%02x%02x%02x%02x%02x" ++ "%02x%02x%02x%02x%02x%02x%02x%02x", ++ &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], ++ &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], ++ &x[15]); ++ if (rc != 16) ++ return; ++ printf("\tUUID:%02x%02x%02x%02x-%02x%02x-%02x%02x" ++ "-%02x%02x-%02x%02x%02x%02x%02x%02x\n", x[0], x[1], x[2], x[3], ++ x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], ++ x[14], x[15]); ++ mode = 52; ++ rc = sscanf(info + mode, "%02x%04x", &role, &vdpbit); ++ if (rc != 2) ++ return; ++ printf("\tFilter Format:%d\n", role); ++ printf("\tEntries:%d\n", vdpbit); ++ mode += 6; ++ while (--vdpbit >= 0) { ++ rc = sscanf(info + mode, "%02x%02x%02x%02x%02x%02x%04x", ++ &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6]); ++ if (rc != 7) ++ return; ++ printf("\t\tMAC:%02x:%02x:%02x:%02x:%02x:%02x\tVlanid:%d\n", ++ x[0], x[1], x[2], x[3], x[4], x[5], x[6]); ++ mode += 16; ++ } ++} ++ ++static struct type_name_info vdp_tlv_names[] = { ++ { ++ .type = ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE, ++ .name = "VDP draft 0.2 protocol configuration", ++ .key = "vdp", ++ .print_info = vdp_show_tlv ++ }, ++ { ++ .type = INVALID_TLVID ++ } ++}; ++ ++static int vdp_print_help() ++{ ++ struct type_name_info *tn = &vdp_tlv_names[0]; ++ ++ while (tn->type != INVALID_TLVID) { ++ if (tn->key && strlen(tn->key) && tn->name) { ++ printf(" %s", tn->key); ++ if (strlen(tn->key)+3 < 8) ++ printf("\t"); ++ printf("\t: %s\n", tn->name); ++ } ++ tn++; ++ } ++ return 0; ++} ++ ++static u32 vdp_lookup_tlv_name(char *tlvid_str) ++{ ++ struct type_name_info *tn = &vdp_tlv_names[0]; ++ ++ while (tn->type != INVALID_TLVID) { ++ if (!strcasecmp(tn->key, tlvid_str)) ++ return tn->type; ++ tn++; ++ } ++ return INVALID_TLVID; ++} ++ ++static void vdp_cli_unregister(struct lldp_module *mod) ++{ ++ free(mod); ++} ++ ++/* return 1: if it printed the TLV ++ * 0: if it did not ++ */ ++static int vdp_print_tlv(u32 tlvid, u16 len, char *info) ++{ ++ struct type_name_info *tn = &vdp_tlv_names[0]; ++ ++ while (tn->type != INVALID_TLVID) { ++ if (tlvid == tn->type) { ++ printf("%s\n", tn->name); ++ if (tn->print_info) { ++ printf("\t"); ++ tn->print_info(len-4, info); ++ } ++ return 1; ++ } ++ tn++; ++ } ++ return 0; ++} ++ ++static const struct lldp_mod_ops vdp_ops_clif = { ++ .lldp_mod_register = vdp_cli_register, ++ .lldp_mod_unregister = vdp_cli_unregister, ++ .print_tlv = vdp_print_tlv, ++ .lookup_tlv_name = vdp_lookup_tlv_name, ++ .print_help = vdp_print_help, ++}; ++ ++struct lldp_module *vdp_cli_register(void) ++{ ++ struct lldp_module *mod; ++ ++ mod = malloc(sizeof(*mod)); ++ if (!mod) { ++ fprintf(stderr, "failed to malloc module data\n"); ++ return NULL; ++ } ++ mod->id = (LLDP_MOD_VDP << 8) | LLDP_VDP_SUBTYPE; ++ mod->ops = &vdp_ops_clif; ++ return mod; ++} +diff --git a/qbg/vdp_cmds.c b/qbg/vdp_cmds.c +new file mode 100644 +index 0000000..95bcfb1 +--- /dev/null ++++ b/qbg/vdp_cmds.c +@@ -0,0 +1,632 @@ ++/****************************************************************************** ++ ++ Implementation of VDP according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2010, 2012 ++ ++ Author(s): Jens Osterkamp ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "lldpad.h" ++#include "ctrl_iface.h" ++#include "lldp.h" ++#include "qbg_vdp.h" ++#include "lldp_mand_clif.h" ++#include "qbg_vdp_cmds.h" ++#include "qbg_utils.h" ++#include "lldp/ports.h" ++#include "lldp_tlv.h" ++#include "messages.h" ++#include "libconfig.h" ++#include "config.h" ++#include "clif_msgs.h" ++#include "lldpad_status.h" ++#include "lldp/states.h" ++ ++static char *check_and_update(size_t *total, size_t *length, char *s, int c) ++{ ++ if (c < 0) ++ return NULL; ++ *total += c; ++ if ((unsigned)c >= *length) ++ return NULL; ++ *length -= c; ++ return s + c; ++} ++ ++static char *print_mode(char *s, size_t length, struct vsi_profile *p) ++{ ++ int c; ++ size_t total = 0; ++ char *r = s; ++ struct mac_vlan *mac_vlan; ++ char instance[VDP_UUID_STRLEN + 2]; ++ ++ vdp_uuid2str(p->instance, instance, sizeof(instance)); ++ c = snprintf(s, length, "%d,%d,%d,%d,%s,%d", ++ p->state, p->mgrid, p->id, p->version, instance, ++ p->format); ++ s = check_and_update(&total, &length, s, c); ++ if (!s) ++ return r; ++ ++ LIST_FOREACH(mac_vlan, &p->macvid_head, entry) { ++ char macbuf[MAC_ADDR_STRLEN + 1]; ++ ++ mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); ++ c = snprintf(s, length, ",%s,%d", macbuf, mac_vlan->vlan); ++ s = check_and_update(&total, &length, s, c); ++ if (!s) ++ return r; ++ } ++ return s; ++} ++ ++static int vdp_cmdok(struct cmd *cmd, cmd_status expected) ++{ ++ if (cmd->cmd != expected) ++ return cmd_invalid; ++ ++ switch (cmd->tlvid) { ++ case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: ++ if (cmd->type != NEAREST_CUSTOMER_BRIDGE) ++ return cmd_agent_not_supported; ++ ++ return cmd_success; ++ case INVALID_TLVID: ++ return cmd_invalid; ++ default: ++ return cmd_not_applicable; ++ } ++} ++ ++static int ++get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ cmd_status good_cmd = vdp_cmdok(cmd, cmd_gettlv); ++ int value; ++ char *s; ++ char arg_path[VDP_BUF_SIZE]; ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ++ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); ++ ++ if (get_cfg(cmd->ifname, cmd->type, arg_path, &value, ++ CONFIG_TYPE_BOOL)) ++ value = false; ++ ++ if (value) ++ s = VAL_YES; ++ else ++ s = VAL_NO; ++ ++ snprintf(obuf, obuf_len, "%02zx%s%04zx%s", ++ strlen(arg), arg, strlen(s), s); ++ ++ return cmd_success; ++} ++ ++static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, ++ bool test) ++{ ++ cmd_status good_cmd = vdp_cmdok(cmd, cmd_settlv); ++ int value, err; ++ char arg_path[VDP_BUF_SIZE]; ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ++ if (!strcasecmp(argvalue, VAL_YES)) ++ value = 1; ++ else if (!strcasecmp(argvalue, VAL_NO)) ++ value = 0; ++ else ++ return cmd_invalid; ++ ++ if (test) ++ return cmd_success; ++ ++ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); ++ ++ err = set_cfg(cmd->ifname, cmd->type, arg_path, ++ &value, CONFIG_TYPE_BOOL); ++ if (err) ++ return cmd_failed; ++ ++ return cmd_success; ++ ++} ++ ++static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return _set_arg_tlvtxenable(cmd, arg, argvalue, false); ++} ++ ++static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return _set_arg_tlvtxenable(cmd, arg, argvalue, true); ++} ++ ++static int get_arg_mode(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ struct vsi_profile *np; ++ struct vdp_data *vd; ++ char mode_str[VDP_BUF_SIZE], *t = mode_str; ++ int filled = 0; ++ ++ if (cmd->cmd != cmd_gettlv) ++ return cmd_invalid; ++ ++ switch (cmd->tlvid) { ++ case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: ++ break; ++ case INVALID_TLVID: ++ return cmd_invalid; ++ default: ++ return cmd_not_applicable; ++ } ++ ++ vd = vdp_data(cmd->ifname); ++ if (!vd) { ++ LLDPAD_ERR("%s: vdp_data for %s not found !\n", ++ __func__, cmd->ifname); ++ return cmd_device_not_found; ++ } ++ ++ memset(mode_str, 0, sizeof mode_str); ++ LIST_FOREACH(np, &vd->profile_head, profile) { ++ t = print_mode(t, sizeof(mode_str) - filled, np); ++ filled = t - mode_str; ++ } ++ ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int)strlen(arg), arg, (unsigned int)strlen(mode_str), ++ mode_str); ++ return cmd_success; ++} ++ ++static void str2instance(struct vsi_profile *profile, char *buffer) ++{ ++ unsigned int i, j = 0; ++ ++ for (i = 0; i <= strlen(buffer); i++) { ++ if (buffer[i] == '-') ++ continue; ++ ++ if (sscanf(&buffer[i], "%02hhx", &profile->instance[j]) == 1) { ++ i++; ++ j++; ++ } ++ } ++} ++ ++static void vdp_fill_profile(struct vsi_profile *profile, char *buffer, ++ int field) ++{ ++ LLDPAD_DBG("%s: parsed %s\n", __func__, buffer); ++ ++ switch(field) { ++ case MODE: ++ profile->mode = atoi(buffer); ++ break; ++ case MGRID: ++ profile->mgrid = atoi(buffer); ++ break; ++ case TYPEID: ++ profile->id = atoi(buffer); ++ break; ++ case TYPEIDVERSION: ++ profile->version = atoi(buffer); ++ break; ++ case INSTANCEID: ++ str2instance(profile, buffer); ++ break; ++ case FORMAT: ++ profile->format = atoi(buffer); ++ break; ++ default: ++ LLDPAD_ERR("Unknown field in buffer !\n"); ++ break; ++ } ++} ++ ++static struct vsi_profile *vdp_parse_mode_line(char *argvalue) ++{ ++ int field; ++ char *cmdstring, *parsed; ++ struct vsi_profile *profile; ++ ++ profile = vdp_alloc_profile(); ++ if (!profile) ++ return NULL; ++ ++ cmdstring = strdup(argvalue); ++ if (!cmdstring) ++ goto out_free; ++ ++ field = 0; ++ ++ parsed = strtok(cmdstring, ","); ++ ++ while (parsed != NULL) { ++ vdp_fill_profile(profile, parsed, field); ++ field++; ++ if (field > FORMAT) ++ break; ++ parsed = strtok(NULL, ","); ++ } ++ ++ if ((field <= FORMAT) || (parsed == NULL)) ++ goto out_free; ++ ++ parsed = strtok(NULL, ","); ++ ++ while (parsed != NULL) { ++ struct mac_vlan *mac_vlan; ++ ++ mac_vlan = calloc(1, sizeof(struct mac_vlan)); ++ if (mac_vlan == NULL) ++ goto out_free; ++ ++ if (str2mac(parsed, &mac_vlan->mac[0], MAC_ADDR_LEN)) { ++ free(mac_vlan); ++ goto out_free; ++ } ++ ++ parsed = strtok(NULL, ","); ++ if (parsed == NULL) { ++ free(mac_vlan); ++ goto out_free; ++ } ++ ++ mac_vlan->vlan = atoi(parsed); ++ LIST_INSERT_HEAD(&profile->macvid_head, mac_vlan, entry); ++ profile->entries++; ++ parsed = strtok(NULL, ","); ++ } ++ ++ free(cmdstring); ++ return profile; ++ ++out_free: ++ free(cmdstring); ++ vdp_delete_profile(profile); ++ return NULL; ++} ++ ++static int _set_arg_mode(struct cmd *cmd, char *argvalue, bool test) ++{ ++ cmd_status good_cmd = vdp_cmdok(cmd, cmd_settlv); ++ struct vsi_profile *profile, *p; ++ struct vdp_data *vd; ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ++ profile = vdp_parse_mode_line(argvalue); ++ if (profile == NULL) ++ return cmd_failed; ++ ++ profile->port = port_find_by_ifindex(get_ifidx(cmd->ifname)); ++ ++ if (!profile->port) { ++ vdp_delete_profile(profile); ++ return cmd_device_not_found; ++ } ++ ++ vd = vdp_data(cmd->ifname); ++ if (!vd) { ++ vdp_delete_profile(profile); ++ return cmd_device_not_found; ++ } ++ ++ if (test) { ++ vdp_delete_profile(profile); ++ return cmd_success; ++ } ++ ++ p = vdp_add_profile(vd, profile); ++ if (profile != p) ++ vdp_delete_profile(profile); ++ ++ return cmd_success; ++} ++ ++static int set_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return _set_arg_mode(cmd, argvalue, false); ++} ++ ++static int test_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return _set_arg_mode(cmd, argvalue, true); ++} ++ ++static int get_arg_role(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ cmd_status good_cmd = vdp_cmdok(cmd, cmd_gettlv); ++ char arg_path[VDP_BUF_SIZE]; ++ const char *p; ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ++ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); ++ if (get_cfg(cmd->ifname, cmd->type, ++ arg_path, &p, CONFIG_TYPE_STRING)) ++ p = VAL_STATION; ++ ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int) strlen(arg), arg, ++ (unsigned int) strlen(p), p); ++ ++ return cmd_success; ++} ++ ++static int _set_arg_role(struct cmd *cmd, char *arg, char *argvalue, bool test) ++{ ++ cmd_status good_cmd = vdp_cmdok(cmd, cmd_settlv); ++ struct vdp_data *vd; ++ char arg_path[VDP_BUF_SIZE]; ++ ++ if (good_cmd != cmd_success) ++ return good_cmd; ++ ++ vd = vdp_data(cmd->ifname); ++ ++ if (!strcasecmp(argvalue, VAL_BRIDGE)) { ++ if (!test && vd) ++ vd->role = VDP_ROLE_BRIDGE; ++ } else if (!strcasecmp(argvalue, VAL_STATION)) { ++ if (!test && vd) ++ vd->role = VDP_ROLE_STATION; ++ } else { ++ return cmd_invalid; ++ } ++ ++ if (test) ++ return cmd_success; ++ ++ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); ++ ++ const char *p = &argvalue[0]; ++ if (set_cfg(cmd->ifname, cmd->type, arg_path, &p, CONFIG_TYPE_STRING)) ++ return cmd_failed; ++ ++ return cmd_success; ++} ++ ++static int set_arg_role(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return _set_arg_role(cmd, arg, argvalue, false); ++} ++ ++static int test_arg_role(struct cmd *cmd, char *arg, char *argvalue, ++ UNUSED char *obuf, UNUSED int obuf_len) ++{ ++ return _set_arg_role(cmd, arg, argvalue, true); ++} ++ ++static struct arg_handlers arg_handlers[] = { ++ { ++ .arg = ARG_VDP_MODE, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_mode, ++ .handle_set = set_arg_mode, ++ .handle_test = test_arg_mode ++ }, ++ { ++ .arg = ARG_VDP_ROLE, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_role, ++ .handle_set = set_arg_role, ++ .handle_test = test_arg_role ++ }, ++ { ++ .arg = ARG_TLVTXENABLE, ++ .arg_class = TLV_ARG, ++ .handle_get = get_arg_tlvtxenable, ++ .handle_set = set_arg_tlvtxenable, ++ .handle_test = test_arg_tlvtxenable ++ }, ++ { ++ .arg = 0 ++ } ++}; ++ ++struct arg_handlers *vdp_get_arg_handlers() ++{ ++ return &arg_handlers[0]; ++} ++ ++/* ++ * Interface to build information for lldptool -V vdp ++ */ ++struct tlv_info_vdp_nopp { /* VSI information without profile data */ ++ u8 oui[3]; /* OUI */ ++ u8 sub; /* Subtype */ ++ u8 role; /* Role: station or bridge */ ++ u8 enabletx; ++ u8 vdpbit_on; ++} __attribute__ ((__packed__)); ++ ++/* ++ * Flatten a profile stored as TLV and append it. Skip the first 4 bytes. ++ * They contain the OUI already stored. ++ * Returns the number of bytes added to the buffer. ++ */ ++static int add_profile(unsigned char *pdu, size_t pdusz, struct vdp_data *vdp) ++{ ++ size_t size = 0; ++ ++ if (!vdp->vdp) ++ return size; ++ size = (unsigned)TLVSIZE(vdp->vdp) - 4; ++ if (pdusz >= size) ++ memcpy(pdu, vdp->vdp->info + 4, size); ++ else { ++ LLDPAD_ERR("%s: %s buffer size too small (need %d bytes)\n", ++ __func__, vdp->ifname, TLVSIZE(vdp->vdp)); ++ return -1; ++ } ++ return size; ++} ++ ++/* ++ * Create unpacked VDP tlv for VSI profile when active. ++ */ ++static int make_vdp_tlv(unsigned char *pdu, size_t pdusz, struct vdp_data *vdp) ++{ ++ struct unpacked_tlv *tlv = (struct unpacked_tlv *)pdu; ++ struct tlv_info_vdp_nopp *vdpno; ++ size_t pduoff; ++ int rc; ++ ++ tlv->info = (unsigned char *)(tlv + 1); ++ vdpno = (struct tlv_info_vdp_nopp *)tlv->info; ++ tlv->type = ORG_SPECIFIC_TLV; ++ tlv->length = sizeof(struct tlv_info_vdp_nopp); ++ hton24(vdpno->oui, LLDP_MOD_VDP); ++ vdpno->sub = LLDP_VDP_SUBTYPE; ++ vdpno->role = vdp->role; ++ vdpno->enabletx = vdp->enabletx; ++ vdpno->vdpbit_on = vdp->vdpbit_on; ++ pduoff = sizeof(*tlv) + tlv->length; ++ pdusz -= pduoff; ++ rc = add_profile(pdu + pduoff, pdusz - pduoff, vdp); ++ if (rc > 0) { ++ tlv->length += rc; ++ rc = 0; ++ } ++ return rc; ++} ++ ++/* ++ * Flatten a VDP TLV into a byte stream. ++ */ ++static int vdp_clif_profile(char *ifname, char *rbuf, size_t rlen) ++{ ++ unsigned char pdu[VDP_BUF_SIZE]; /* Buffer for unpacked TLV */ ++ int i, c, rstatus = cmd_success; ++ size_t sum = 0; ++ struct vdp_data *vd; ++ struct unpacked_tlv *tlv = (struct unpacked_tlv *)pdu; ++ struct packed_tlv *ptlv; ++ ++ LLDPAD_DBG("%s: %s rlen:%zu\n", __func__, ifname, rlen); ++ vd = vdp_data(ifname); ++ if (!vd) ++ return cmd_device_not_found; ++ ++ if (make_vdp_tlv(pdu, sizeof pdu, vd)) ++ return cmd_failed; ++ ++ /* Convert to packed TLV */ ++ ptlv = pack_tlv(tlv); ++ if (!ptlv) ++ return cmd_failed; ++ for (i = 0; i < TLVSIZE(tlv); ++i) { ++ c = snprintf(rbuf, rlen, "%02x", ptlv->tlv[i]); ++ rbuf = check_and_update(&sum, &rlen, rbuf, c); ++ if (!rbuf) { ++ rstatus = cmd_failed; ++ break; ++ } ++ } ++ free_pkd_tlv(ptlv); ++ return rstatus; ++} ++ ++/* ++ * Module function to extract all VSI profile data on a given interface. It ++ * is invoked via 'lldptool -t -i ethx -g ncb -V vdp' without any configuration ++ * options. ++ * This function does not support arguments and its values. They are handled ++ * using the lldp_mand_cmds.c interfaces. ++ */ ++int vdp_clif_cmd(char *ibuf, UNUSED int ilen, char *rbuf, int rlen) ++{ ++ struct cmd cmd; ++ u8 len, version; ++ int c, ioff; ++ size_t roff = 0, outlen = rlen; ++ char *here; ++ int rstatus = cmd_invalid; ++ ++ /* Pull out the command elements of the command message */ ++ hexstr2bin(ibuf + MSG_VER, (u8 *)&version, sizeof(u8)); ++ version >>= 4; ++ hexstr2bin(ibuf + CMD_CODE, (u8 *)&cmd.cmd, sizeof(cmd.cmd)); ++ hexstr2bin(ibuf + CMD_OPS, (u8 *)&cmd.ops, sizeof(cmd.ops)); ++ cmd.ops = ntohl(cmd.ops); ++ hexstr2bin(ibuf + CMD_IF_LEN, &len, sizeof(len)); ++ ioff = CMD_IF; ++ if (len < sizeof(cmd.ifname)) ++ memcpy(cmd.ifname, ibuf + CMD_IF, len); ++ else ++ return cmd_failed; ++ cmd.ifname[len] = '\0'; ++ ioff += len; ++ ++ memset(rbuf, 0, rlen); ++ c = snprintf(rbuf, rlen, "%c%1x%02x%08x%02x%s", ++ CMD_REQUEST, CLIF_MSG_VERSION, cmd.cmd, cmd.ops, ++ (unsigned int)strlen(cmd.ifname), cmd.ifname); ++ here = check_and_update(&roff, &outlen, rbuf, c); ++ if (!here) ++ return cmd_failed; ++ ++ if (version == CLIF_MSG_VERSION) { ++ hexstr2bin(ibuf+ioff, &cmd.type, sizeof(cmd.type)); ++ ioff += 2 * sizeof(cmd.type); ++ } else /* Command valid only for nearest customer bridge */ ++ goto out; ++ ++ if (cmd.cmd == cmd_gettlv) { ++ hexstr2bin(ibuf+ioff, (u8 *)&cmd.tlvid, sizeof(cmd.tlvid)); ++ cmd.tlvid = ntohl(cmd.tlvid); ++ ioff += 2 * sizeof(cmd.tlvid); ++ } else ++ goto out; ++ ++ c = snprintf(here, outlen, "%08x", cmd.tlvid); ++ here = check_and_update(&roff, &outlen, here, c); ++ if (!here) ++ return cmd_failed; ++ rstatus = vdp_clif_profile(cmd.ifname, here, outlen); ++out: ++ return rstatus; ++} +diff --git a/qbg/vdpnl.c b/qbg/vdpnl.c +new file mode 100644 +index 0000000..5c0ffd4 +--- /dev/null ++++ b/qbg/vdpnl.c +@@ -0,0 +1,575 @@ ++/****************************************************************************** ++ ++ Implementation of VDP according to IEEE 802.1Qbg ++ (c) Copyright IBM Corp. 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++/* ++ * Contains netlink message parsing for VDP protocol from libvirtd or other ++ * buddies. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#include "messages.h" ++#include "qbg_vdp.h" ++#include "qbg_vdp22.h" ++#include "qbg_vdpnl.h" ++#include "qbg_utils.h" ++#include "lldp_rtnl.h" ++ ++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_VF] = { .type = NLA_U32 }, ++ [IFLA_PORT_PROFILE] = { .type = NLA_STRING }, ++ [IFLA_PORT_VSI_TYPE] = { .minlen = sizeof(struct ifla_port_vsi) }, ++ [IFLA_PORT_INSTANCE_UUID] = { .minlen = PORT_UUID_MAX, ++ .maxlen = PORT_UUID_MAX, }, ++ [IFLA_PORT_HOST_UUID] = { .minlen = PORT_UUID_MAX, ++ .maxlen = PORT_UUID_MAX, }, ++ [IFLA_PORT_REQUEST] = { .type = NLA_U8 }, ++ [IFLA_PORT_RESPONSE] = { .type = NLA_U16 }, ++}; ++ ++static void vdpnl_show(struct vdpnl_vsi *vsi) ++{ ++ char instance[VDP_UUID_STRLEN + 2]; ++ struct vdpnl_mac *mac; ++ int i; ++ ++ LLDPAD_DBG("%s:IFLA_IFNAME:%s index:%d\n", __func__, vsi->ifname, ++ vsi->ifindex); ++ for (i = 0, mac = vsi->maclist; i < vsi->macsz; ++i, ++mac) { ++ LLDPAD_DBG("%s:IFLA_VF_MAC:%2x:%2x:%2x:%2x:%2x:%2x\n", ++ __func__, mac->mac[0], mac->mac[1], mac->mac[2], ++ mac->mac[3], mac->mac[4], mac->mac[5]); ++ LLDPAD_DBG("%s:IFLA_VF_VLAN:%d QOS:%d\n", __func__, mac->vlan, ++ mac->qos); ++ } ++ LLDPAD_DBG("%s:IFLA_PORT_VSI_TYPE:mgr_id:%d type_id:%ld " ++ "typeid_version:%d\n", ++ __func__, vsi->vsi_mgrid, vsi->vsi_typeid, ++ vsi->vsi_typeversion); ++ vdp_uuid2str(vsi->vsi_uuid, instance, sizeof(instance)); ++ LLDPAD_DBG("%s:IFLA_PORT_INSTANCE_UUID:%s\n", __func__, instance); ++ LLDPAD_DBG("%s:IFLA_PORT_REQUEST:%d\n", __func__, vsi->request); ++ LLDPAD_DBG("%s:IFLA_PORT_RESPONSE:%d\n", __func__, vsi->response); ++} ++ ++/* ++ * Parse the IFLA_IFLA_VF_PORTIFLA_VF_PORTS block of the netlink message. ++ * Return zero on success and errno else. ++ */ ++static int vdpnl_vfports(struct nlattr *vfports, struct vdpnl_vsi *vsi) ++{ ++ char instance[VDP_UUID_STRLEN + 2]; ++ struct nlattr *tb_vf_ports, *tb3[IFLA_PORT_MAX + 1]; ++ int rem; ++ ++ if (!vfports) { ++ LLDPAD_DBG("%s:FOUND NO IFLA_VF_PORTS\n", __func__); ++ return -EINVAL; ++ } ++ ++ nla_for_each_nested(tb_vf_ports, vfports, rem) { ++ if (nla_type(tb_vf_ports) != IFLA_VF_PORT) { ++ LLDPAD_DBG("%s:not a IFLA_VF_PORT skipping\n", ++ __func__); ++ continue; ++ } ++ if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports, ++ ifla_port_policy)) { ++ LLDPAD_ERR("%s:IFLA_PORT_MAX parsing failed\n", ++ __func__); ++ return -EINVAL; ++ } ++ if (tb3[IFLA_PORT_VF]) ++ LLDPAD_DBG("%s:IFLA_PORT_VF:%d\n", __func__, ++ *(uint32_t *) RTA_DATA(tb3[IFLA_PORT_VF])); ++ if (tb3[IFLA_PORT_PROFILE]) ++ LLDPAD_DBG("%s:IFLA_PORT_PROFILE:%s\n", __func__, ++ (char *)RTA_DATA(tb3[IFLA_PORT_PROFILE])); ++ if (tb3[IFLA_PORT_HOST_UUID]) { ++ unsigned char *uuid; ++ ++ uuid = (unsigned char *) ++ RTA_DATA(tb3[IFLA_PORT_HOST_UUID]); ++ vdp_uuid2str(uuid, instance, sizeof(instance)); ++ LLDPAD_DBG("%s:IFLA_PORT_HOST_UUID:%s\n", __func__, ++ instance); ++ } ++ 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]; ++ vsi->vsi_mgrid = pvsi->vsi_mgr_id; ++ vsi->vsi_typeversion = pvsi->vsi_type_version; ++ vsi->vsi_typeid = tid; ++ } ++ if (tb3[IFLA_PORT_INSTANCE_UUID]) { ++ unsigned char *uuid = (unsigned char *) ++ RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]); ++ memcpy(vsi->vsi_uuid, uuid, sizeof vsi->vsi_uuid); ++ } ++ if (tb3[IFLA_PORT_REQUEST]) ++ vsi->request = ++ *(uint8_t *) RTA_DATA(tb3[IFLA_PORT_REQUEST]); ++ if (tb3[IFLA_PORT_RESPONSE]) ++ vsi->response = ++ *(uint16_t *) RTA_DATA(tb3[IFLA_PORT_RESPONSE]); ++ } ++ return 0; ++} ++ ++/* ++ * Parse the IFLA_VFINFO_LIST block of the netlink message. ++ * Return zero on success and errno else. ++ */ ++static int vdpnl_vfinfolist(struct nlattr *vfinfolist, struct vdpnl_vsi *vsi) ++{ ++ struct nlattr *le1, *vf[IFLA_VF_MAX + 1]; ++ int rem; ++ ++ if (!vfinfolist) { ++ LLDPAD_ERR("%s:IFLA_VFINFO_LIST missing\n", __func__); ++ return -EINVAL; ++ } ++ nla_for_each_nested(le1, vfinfolist, rem) { ++ bool have_mac = false, have_vid = false; ++ ++ if (nla_type(le1) != IFLA_VF_INFO) { ++ LLDPAD_ERR("%s:parsing of IFLA_VFINFO_LIST failed\n", ++ __func__); ++ return -EINVAL; ++ } ++ if (nla_parse_nested(vf, IFLA_VF_MAX, le1, ifla_vf_policy)) { ++ LLDPAD_ERR("%s:parsing of IFLA_VF_INFO failed\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ if (vf[IFLA_VF_MAC]) { ++ struct ifla_vf_mac *mac = RTA_DATA(vf[IFLA_VF_MAC]); ++ ++ memcpy(vsi->maclist->mac, mac->mac, ETH_ALEN); ++ have_mac = true; ++ } ++ ++ if (vf[IFLA_VF_VLAN]) { ++ struct ifla_vf_vlan *vlan = RTA_DATA(vf[IFLA_VF_VLAN]); ++ ++ vsi->maclist->vlan = vlan->vlan; ++ vsi->maclist->qos = vlan->qos; ++ have_vid = true; ++ } ++ LLDPAD_DBG("%s:have_vid:%d have_mac:%d\n", __func__, have_vid, ++ have_mac); ++ if (have_vid && have_mac) ++ vsi->filter_fmt = VDP22_FFMT_MACVID; ++ else if (have_vid) ++ vsi->filter_fmt = VDP22_FFMT_VID; ++ else ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ++ * Convert the SETLINK message into internal data structure. ++ */ ++static int vdpnl_set(struct nlmsghdr *nlh, struct vdpnl_vsi *vsi) ++{ ++ struct nlattr *tb[IFLA_MAX + 1]; ++ struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh); ++ int rc; ++ ++ if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), ++ (struct nlattr **)&tb, IFLA_MAX, NULL)) { ++ LLDPAD_ERR("%s:error parsing SETLINK request\n", __func__); ++ return -EINVAL; ++ } ++ ++ vsi->ifindex = ifinfo->ifi_index; ++ if (tb[IFLA_IFNAME]) ++ strncpy(vsi->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), ++ sizeof vsi->ifname); ++ else { ++ if (!if_indextoname(ifinfo->ifi_index, vsi->ifname)) { ++ LLDPAD_ERR("%s:can not find name for interface %i\n", ++ __func__, ifinfo->ifi_index); ++ return -ENXIO; ++ } ++ } ++ vsi->req_pid = nlh->nlmsg_pid; ++ vsi->req_seq = nlh->nlmsg_seq; ++ rc = vdpnl_vfinfolist(tb[IFLA_VFINFO_LIST], vsi); ++ if (!rc) { ++ rc = vdpnl_vfports(tb[IFLA_VF_PORTS], vsi); ++ if (!rc) ++ vdpnl_show(vsi); ++ } ++ return rc; ++} ++ ++/* ++ * Return the error code (can be zero) to the sender. Assume buffer is ++ * large enough to hold the information. ++ * Construct the netlink response on the input buffer. ++ */ ++static int vdpnl_error(int err, struct nlmsghdr *from, size_t len) ++{ ++ struct nlmsgerr nlmsgerr; ++ ++ LLDPAD_DBG("%s:error %d\n", __func__, err); ++ nlmsgerr.error = err; ++ nlmsgerr.msg = *from; ++ memset(from, 0, len); ++ from->nlmsg_type = NLMSG_ERROR; ++ from->nlmsg_seq = nlmsgerr.msg.nlmsg_seq; ++ from->nlmsg_pid = nlmsgerr.msg.nlmsg_pid; ++ from->nlmsg_flags = 0; ++ from->nlmsg_len = NLMSG_SPACE(sizeof nlmsgerr); ++ memcpy(NLMSG_DATA(from), &nlmsgerr, sizeof nlmsgerr); ++ return from->nlmsg_len; ++} ++ ++/* ++ * Build the variable part of the netlink reply message for status inquiry. ++ * It contains the UUID and the response field for the VSI profile. ++ */ ++static void vdpnl_reply2(struct vdpnl_vsi *p, struct nl_msg *nlh) ++{ ++ char instance[VDP_UUID_STRLEN + 2]; ++ ++ nla_put(nlh, IFLA_PORT_INSTANCE_UUID, sizeof p->vsi_uuid, ++ p->vsi_uuid); ++ vdp_uuid2str(p->vsi_uuid, instance, sizeof instance); ++ LLDPAD_DBG("%s:IFLA_PORT_INSTANCE_UUID:%s\n", __func__, instance); ++ nla_put_u32(nlh, IFLA_PORT_VF, PORT_SELF_VF); ++ LLDPAD_DBG("%s:IFLA_PORT_VF:%d\n", __func__, PORT_SELF_VF); ++ if (p->response != VDP_RESPONSE_NO_RESPONSE) { ++ nla_put_u16(nlh, IFLA_PORT_RESPONSE, p->response); ++ LLDPAD_DBG("%s:IFLA_PORT_RESPONSE:%d\n", __func__, ++ p->response); ++ } ++} ++ ++/* ++ * Return bytes needed for one VSI in a netlink message. ++ */ ++static size_t vdp_nllen(void) ++{ ++ size_t needed; ++ ++ needed = nla_total_size(sizeof(struct nlattr)) /* IFLA_VF_PORT */ ++ + nla_total_size(4); /* IFLA_PORT_VF */ ++ + nla_total_size(PORT_UUID_MAX); /* IFLA_PORT_INSTANCE_UUID */ ++ + nla_total_size(2); /* IFLA_PORT_RESPONSE */ ++ return needed; ++} ++ ++/* ++ * Get interface name (either from netlink message for from ifi_index). ++ * Return error when no interface available. ++ */ ++static int vdpnl_ifname(struct vdpnl_vsi *p, struct nlattr *tb) ++{ ++ int rc = 0; ++ ++ if (tb) ++ nla_strlcpy(p->ifname, tb, sizeof(p->ifname)); ++ else if (!if_indextoname(p->ifindex, p->ifname)) { ++ LLDPAD_ERR("%s:ifindex %d without interface name\n", __func__, ++ p->ifindex); ++ rc = -EINVAL; ++ } ++ return rc; ++} ++ ++/* ++ * Parse a received netlink request message and return a filled VSI data ++ * structure. ++ */ ++static struct nla_policy pc_max[IFLA_MAX + 1] = { ++ [IFLA_IFNAME] = { ++ .minlen = 1, ++ .maxlen = IFNAMSIZ + 1, ++ .type = NLA_STRING ++ } ++}; ++ ++/* ++ * Retrieve name of interface and its index value from the netlink messaage ++ * and store it in the data structure. ++ * The GETLINK message may or may not contain the IFLA_IFNAME attribute. ++ * Return 0 on success and errno on error. ++ */ ++static int vdpnl_get(struct vdpnl_vsi *p, struct nlmsghdr *nlh) ++{ ++ int rc; ++ struct nlattr *tb[IFLA_MAX + 1]; ++ struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh); ++ ++ memset(tb, 0, sizeof(tb)); ++ rc = nla_parse(tb, sizeof(tb) / sizeof(tb[0]), ++ (struct nlattr *)IFLA_RTA(NLMSG_DATA(nlh)), ++ IFLA_PAYLOAD(nlh), pc_max); ++ if (rc) { ++ LLDPAD_ERR("%s:error parsing GETLINK request\n", __func__); ++ return -EINVAL; ++ } ++ p->ifindex = ifinfo->ifi_index; ++ return vdpnl_ifname(p, tb[IFLA_IFNAME]); ++} ++ ++/* ++ * Free an malloc'ed maclist array. ++ */ ++void vdp22_freemaclist(struct vdpnl_vsi *vsi) ++{ ++ vsi->macsz = 0; ++ free(vsi->maclist); ++ vsi->maclist = NULL; ++} ++ ++/* ++ * Extract the interface name and loop over all VSI profile entries. ++ * Find UUID and response field for each active profile and construct a ++ * netlink response message. ++ * ++ * Return message size. ++ */ ++static int vdpnl_getlink(struct nlmsghdr *nlh, size_t len) ++{ ++ struct nlmsghdr *nlh_new; ++ struct nl_msg *msg; ++ struct vdpnl_vsi p; ++ int i = 0, rc = -ENOMEM; ++ struct nlattr *vf_ports, *vf_port; ++ struct ifinfomsg ifinfo; ++ size_t mylen = nla_total_size(sizeof(struct ifinfomsg)) ++ + nla_total_size(sizeof(struct nlattr)); ++ /* Header + IFLA_VF_PORTS */ ++ ++ mylen = nlmsg_total_size(mylen); ++ memset(&ifinfo, 0, sizeof ifinfo); ++ memset(&p, 0, sizeof p); ++ msg = nlmsg_alloc_size(len); ++ if (msg) ++ rc = vdpnl_get(&p, nlh); ++ if (rc) { ++ nlmsg_free(msg); ++ return vdpnl_error(rc, nlh, len); ++ } ++ nlmsg_put(msg, nlh->nlmsg_pid, nlh->nlmsg_seq, NLMSG_DONE, 0, 0); ++ ifinfo.ifi_index = p.ifindex; ++ nlmsg_append(msg, &ifinfo, sizeof(ifinfo), 0); ++ ++ vf_ports = nla_nest_start(msg, IFLA_VF_PORTS); ++ /* Iterate over all profiles */ ++ do { ++ rc = vdp22_query(p.ifname) ? vdp22_status(++i, &p, 0) ++ : vdp_status(++i, &p); ++ mylen += vdp_nllen(); ++ if (rc == 1 && mylen < len) { ++ vf_port = nla_nest_start(msg, IFLA_VF_PORT); ++ vdpnl_reply2(&p, msg); ++ nla_nest_end(msg, vf_port); ++ } ++ vdp22_freemaclist(&p); ++ } while (rc == 1); ++ nla_nest_end(msg, vf_ports); ++ if (rc < 0) { ++ nlmsg_free(msg); ++ return vdpnl_error(rc, nlh, len); ++ } ++ nlh_new = nlmsg_hdr(msg); ++ rc = nlh_new->nlmsg_len; ++ memcpy((unsigned char *)nlh, nlh_new, rc); ++ nlmsg_free(msg); ++ LLDPAD_DBG("%s:message-size:%d\n", __func__, rc); ++ return rc; ++} ++ ++/* ++ * Parse incoming command and create a data structure to store the VSI data. ++ */ ++static int vdpnl_setlink(struct nlmsghdr *nlh, size_t len) ++{ ++ int rc = -ENOMEM; ++ struct vdpnl_mac mac; ++ struct vdpnl_vsi p; ++ ++ memset(&p, 0, sizeof p); ++ memset(&mac, 0, sizeof mac); ++ p.vsi_idfmt = VDP22_ID_UUID; ++ p.macsz = 1; ++ p.maclist = &mac; ++ rc = vdpnl_set(nlh, &p); ++ if (!rc) ++ rc = vdp22_query(p.ifname) ? vdp22_request(&p, 0) ++ : vdp_request(&p); ++ return vdpnl_error(rc, nlh, len); ++} ++ ++/* ++ * Process the netlink message. Parameters are the socket, the message and ++ * its length in bytes. ++ * The message buffer 'buf' is used for parsing the incoming message. ++ * After parsing and decoding, the outgoing message is stored in 'buf'. ++ * ++ * Returns: ++ * < 0: Errno number when message parsing failed. ++ * == 0: Message ok and no response. ++ * > 0: Message ok and response returned in buf parameter. Returns bytes ++ * of response. ++ */ ++int vdpnl_recv(unsigned char *buf, size_t buflen) ++{ ++ struct nlmsghdr *nlh = (struct nlmsghdr *)buf; ++ ++ LLDPAD_DBG("%s:buflen:%zd nlh.nl_pid:%d nlh_type:%d nlh_seq:%d " ++ "nlh_len:%d\n", __func__, buflen, nlh->nlmsg_pid, ++ nlh->nlmsg_type, nlh->nlmsg_seq, nlh->nlmsg_len); ++ ++ switch (nlh->nlmsg_type) { ++ case RTM_SETLINK: ++ return vdpnl_setlink(nlh, buflen); ++ case RTM_GETLINK: ++ return vdpnl_getlink(nlh, buflen); ++ default: ++ LLDPAD_ERR("%s:unknown type %d\n", __func__, nlh->nlmsg_type); ++ } ++ return -ENODEV; ++} ++ ++/* ++ * Add one entry in the list of MAC,VLAN pairs. ++ */ ++static void add_pair(struct vdpnl_mac *mac, struct nl_msg *nlh) ++{ ++ struct nlattr *vfinfo; ++ struct ifla_vf_mac ifla_vf_mac = { ++ .vf = PORT_SELF_VF, ++ .mac = { 0, } ++ }; ++ struct ifla_vf_vlan ifla_vf_vlan = { ++ .vf = PORT_SELF_VF, ++ .vlan = mac->vlan, ++ .qos = mac->qos ++ }; ++ ++ vfinfo = nla_nest_start(nlh, IFLA_VF_INFO); ++ memcpy(ifla_vf_mac.mac, mac->mac, sizeof mac->mac); ++ nla_put(nlh, IFLA_VF_MAC, sizeof ifla_vf_mac, &ifla_vf_mac); ++ nla_put(nlh, IFLA_VF_VLAN, sizeof ifla_vf_vlan, &ifla_vf_vlan); ++ nla_nest_end(nlh, vfinfo); ++} ++ ++/* ++ * Walk along the MAC,VLAN ID list and add each entry into the message. ++ */ ++static void add_mac_vlan(struct vdpnl_vsi *vsi, struct nl_msg *nlh) ++{ ++ struct nlattr *vfinfolist; ++ int i; ++ ++ vfinfolist = nla_nest_start(nlh, IFLA_VFINFO_LIST); ++ for (i = 0; i < vsi->macsz; ++i) ++ add_pair(&vsi->maclist[i], nlh); ++ nla_nest_end(nlh, vfinfolist); ++} ++ ++/* ++ * Build an unsolicited netlink message to the VSI requestor. The originator ++ * is the switch abondoning the VSI profile. ++ * Assumes the messages fits into an 4KB buffer. ++ * Returns the message size in bytes. ++ */ ++int vdpnl_send(struct vdpnl_vsi *vsi) ++{ ++ struct nlmsghdr *nlh; ++ struct nlattr *vf_ports, *vf_port; ++ struct ifinfomsg ifinfo; ++ struct ifla_port_vsi portvsi; ++ struct nl_msg *msg; ++ int rc = -ENOMEM; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) { ++ LLDPAD_DBG("%s:%s error allocating netlink message memory:\n", ++ __func__, vsi->ifname); ++ return rc; ++ } ++ nlmsg_put(msg, getpid(), vsi->req_seq, RTM_SETLINK, 0, 0); ++ ++ memset(&ifinfo, 0, sizeof ifinfo); ++ ifinfo.ifi_index = vsi->ifindex; ++ nlmsg_append(msg, &ifinfo, sizeof(ifinfo), 0); ++ nla_put_string(msg, IFLA_IFNAME, vsi->ifname); ++ ++ add_mac_vlan(vsi, msg); ++ portvsi.vsi_mgr_id = vsi->vsi_mgrid; ++ portvsi.vsi_type_id[0] = vsi->vsi_typeid & 0xff; ++ portvsi.vsi_type_id[1] = (vsi->vsi_typeid >> 8) & 0xff; ++ portvsi.vsi_type_id[2] = (vsi->vsi_typeid >> 16) & 0xff; ++ portvsi.vsi_type_version = vsi->vsi_typeversion; ++ vf_ports = nla_nest_start(msg, IFLA_VF_PORTS); ++ vf_port = nla_nest_start(msg, IFLA_VF_PORT); ++ nla_put(msg, IFLA_PORT_VSI_TYPE, sizeof portvsi, &portvsi); ++ nla_put(msg, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsi->vsi_uuid); ++ nla_put_u32(msg, IFLA_PORT_VF, PORT_SELF_VF); ++ nla_put_u16(msg, IFLA_PORT_REQUEST, vsi->request); ++ nla_nest_end(msg, vf_port); ++ nla_nest_end(msg, vf_ports); ++ vdpnl_show(vsi); ++ nlh = nlmsg_hdr(msg); ++ LLDPAD_DBG("%s:nlh.nl_pid:%d nlh_type:%d nlh_seq:%d nlh_len:%d\n", ++ __func__, nlh->nlmsg_pid, nlh->nlmsg_type, nlh->nlmsg_seq, ++ nlh->nlmsg_len); ++ rc = event_trigger(nlh, vsi->req_pid); ++ nlmsg_free(msg); ++ return rc; ++} +diff --git a/qbg_utils.c b/qbg_utils.c +new file mode 100644 +index 0000000..9daeade +--- /dev/null ++++ b/qbg_utils.c +@@ -0,0 +1,83 @@ ++/****************************************************************************** ++ ++ Implementation of ECP according to 802.1Qbg ++ (c) Copyright IBM Corp. 2010, 2013 ++ ++ Author(s): Thomas Richter ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++******************************************************************************/ ++ ++/* ++ * This file contains common support utilities for the ECP protocols. ++ */ ++ ++#include ++#include ++ ++#include "lldp.h" ++#include "lldp_mod.h" ++#include "messages.h" ++#include "qbg_utils.h" ++ ++extern int loglvl; /* Global lldpad log level */ ++extern struct lldp_head lldp_head; ++ ++/* ++ * hexdump_frame - print raw evb/ecp/vdp frame ++ */ ++void hexdump_frame(const char *ifname, char *txt, const unsigned char *buf, ++ size_t len) ++{ ++ size_t i; ++ int left = 0; ++ char buffer[ETH_FRAME_LEN * 3]; ++ ++ /* Only collect data when the loglvl ensures data printout */ ++ if (LOG_DEBUG < loglvl) ++ return; ++ for (i = 0; i < len; i++) { ++ int c; ++ c = snprintf(buffer + left, sizeof buffer - left, "%02x%c", ++ buf[i], !((i + 1) % 16) ? '\n' : ' '); ++ if (c > 0 && (c < (int)sizeof buffer - left)) ++ left += c; ++ } ++ LLDPAD_DBG("%s:%s %s\n%s\n", __func__, ifname, txt, buffer); ++} ++ ++/* ++ * Function to advertise changed variables to other modules. ++ * ++ * Parameters are interface name, target module id and data. ++ * When sending the data, the module call back function contains the ++ * module id of the sender. ++ * ++ * Return 0 when no addressee found or addressess found but addressee was ++ * unable to handle data. ++ */ ++int modules_notify(int id, int sender_id, char *ifname, void *data) ++{ ++ struct lldp_module *mp = find_module_by_id(&lldp_head, id); ++ int rc = 0; ++ ++ if (mp && mp->ops->lldp_mod_notify) ++ rc = mp->ops->lldp_mod_notify(sender_id, ifname, data); ++ LLDPAD_DBG("%s:%s target-id:%#x rc:%d\n", __func__, ifname, id, rc); ++ return rc; ++} +diff --git a/test/nltest.c b/test/nltest.c +index 7ace3b1..da05463 100644 +--- a/test/nltest.c ++++ b/test/nltest.c +@@ -1156,12 +1156,14 @@ void print_pfc(struct ieee_pfc *pfc) + + printf("\t requests: "); + for (i = 0; i < 8; i++) +- printf("%lli ", pfc->requests[i]); ++ printf("%llu ", ++ (unsigned long long)pfc->requests[i]); + printf("\n"); + + printf("\t requests: "); + for (i = 0; i < 8; i++) +- printf("%lli ", pfc->indications[i]); ++ printf("%llu ", ++ (unsigned long long)pfc->indications[i]); + printf("\n"); + } + +diff --git a/test/qbg22/README b/test/qbg22/README +new file mode 100644 +index 0000000..bb0c6e8 +--- /dev/null ++++ b/test/qbg22/README +@@ -0,0 +1,19 @@ ++ ++(c) Copyright IBM Corp. 2013 ++ ++Thomas Richter, IBM Research and Development, Germany, April 2013 ++ ++Test cases for IEEE802.1Qbg ratified standard QBG22 support. ++ ++29-Apr-2013 ++=========== ++The test cases run on one machine using 2 network name spaces: ++1. Run on one machine using 2 network name spaces (requires linux-3.8 kernel). ++2. Create a pair of virtual network interfaces (veth0 and veth2) and assign ++ veth2 to network name space bridge_ns ++ ++lldpad (station rile) uses the default network name space and veth0. ++The qbg22 simulator program qbg22sim uses bridge_ns and veth2 interface. ++The lldpad (bridge role) vor vpd22 protocol testing uses the bridge_ns and ++veth2 interface and creates an unnamed IPC name space to have its on shared ++memory segment. +diff --git a/test/qbg22/ecp22/1-lldpad.conf b/test/qbg22/ecp22/1-lldpad.conf +new file mode 100644 +index 0000000..484322a +--- /dev/null ++++ b/test/qbg22/ecp22/1-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of ECP according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = false; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/ecp22/1.chk b/test/qbg22/ecp22/1.chk +new file mode 100644 +index 0000000..f5bf6df +--- /dev/null ++++ b/test/qbg22/ecp22/1.chk +@@ -0,0 +1,45 @@ ++#!/bin/bash ++# ++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013 ++# Check of lldpad did start the ecp module, it shound not. ++ ++# Note first parameter is the test case number ++tfile=/tmp/$1-lldpad.conf.out ++ ++echo "check for ecp22 module not started" ++ ++if [ ! -r $tfile ] ++then ++ echo "lldpad trace file not readable" ++ exit 126 ++fi ++ ++if fgrep -q 'ecp22_start:veth0' $tfile ++then ++ echo "error ecp22 module started" ++ exit 125 ++fi ++ ++echo SUCCESS ++exit 0 +diff --git a/test/qbg22/ecp22/1.ecp b/test/qbg22/ecp22/1.ecp +new file mode 100644 +index 0000000..d1f8b95 +--- /dev/null ++++ b/test/qbg22/ecp22/1.ecp +@@ -0,0 +1,65 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (- is replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. ECP header and paylaod data field according to standard 802.1qbg ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * ECP negotiation ++ * Bridge does not offer reflective relay. ++ * Check that LLDPAD does not start ECP module. ++ */ ++ ++#include "defines.ecp" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_norr_ack ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_norr_ack ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_norr_ack ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_norr_ack ++ ++18 lldpad_mac - ecp_type 10:01 12:24 0a:0b:0c:0d ++21 lldpad_mac - ecp_type 10:01 12:25 0a:0b:0c:0d ++24 lldpad_mac - ecp_type 10:01 12:26 0a:0b:0c:0d ++ ++35 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/ecp22/10-lldpad.conf b/test/qbg22/ecp22/10-lldpad.conf +new file mode 100644 +index 0000000..2355662 +--- /dev/null ++++ b/test/qbg22/ecp22/10-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of ECP according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/ecp22/10.ecp b/test/qbg22/ecp22/10.ecp +new file mode 100644 +index 0000000..9cdbe18 +--- /dev/null ++++ b/test/qbg22/ecp22/10.ecp +@@ -0,0 +1,64 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (- is replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. ECP header and paylaod data field according to standard 802.1qbg ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * ECP negotiation ++ * Bridge offer reflective relay. ++ * Check that lldpad start ecp transmit state machine. ++ */ ++ ++#include "defines.ecp" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:def_counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++ ++ ++60 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/ecp22/11-lldpad.conf b/test/qbg22/ecp22/11-lldpad.conf +new file mode 100644 +index 0000000..2355662 +--- /dev/null ++++ b/test/qbg22/ecp22/11-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of ECP according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/ecp22/11.ecp b/test/qbg22/ecp22/11.ecp +new file mode 100644 +index 0000000..937d2f0 +--- /dev/null ++++ b/test/qbg22/ecp22/11.ecp +@@ -0,0 +1,68 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (- is replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. ECP header and paylaod data field according to standard 802.1qbg ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * ECP negotiation ++ * Bridge offer reflective relay. ++ * Check that lldpad start ecp transmit state machine. ++ * Needs special code that transmits a data packet after some time out ++ * inside ECP module of lldpad !!!!!!!!!!!!!!!!!!!! ++ */ ++ ++#include "defines.ecp" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:def_counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++11 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:6f:00:00 end_tlv @evbhead:03:05:6f:88:08 ++ ++ ++60 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/ecp22/2-lldpad.conf b/test/qbg22/ecp22/2-lldpad.conf +new file mode 100644 +index 0000000..2355662 +--- /dev/null ++++ b/test/qbg22/ecp22/2-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of ECP according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/ecp22/2.chk b/test/qbg22/ecp22/2.chk +new file mode 100644 +index 0000000..bb9aa41 +--- /dev/null ++++ b/test/qbg22/ecp22/2.chk +@@ -0,0 +1,54 @@ ++#!/bin/bash ++# ++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013 ++# Check of lldpad did start the ecp module, it shound not. ++ ++# Note first parameter is the test case number ++ ++tfile=/tmp/$1-lldpad.conf.out ++ ++if [ ! -r $tfile ] ++then ++ echo "lldpad trace file not readable" ++ exit 126 ++fi ++ ++echo "check for ecp22 module started" ++ ++if ! fgrep -q 'ecp22_start:veth0' $tfile ++then ++ echo "error ecp22 module not started" ++ exit 125 ++fi ++ ++echo "check for one ULP notification" ++count=$(fgrep 'notify ULP 1 seqno 0x1224' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 invalid ULP notifications:$count" ++ exit 124 ++fi ++ ++echo SUCCESS ++exit 0 +diff --git a/test/qbg22/ecp22/2.ecp b/test/qbg22/ecp22/2.ecp +new file mode 100644 +index 0000000..3fcea5e +--- /dev/null ++++ b/test/qbg22/ecp22/2.ecp +@@ -0,0 +1,70 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (- is replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. ECP header and paylaod data field according to standard 802.1qbg ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * ECP negotiation ++ * Bridge offer reflective relay. ++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange. ++ * Use same sequence number and check for acknowledgement. Only ONE!!!! upper ++ * layer notification on the lldpad side ++ */ ++ ++#include "defines.ecp" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:def_counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++ ++15 lldpad_mac - ecp_type 10:01 12:24 end_tlv @14:01:12:24 ++16 lldpad_mac - ecp_type 10:01 12:24 end_tlv @14:01:12:24 ++17 lldpad_mac - ecp_type 10:01 12:24 end_tlv @14:01:12:24 ++ ++ ++30 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/ecp22/3-lldpad.conf b/test/qbg22/ecp22/3-lldpad.conf +new file mode 100644 +index 0000000..2355662 +--- /dev/null ++++ b/test/qbg22/ecp22/3-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of ECP according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/ecp22/3.chk b/test/qbg22/ecp22/3.chk +new file mode 100755 +index 0000000..a70475e +--- /dev/null ++++ b/test/qbg22/ecp22/3.chk +@@ -0,0 +1,68 @@ ++#!/bin/bash ++# ++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013 ++# Check of lldpad did start the ecp module, it shound not. ++ ++# Note first parameter is the test case number ++ ++tfile=/tmp/$1-lldpad.conf.out ++ ++if [ ! -r $tfile ] ++then ++ echo "lldpad trace file not readable" ++ exit 126 ++fi ++ ++echo "check for ecp22 module started" ++ ++if ! fgrep -q 'ecp22_start:veth0' $tfile ++then ++ echo "error ecp22 module not started" ++ exit 125 ++fi ++ ++echo "check for one ULP notification seqno 0x1224" ++count=$(fgrep 'notify ULP 1 seqno 0x1224' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 invalid ULP notifications:$count sequence 0x1224" ++ exit 124 ++fi ++echo "check for one ULP notification seqno 0x1225" ++count=$(fgrep 'notify ULP 1 seqno 0x1225' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 invalid ULP notifications:$count sequence 0x1225" ++ exit 123 ++fi ++echo "check for one ULP notification seqno 0x1226" ++count=$(fgrep 'notify ULP 1 seqno 0x1226' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 invalid ULP notifications:$count sequence 0x1226" ++ exit 122 ++fi ++ ++echo SUCCESS ++exit 0 +diff --git a/test/qbg22/ecp22/3.ecp b/test/qbg22/ecp22/3.ecp +new file mode 100644 +index 0000000..d4f7b31 +--- /dev/null ++++ b/test/qbg22/ecp22/3.ecp +@@ -0,0 +1,70 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (- is replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. ECP header and paylaod data field according to standard 802.1qbg ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * ECP negotiation ++ * Bridge offer reflective relay. ++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange. ++ * Use different sequence number and check for acknowledgement. 3 upper ++ * layer notification on the lldpad side ++ */ ++ ++#include "defines.ecp" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:def_counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++ ++15 lldpad_mac - ecp_type 10:01 12:24 aa:bb:cc:dd end_tlv @14:01:12:24 ++17 lldpad_mac - ecp_type 10:01 12:25 00:11:22:33 end_tlv @14:01:12:25 ++19 lldpad_mac - ecp_type 10:01 12:26 44:55:66:77 end_tlv @14:01:12:26 ++ ++ ++30 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/ecp22/30-lldpad.conf b/test/qbg22/ecp22/30-lldpad.conf +new file mode 100644 +index 0000000..2355662 +--- /dev/null ++++ b/test/qbg22/ecp22/30-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of ECP according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/ecp22/30.ecp b/test/qbg22/ecp22/30.ecp +new file mode 100644 +index 0000000..63e06cf +--- /dev/null ++++ b/test/qbg22/ecp22/30.ecp +@@ -0,0 +1,83 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (- is replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. ECP header and paylaod data field according to standard 802.1qbg ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * ECP negotiation ++ * Bridge offer reflective relay. ++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange. ++ */ ++ ++#include "defines.ecp" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:def_counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++ ++20 lldpad_mac - ecp_type 10:01 12:30 44:55:66:77 end_tlv @14:01:12:30 ++ ++/* ++ * In the mean time disable and enable interface on target machine ++ * via remote executed shell script. Disable happens after 30 seconds and ++ * enable is after 40 seconds. ++ */ ++ ++45 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:def_counts ++46 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts ++47 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++48 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++49 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++60 lldpad_mac - ecp_type 10:01 12:31 44:55:66:77 end_tlv @14:01:12:31 ++ ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/ecp22/30.sh b/test/qbg22/ecp22/30.sh +new file mode 100755 +index 0000000..875c9ca +--- /dev/null ++++ b/test/qbg22/ecp22/30.sh +@@ -0,0 +1,38 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD ECP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Nov-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 30 seconds and disable/enable interface ++sleep 30; ++ip l s down dev veth0 ++sleep 10 ++ip l s up dev veth0 ++ip a sh dev veth0 | fgrep -q UP ++exit $? ++ +diff --git a/test/qbg22/ecp22/4-lldpad.conf b/test/qbg22/ecp22/4-lldpad.conf +new file mode 100644 +index 0000000..2355662 +--- /dev/null ++++ b/test/qbg22/ecp22/4-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of ECP according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/ecp22/4.chk b/test/qbg22/ecp22/4.chk +new file mode 100644 +index 0000000..d24eca4 +--- /dev/null ++++ b/test/qbg22/ecp22/4.chk +@@ -0,0 +1,68 @@ ++#!/bin/bash ++# ++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013 ++# Check of lldpad did start the ecp module, it shound not. ++ ++# Note first parameter is the test case number ++ ++tfile=/tmp/$1-lldpad.conf.out ++ ++if [ ! -r $tfile ] ++then ++ echo "lldpad trace file not readable" ++ exit 126 ++fi ++ ++echo "check for ecp22 module started" ++ ++if ! fgrep -q 'ecp22_start:veth0' $tfile ++then ++ echo "error ecp22 module not started" ++ exit 125 ++fi ++ ++echo "check for unknown version 0xf001 seqno 0x1224" ++count=$(fgrep 'unknown version 0xf001 seqno 0x1224' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 unknown version 0xf001:$count sequence 0x1224" ++ exit 124 ++fi ++echo "check for unknown version 0xf001 seqno 0x1225" ++count=$(fgrep 'unknown version 0xf001 seqno 0x1225' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 unknown version 0xf001:$count sequence 0x1225" ++ exit 123 ++fi ++echo "check for unknown version 0xf001 seqno 0x1226" ++count=$(fgrep 'unknown version 0xf001 seqno 0x1226' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 unknown version 0xf001:$count sequence 0x1226" ++ exit 122 ++fi ++ ++echo SUCCESS ++exit 0 +diff --git a/test/qbg22/ecp22/4.ecp b/test/qbg22/ecp22/4.ecp +new file mode 100644 +index 0000000..79bb5ba +--- /dev/null ++++ b/test/qbg22/ecp22/4.ecp +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (- is replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. ECP header and paylaod data field according to standard 802.1qbg ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * ECP negotiation ++ * Bridge offer reflective relay. ++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange. ++ * Use invalid version number. No acknowledgement expected. ++ * Use different sequence number and check for acknowledgement. No upper ++ * layer notification on the lldpad side. ++ */ ++ ++#include "defines.ecp" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:def_counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++ ++15 lldpad_mac - ecp_type f0:01 12:24 aa:bb:cc:dd end_tlv ++17 lldpad_mac - ecp_type f0:01 12:25 00:11:22:33 end_tlv ++19 lldpad_mac - ecp_type f0:01 12:26 44:55:66:77 end_tlv ++ ++25 lldpad_mac - ecp_type 10:01 12:27 44:55:66:77 end_tlv @14:01:12:27 ++ ++30 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/ecp22/5-lldpad.conf b/test/qbg22/ecp22/5-lldpad.conf +new file mode 100644 +index 0000000..2355662 +--- /dev/null ++++ b/test/qbg22/ecp22/5-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of ECP according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/ecp22/5.chk b/test/qbg22/ecp22/5.chk +new file mode 100644 +index 0000000..a1e7c9a +--- /dev/null ++++ b/test/qbg22/ecp22/5.chk +@@ -0,0 +1,68 @@ ++#!/bin/bash ++# ++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013 ++# Check of lldpad did start the ecp module, it shound not. ++ ++# Note first parameter is the test case number ++ ++tfile=/tmp/$1-lldpad.conf.out ++ ++if [ ! -r $tfile ] ++then ++ echo "lldpad trace file not readable" ++ exit 126 ++fi ++ ++echo "check for ecp22 module started" ++ ++if ! fgrep -q 'ecp22_start:veth0' $tfile ++then ++ echo "error ecp22 module not started" ++ exit 125 ++fi ++ ++echo "check for unknown subtype 0x100f seqno 0x1224" ++count=$(fgrep 'unknown subtype 0x100f seqno 0x1224' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 unknown subtype 0x100f:$count sequence 0x1224" ++ exit 124 ++fi ++echo "check for unknown subtype 0x100f seqno 0x1225" ++count=$(fgrep 'unknown subtype 0x100f seqno 0x1225' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 unknown subtype 0x100f:$count sequence 0x1225" ++ exit 123 ++fi ++echo "check for unknown subtype 0x100f seqno 0x1226" ++count=$(fgrep 'unknown subtype 0x100f seqno 0x1226' $tfile | wc -l) ++if [ "$count" -ne 1 ] ++then ++ echo "error ecp22 unknown subtype 0x100f:$count sequence 0x1226" ++ exit 122 ++fi ++ ++echo SUCCESS ++exit 0 +diff --git a/test/qbg22/ecp22/5.ecp b/test/qbg22/ecp22/5.ecp +new file mode 100644 +index 0000000..2d6c15a +--- /dev/null ++++ b/test/qbg22/ecp22/5.ecp +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (- is replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. ECP header and paylaod data field according to standard 802.1qbg ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * ECP negotiation ++ * Bridge offer reflective relay. ++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange. ++ * Use invalid subtype number. No acknowledgement expected. ++ * Use different sequence number and check for acknowledgement. No upper ++ * layer notification on the lldpad side. ++ */ ++ ++#include "defines.ecp" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:def_counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts ++ ++15 lldpad_mac - ecp_type 10:0f 12:24 aa:bb:cc:dd end_tlv ++17 lldpad_mac - ecp_type 10:0f 12:25 00:11:22:33 end_tlv ++19 lldpad_mac - ecp_type 10:0f 12:26 44:55:66:77 end_tlv ++ ++25 lldpad_mac - ecp_type 10:01 12:27 44:55:66:77 end_tlv @14:01:12:27 ++ ++30 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/ecp22/README b/test/qbg22/ecp22/README +new file mode 100644 +index 0000000..e0b2137 +--- /dev/null ++++ b/test/qbg22/ecp22/README +@@ -0,0 +1,80 @@ ++ ++Implementation of EVB according to IEEE 802.1Qbg ++(c) Copyright IBM Corp. 2014 ++ ++Author(s): Thomas Richter ++ ++This program is free software; you can redistribute it and/or modify it ++under the terms and conditions of the GNU General Public License, ++version 2, as published by the Free Software Foundation. ++ ++This program is distributed in the hope it will be useful, but WITHOUT ++ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++more details. ++ ++You should have received a copy of the GNU General Public License along with ++this program; if not, write to the Free Software Foundation, Inc., ++51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++The full GNU General Public License is included in this distribution in ++the file called "COPYING". ++ ++Thomas Richter, IBM Research and Development, Germany, Aug 2012 ++ ++Test cases for IEEE802.1Qbg ratified standard ECP module. ++ ++Files ++===== ++There are 3 shell scripts which are executed on f18a. ++allecp.sh: Runs all test cases with file names [1-9]*.ecp. Uses ++ runecp.sh to execute one test case. ++ On success the exit code is zero, on failure none zero. ++ A none zero exit code termintes the programme immediately. ++runecp.sh Runs one test case. Symbolic link to runevb.sh ++3.sh .sh contain shell scripts to be executed ++ on the remote virtual machine. Usually done to change some ++ lldpad configuration settings during execution of lldpad. ++3.chk Runs a shell script to scan the lldpad trace file and ++ checks for proper entries. ++ ++Tests ++===== ++The following test cases are executed. Each test case has a number. ++All test cases need a lldpad.conf configuration file and an ECP test input ++file: ++- The ECP test input files have the extension .ecp. The test case number ++ is the base file name. ++- The lldpad configuration file has the extension -lldpad.conf. ++ ++The purpose is to trigger an ECP DU exchange between qbg22sim and llpdad. ++The exchanged data can be inspected automaticly with little inteligence ++(see qbg22sim.1) or manually. ++ ++Test Description ++1 bridge does not support refective-relay. ++2 bridge supports refective-relay. Use same sequence number ++3 bridge supports refective-relay. Use different sequence numbers ++4 bridge supports refective-relay. Use different invalid version ++5 bridge supports refective-relay. Use different invalid subversion ++30 bridge supports refective-relay. Interface will go down and up ++ again during the ECP module run time. ++ ++Remarks: ++ ++Test Execution ++============== ++Directory structure: ++ ++The following directory structure is assumed: ++/home/richter/dcn/qbg/mywork/open-lldp --> lldpad to test on target f18b ++/home/richter/dcn/qbg/mywork/testns/qbg22/evb22 --> EVB protocol test cases ++/home/richter/dcn/qbg/mywork/testns/qbg22/ecp22 --> ECP protocol test cases ++ ++Select the qbg22sim program by adding the path relative to test directory ++1. cd /home/richter/dcn/qbg/mywork/test/qbg22/ecp22 ++2. Symbolic link such as ./qbg22sim --> ../../../lldpad/qbg22sim. ++3. Add the environment variable LLDPAD_DIR=abc to select an different lldpad ++ executable. For example the invocation ++ LLDPAD_DIR=new ecpall.sh ++ selects the file /home/richter/dcn/qbg/mywork/new/lldpad for execution. +diff --git a/test/qbg22/ecp22/allecp.sh b/test/qbg22/ecp22/allecp.sh +new file mode 100755 +index 0000000..6f5a418 +--- /dev/null ++++ b/test/qbg22/ecp22/allecp.sh +@@ -0,0 +1,68 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD ECP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute the complete evb test suite. ++# ++ ++runcommand() ++{ ++ # echo parameter $@ ++ cmd=$1 ++ file=$2 ++ ++ echo "start testcase $number" ++ $cmd $file $@ 2>&1 ++ rc="$?" ++ if [ "$rc" -ne 0 ] ++ then ++ echo -en "\\033[1;31m" # Failures in red ++ echo "ERROR $file exit with $rc" ++ echo -en "\\033[0;39m" ++ exit 2 ++ fi ++ echo -en "\\033[1;32m" # Success in green ++ echo "OK testcase $file" ++ echo -en "\\033[0;39m" ++ return 0 ++} ++ ++# Extract type of test case from the first 3 characters of invocation file ++type=$(basename $0) ++type="${type:3:3}" ++ ++if ! which run$type.sh 2>/dev/null ++then ++ export PATH=$PATH:$PWD ++fi ++ ++echo "Start testsuite at $(date)" ++for i in $(ls [1-9]*.$type|sort -n) ++do ++ runcommand run$type.sh $i ++done ++echo "Stop testsuite at $(date)" ++exit 0 +diff --git a/test/qbg22/ecp22/defines.ecp b/test/qbg22/ecp22/defines.ecp +new file mode 100644 +index 0000000..ea53399 +--- /dev/null ++++ b/test/qbg22/ecp22/defines.ecp +@@ -0,0 +1,52 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set ++ * is needed for each transmission. ++ */ ++/* ++ * Very common defines ++ */ ++ ++#define lldpad_mac 01:80:c2:00:00:00 ++#define lldp_type 88:cc ++#define chassis_tlv 02:07:06:64:75:6d:6d:79:00 ++#define port_tlv 04:05:05:65:74:68:30 ++#define ttl_tlv120 06:02:00:78 ++#define ttl_tlv0 06:02:00:00 ++#define end_tlv 00:00 ++ ++#define evbhead fe:09:00:80:c2:0d ++#define def_counts 68:88:08 /* Default ECP values */ ++ ++/* Bridge denies reflective-relay */ ++#define evb_norr evbhead:00:00:00:40:00 ++#define evb_norr_ack evbhead:00:00:def_counts ++ ++#define ecp_type 89:40 ++ ++/* Bridge offers reflective-relay */ ++#define evb_brrr evbhead:02:00:00:40:00 ++#define evb_brrr_ack evbhead:02:00:def_counts +diff --git a/test/qbg22/ecp22/runecp.sh b/test/qbg22/ecp22/runecp.sh +new file mode 100755 +index 0000000..bf6b0ef +--- /dev/null ++++ b/test/qbg22/ecp22/runecp.sh +@@ -0,0 +1,153 @@ ++#!/bin/bash ++# ++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single test. Parameter is the name of the test file ++# ++ ++# Check if lldpad is up and running. Return pid or 0 if not running. ++# Note that lldpad may be started without creating a PID file. If no PID file ++# exists, use the lldptool to query the PID of lldpad. ++function lldpad_up() ++{ ++ if [ ! -r /var/run/lldpad.pid ] ++ then ++ pidfile=$(../../../lldptool -p 2>/dev/null) ++ if [ "$?" -ne 0 ] ++ then ++ return 0 ++ fi ++ else ++ pidfile="$(cat /var/run/lldpad.pid)" ++ fi ++ if [ -z "$pidfile" ] ++ then ++ return 0 ++ else ++ ps -p $pidfile -o pid --no-header > /dev/null ++ if [ $? -ne 0 ] ++ then ++ return 0 ++ fi ++ fi ++ echo "LLDPAD running pid $pidfile" ++ return $pidfile ++} ++ ++function lldpad_down() ++{ ++ if [ ! -r /var/run/lldpad.pid ] ++ then ++ pidfile=$(../../../lldptool -p 2>/dev/null) ++ if [ "$?" -ne 0 ] ++ then ++ return 1 ++ fi ++ else ++ pidfile="$(cat /var/run/lldpad.pid)" ++ fi ++ if [ -z "$pidfile" ] ++ then ++ return 1 ++ fi ++ kill -s SIGTERM $pidfile ++ sleep 1 ++ ps -p $pidfile -o pid --no-header > /dev/null ++ if [ $? -ne 1 ] ++ then ++ kill -s SIGKILL $pidfile ++ fi ++ return 0 ++} ++ ++# Use the correct lldpad configuration file and start lldpad. ++# Parameter 1: path to lldpad to use ++# Parameter 2: name of configuration file ++function lldpad_start() ++{ ++ if lldpad_up ++ then ++ rm -f /var/lib/lldpad/lldpad.conf ./lldpad.conf ++ cp $2 /tmp/$2 ++ $1/lldpad -V7 -f /tmp/$2 >/tmp/$2.out 2>&1 & ++ sleep 1 ++ if lldpad_up ++ then ++ echo "$0:lldpad not started or terminated unexpectedly" ++ exit 1 ++ fi ++ else ++ exit 1 ++ fi ++ return 0 ++} ++ ++if ! which runecp.sh 1>/dev/null 2>/dev/null ++then ++ export PATH=$PATH:$PWD ++fi ++ ++# Extract type of test case from last 3 characters of invocation ++type=$(basename $0) ++type=".${type:3:3}" ++ ++testfile=$1 ++no=$(basename $testfile $type) ++ ++# Start lldpad using this name space ++if ! lldpad_start ../../.. $no-lldpad.conf ++then ++ echo "$0:can not start lldpad" ++ exit 1 ++fi ++ ++# Check for shell script to run in parallel ++if [ -r "./$no.sh" -a -x "./$no.sh" ] ++then ++ ./$no.sh ../../.. & ++fi ++ ++# get the duration fron the last entry in the test file. ++duration=$(cpp $testfile | cut -f1 -d' ' | sed '/^$/d' | tail -1) ++let duration=duration+5 ++ ++# run the test with output save to /tmp/testfile.out ++ip netns exec bridge_ns ../../../qbg22sim -v -v -v -T 2500000 -d $duration veth2 $testfile > /tmp/$testfile.out ++rc=$? ++ ++# Stop lldpad ++if ! lldpad_down ++then ++ echo "$0:can not stop lldpad" ++ exit 1 ++fi ++ ++# Check for shell script to test result of test case ++if [ -r "./$no.chk" -a -x "./$no.chk" ] ++then ++ ./$no.chk $no >/tmp/$no.chk.out ++ rc=$? ++fi ++ ++exit $rc +diff --git a/test/qbg22/evb22/1-lldpad.conf b/test/qbg22/evb22/1-lldpad.conf +new file mode 100644 +index 0000000..280566b +--- /dev/null ++++ b/test/qbg22/evb22/1-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "041A17CEF5FBBD"; ++ }; ++ tlvid00000002 : ++ { ++ info = "031A17CEF5FBBD"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = false; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/1.evb b/test/qbg22/evb22/1.evb +new file mode 100644 +index 0000000..8c94f60 +--- /dev/null ++++ b/test/qbg22/evb22/1.evb +@@ -0,0 +1,59 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_norr_ack ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_norr_ack ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_norr_ack ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_norr_ack ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/10-lldpad.conf b/test/qbg22/evb22/10-lldpad.conf +new file mode 100644 +index 0000000..a219bbf +--- /dev/null ++++ b/test/qbg22/evb22/10-lldpad.conf +@@ -0,0 +1,32 @@ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/10.evb b/test/qbg22/evb22/10.evb +new file mode 100644 +index 0000000..e90cd1d +--- /dev/null ++++ b/test/qbg22/evb22/10.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. RKA value is lower than on station. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/11-lldpad.conf b/test/qbg22/evb22/11-lldpad.conf +new file mode 100644 +index 0000000..3f86198 +--- /dev/null ++++ b/test/qbg22/evb22/11-lldpad.conf +@@ -0,0 +1,54 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/11.evb b/test/qbg22/evb22/11.evb +new file mode 100644 +index 0000000..45b228a +--- /dev/null ++++ b/test/qbg22/evb22/11.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. RWD value is higher than on station. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:5f:00 end_tlv @evbhead:00:04:68:bf:08 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:5f:00 end_tlv @evbhead:00:04:68:bf:08 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:5f:00 end_tlv @evbhead:00:04:68:bf:08 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:5f:00 end_tlv @evbhead:00:04:68:bf:08 ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/12-lldpad.conf b/test/qbg22/evb22/12-lldpad.conf +new file mode 100644 +index 0000000..3f86198 +--- /dev/null ++++ b/test/qbg22/evb22/12-lldpad.conf +@@ -0,0 +1,54 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/12.evb b/test/qbg22/evb22/12.evb +new file mode 100644 +index 0000000..0de9daa +--- /dev/null ++++ b/test/qbg22/evb22/12.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. RWD value is lower than on station. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/13-lldpad.conf b/test/qbg22/evb22/13-lldpad.conf +new file mode 100644 +index 0000000..3f86198 +--- /dev/null ++++ b/test/qbg22/evb22/13-lldpad.conf +@@ -0,0 +1,54 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/13.evb b/test/qbg22/evb22/13.evb +new file mode 100644 +index 0000000..1b41f46 +--- /dev/null ++++ b/test/qbg22/evb22/13.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. Retry value is higher than on station. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:e0:40:00 end_tlv @evbhead:00:04:e8:88:08 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:e0:40:00 end_tlv @evbhead:00:04:e8:88:08 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:e0:40:00 end_tlv @evbhead:00:04:e8:88:08 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:e0:40:00 end_tlv @evbhead:00:04:e8:88:08 ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/14-lldpad.conf b/test/qbg22/evb22/14-lldpad.conf +new file mode 100644 +index 0000000..3f86198 +--- /dev/null ++++ b/test/qbg22/evb22/14-lldpad.conf +@@ -0,0 +1,54 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/14.evb b/test/qbg22/evb22/14.evb +new file mode 100644 +index 0000000..0de9daa +--- /dev/null ++++ b/test/qbg22/evb22/14.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. RWD value is lower than on station. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/2-lldpad.conf b/test/qbg22/evb22/2-lldpad.conf +new file mode 100644 +index 0000000..0db19ce +--- /dev/null ++++ b/test/qbg22/evb22/2-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = false; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/2.evb b/test/qbg22/evb22/2.evb +new file mode 100644 +index 0000000..2059520 +--- /dev/null ++++ b/test/qbg22/evb22/2.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay but station ++ * does not request it. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evb_brrr_ack ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evb_brrr_ack ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evb_brrr_ack ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evb_brrr_ack ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/20-lldpad.conf b/test/qbg22/evb22/20-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/20-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/20.evb b/test/qbg22/evb22/20.evb +new file mode 100644 +index 0000000..43cfd94 +--- /dev/null ++++ b/test/qbg22/evb22/20.evb +@@ -0,0 +1,62 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge sets group id bit, but station denies. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:04:00:00:00 end_tlv @evbhead:07:05:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:00:00 end_tlv @evbhead:07:05:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:00:00 end_tlv @evbhead:07:05:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:00:00 end_tlv @evbhead:07:05:counts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/21-lldpad.conf b/test/qbg22/evb22/21-lldpad.conf +new file mode 100644 +index 0000000..456da71 +--- /dev/null ++++ b/test/qbg22/evb22/21-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/21.evb b/test/qbg22/evb22/21.evb +new file mode 100644 +index 0000000..d68e299 +--- /dev/null ++++ b/test/qbg22/evb22/21.evb +@@ -0,0 +1,62 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge denies group id bit, but station sets it. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:40:00 end_tlv @evbhead:02:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0c:00:00:00 end_tlv @evbhead:03:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0c:00:00:00 end_tlv @evbhead:03:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0c:00:00:00 end_tlv @evbhead:03:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0c:00:00:00 end_tlv @evbhead:03:0d:counts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/22-lldpad.conf b/test/qbg22/evb22/22-lldpad.conf +new file mode 100644 +index 0000000..456da71 +--- /dev/null ++++ b/test/qbg22/evb22/22-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/22.evb b/test/qbg22/evb22/22.evb +new file mode 100644 +index 0000000..628a7ea +--- /dev/null ++++ b/test/qbg22/evb22/22.evb +@@ -0,0 +1,62 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:00:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/23-lldpad.conf b/test/qbg22/evb22/23-lldpad.conf +new file mode 100644 +index 0000000..456da71 +--- /dev/null ++++ b/test/qbg22/evb22/23-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/23.evb b/test/qbg22/evb22/23.evb +new file mode 100644 +index 0000000..ebce9c9 +--- /dev/null ++++ b/test/qbg22/evb22/23.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. Bridge turns off bgid ++ * later. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:00:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts ++40 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts ++41 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts ++42 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts ++43 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts ++44 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts +diff --git a/test/qbg22/evb22/24-lldpad.conf b/test/qbg22/evb22/24-lldpad.conf +new file mode 100644 +index 0000000..456da71 +--- /dev/null ++++ b/test/qbg22/evb22/24-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/24.evb b/test/qbg22/evb22/24.evb +new file mode 100644 +index 0000000..d79a2a9 +--- /dev/null ++++ b/test/qbg22/evb22/24.evb +@@ -0,0 +1,73 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. Station turns off ++ * sgid later. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/24.sh b/test/qbg22/evb22/24.sh +new file mode 100755 +index 0000000..f208a1d +--- /dev/null ++++ b/test/qbg22/evb22/24.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds change setting ++sleep 50; ++$1/lldptool -i veth0 -gncb -T -V evb -c evbgpid=no +diff --git a/test/qbg22/evb22/25-lldpad.conf b/test/qbg22/evb22/25-lldpad.conf +new file mode 100644 +index 0000000..cea1077 +--- /dev/null ++++ b/test/qbg22/evb22/25-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = false; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/25.evb b/test/qbg22/evb22/25.evb +new file mode 100644 +index 0000000..e78fd0b +--- /dev/null ++++ b/test/qbg22/evb22/25.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv \\ ++ @02:07:04:e6:f1:20:5a:b0:e6\\ ++ @04:07:03:e6:f1:20:5a:b0:e6\\ ++ @06:02:00:78:00:00 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv \\ ++ @02:07:04:e6:f1:20:5a:b0:e6\\ ++ @04:07:03:e6:f1:20:5a:b0:e6\\ ++ @06:02:00:78:00:00 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv \\ ++ @02:07:04:e6:f1:20:5a:b0:e6\\ ++ @04:07:03:e6:f1:20:5a:b0:e6\\ ++ @06:02:00:78:00:00 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv \\ ++ @02:07:04:e6:f1:20:5a:b0:e6\\ ++ @04:07:03:e6:f1:20:5a:b0:e6\\ ++ @06:02:00:78:00:00 ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/26-lldpad.conf b/test/qbg22/evb22/26-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/26-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/26.evb b/test/qbg22/evb22/26.evb +new file mode 100644 +index 0000000..f3ff74d +--- /dev/null ++++ b/test/qbg22/evb22/26.evb +@@ -0,0 +1,83 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts ++10 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts ++11 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts ++41 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv \\ ++ @02:07:04:e6:f1:20:5a:b0:e6\\ ++ @04:07:03:e6:f1:20:5a:b0:e6\\ ++ @06:02:00:78:00:00 ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv \\ ++ @02:07:04:e6:f1:20:5a:b0:e6\\ ++ @04:07:03:e6:f1:20:5a:b0:e6\\ ++ @06:02:00:78:00:00 ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv \\ ++ @02:07:04:e6:f1:20:5a:b0:e6\\ ++ @04:07:03:e6:f1:20:5a:b0:e6\\ ++ @06:02:00:78:00:00 ++90 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/26.sh b/test/qbg22/evb22/26.sh +new file mode 100755 +index 0000000..10abfac +--- /dev/null ++++ b/test/qbg22/evb22/26.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds change setting ++sleep 50; ++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=no +diff --git a/test/qbg22/evb22/3-lldpad.conf b/test/qbg22/evb22/3-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/3-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/3.evb b/test/qbg22/evb22/3.evb +new file mode 100644 +index 0000000..cd80fd0 +--- /dev/null ++++ b/test/qbg22/evb22/3.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv @evb_strr_ack ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr2 end_tlv @evb_strr_ack ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr2 end_tlv @evb_strr_ack ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr2 end_tlv @evb_strr_ack ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/30-lldpad.conf b/test/qbg22/evb22/30-lldpad.conf +new file mode 100644 +index 0000000..0b1dcd8 +--- /dev/null ++++ b/test/qbg22/evb22/30-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "bridge"; ++ evbrrcap = false; ++ evbrrreq = false; ++ evbgpid = false; ++ ecpretries = 5; ++ ecprte = 6; ++ vdprwd = 24; ++ vdprka = 24; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/30.evb b/test/qbg22/evb22/30.evb +new file mode 100644 +index 0000000..49bbe29 +--- /dev/null ++++ b/test/qbg22/evb22/30.evb +@@ -0,0 +1,61 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Runs a station. No reflective relay and sgid support. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:01:00:80:00 end_tlv @evbhead:00:01:stcounts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:00:00 end_tlv @evbhead:00:00:stcounts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:00:00 end_tlv @evbhead:00:00:stcounts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:00:00 end_tlv @evbhead:00:00:stcounts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:00:00 end_tlv @evbhead:00:00:stcounts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/31-lldpad.conf b/test/qbg22/evb22/31-lldpad.conf +new file mode 100644 +index 0000000..e2a7c42 +--- /dev/null ++++ b/test/qbg22/evb22/31-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "bridge"; ++ evbrrcap = true; ++ evbrrreq = false; ++ evbgpid = false; ++ ecpretries = 5; ++ ecprte = 6; ++ vdprwd = 24; ++ vdprka = 24; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/31.evb b/test/qbg22/evb22/31.evb +new file mode 100644 +index 0000000..4b6d8e6 +--- /dev/null ++++ b/test/qbg22/evb22/31.evb +@@ -0,0 +1,62 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Runs a station. Bridge offers reflective relay, ++ * no sgid support. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:01:00:80:00 end_tlv @evbhead:02:01:stcounts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:00:00 end_tlv @evbhead:02:00:stcounts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:00:00 end_tlv @evbhead:02:00:stcounts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:00:00 end_tlv @evbhead:02:00:stcounts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:00:00 end_tlv @evbhead:02:00:stcounts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/32-lldpad.conf b/test/qbg22/evb22/32-lldpad.conf +new file mode 100644 +index 0000000..78608e4 +--- /dev/null ++++ b/test/qbg22/evb22/32-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "bridge"; ++ evbrrcap = true; ++ evbrrreq = false; ++ evbgpid = true; ++ ecpretries = 5; ++ ecprte = 6; ++ vdprwd = 24; ++ vdprka = 24; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/32.evb b/test/qbg22/evb22/32.evb +new file mode 100644 +index 0000000..23127c4 +--- /dev/null ++++ b/test/qbg22/evb22/32.evb +@@ -0,0 +1,62 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Runs a station. Bridge offers reflective relay and ++ * sgid support. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:01:00:80:00 end_tlv @evbhead:06:01:stcounts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:00:00 end_tlv @evbhead:06:00:stcounts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:00:00 end_tlv @evbhead:06:00:stcounts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:00:00 end_tlv @evbhead:06:00:stcounts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:00:00 end_tlv @evbhead:06:00:stcounts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/33-lldpad.conf b/test/qbg22/evb22/33-lldpad.conf +new file mode 100644 +index 0000000..78608e4 +--- /dev/null ++++ b/test/qbg22/evb22/33-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "bridge"; ++ evbrrcap = true; ++ evbrrreq = false; ++ evbgpid = true; ++ ecpretries = 5; ++ ecprte = 6; ++ vdprwd = 24; ++ vdprka = 24; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/33.evb b/test/qbg22/evb22/33.evb +new file mode 100644 +index 0000000..65da9d2 +--- /dev/null ++++ b/test/qbg22/evb22/33.evb +@@ -0,0 +1,62 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Runs a station. Bridge offers eflective relay and ++ * sgid support. Station accepts both. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:0d:00:80:00 end_tlv @evbhead:07:0d:stcounts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0e:00:00:00 end_tlv @evbhead:07:0e:stcounts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0e:00:00:00 end_tlv @evbhead:07:0e:stcounts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0e:00:00:00 end_tlv @evbhead:07:0e:stcounts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0e:00:00:00 end_tlv @evbhead:07:0e:stcounts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/4-lldpad.conf b/test/qbg22/evb22/4-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/4-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/4.evb b/test/qbg22/evb22/4.evb +new file mode 100644 +index 0000000..e64e5b5 +--- /dev/null ++++ b/test/qbg22/evb22/4.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/41-lldpad.conf b/test/qbg22/evb22/41-lldpad.conf +new file mode 100644 +index 0000000..ec9b520 +--- /dev/null ++++ b/test/qbg22/evb22/41-lldpad.conf +@@ -0,0 +1,43 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ }; ++}; +diff --git a/test/qbg22/evb22/41.evb b/test/qbg22/evb22/41.evb +new file mode 100644 +index 0000000..ef941ce +--- /dev/null ++++ b/test/qbg22/evb22/41.evb +@@ -0,0 +1,57 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Do nothing, send data and expect no response. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++35 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++65 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 +diff --git a/test/qbg22/evb22/41.sh b/test/qbg22/evb22/41.sh +new file mode 100755 +index 0000000..03a1d00 +--- /dev/null ++++ b/test/qbg22/evb22/41.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait some seconds and then change setting, define evb22.enableTx=no ++sleep 30; ++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=no ++rc=$? ++if [ $rc -ne 0 ] ++then ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=no" ++ exit $rc ++fi ++ ++sleep 20 ++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=no ++rc=$? ++if [ $rc -ne 0 ] ++then ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=no" ++ exit $rc ++fi ++ ++sleep 10 ++lines="$(fgrep 'enableTx = false;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)" ++ ++if [ "x$lines" != x2 ] ++then ++ rc=5 ++ echo $rc "FAILURE:lldptool -V evbcfg/evb -c enabletx=no" ++fi ++exit $rc +diff --git a/test/qbg22/evb22/42-lldpad.conf b/test/qbg22/evb22/42-lldpad.conf +new file mode 100644 +index 0000000..ec9b520 +--- /dev/null ++++ b/test/qbg22/evb22/42-lldpad.conf +@@ -0,0 +1,43 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ }; ++}; +diff --git a/test/qbg22/evb22/42.evb b/test/qbg22/evb22/42.evb +new file mode 100644 +index 0000000..ef941ce +--- /dev/null ++++ b/test/qbg22/evb22/42.evb +@@ -0,0 +1,57 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Do nothing, send data and expect no response. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++35 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++65 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 +diff --git a/test/qbg22/evb22/42.sh b/test/qbg22/evb22/42.sh +new file mode 100755 +index 0000000..dd9d179 +--- /dev/null ++++ b/test/qbg22/evb22/42.sh +@@ -0,0 +1,65 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait some seconds and then change setting ++sleep 30; ++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=no ++rc=$? ++if [ $rc -ne 0 ] ++then ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=no" ++ exit $rc ++fi ++lines="$(fgrep 'enableTx = false;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)" ++if [ "x$lines" != x1 ] ++then ++ rc=4 ++ echo $rc "FAILURE:lldptool -V evb -c enabletx=no" ++ exit $rc ++fi ++ ++sleep 20 ++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=yes -c fmode=reflectiverelay -c capabilities="rte ecp vdp" ++rc=$? ++if [ $rc -ne 0 ] ++then ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=yes ..." ++ exit $rc ++fi ++ ++lines="$(fgrep 'enableTx = true;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)" ++if [ "x$lines" != x1 ] ++then ++ rc=5 ++ echo $rc "FAILURE:lldptool -V evbcfg -c enabletx=yes ..." ++ echo lines $lines ++ exit $rc ++fi ++exit $rc +diff --git a/test/qbg22/evb22/43-lldpad.conf b/test/qbg22/evb22/43-lldpad.conf +new file mode 100644 +index 0000000..ec9b520 +--- /dev/null ++++ b/test/qbg22/evb22/43-lldpad.conf +@@ -0,0 +1,43 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ }; ++}; +diff --git a/test/qbg22/evb22/43.evb b/test/qbg22/evb22/43.evb +new file mode 100644 +index 0000000..ef941ce +--- /dev/null ++++ b/test/qbg22/evb22/43.evb +@@ -0,0 +1,57 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Do nothing, send data and expect no response. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++35 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++65 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 +diff --git a/test/qbg22/evb22/43.sh b/test/qbg22/evb22/43.sh +new file mode 100755 +index 0000000..4961e59 +--- /dev/null ++++ b/test/qbg22/evb22/43.sh +@@ -0,0 +1,64 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait some seconds and then change setting ++sleep 30; ++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=yes ++rc=$? ++if [ $rc -ne 0 ] ++then ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=yes" ++ exit $rc ++fi ++lines="$(fgrep 'enableTx = true;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)" ++if [ "x$lines" != x1 ] ++then ++ rc=4 ++ echo $rc "FAILURE:lldptool -V evb -c enabletx=no" ++ exit $rc ++fi ++ ++sleep 20 ++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=no -c fmode=reflectiverelay -c capabilities="rte ecp vdp" ++rc=$? ++if [ $rc -ne 0 ] ++then ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=no ..." ++ exit $rc ++fi ++ ++lines="$(fgrep 'enableTx = false;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)" ++if [ "x$lines" != x1 ] ++then ++ rc=5 ++ echo $rc "FAILURE:lldptool -V evbcfg -c enabletx=no ..." ++ exit $rc ++fi ++exit $rc +diff --git a/test/qbg22/evb22/44-lldpad.conf b/test/qbg22/evb22/44-lldpad.conf +new file mode 100644 +index 0000000..ec9b520 +--- /dev/null ++++ b/test/qbg22/evb22/44-lldpad.conf +@@ -0,0 +1,43 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ }; ++}; +diff --git a/test/qbg22/evb22/44.evb b/test/qbg22/evb22/44.evb +new file mode 100644 +index 0000000..d0b552e +--- /dev/null ++++ b/test/qbg22/evb22/44.evb +@@ -0,0 +1,59 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Do nothing, send data and expect no response. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++35 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++65 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++95 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++125 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 +diff --git a/test/qbg22/evb22/44.sh b/test/qbg22/evb22/44.sh +new file mode 100755 +index 0000000..351a478 +--- /dev/null ++++ b/test/qbg22/evb22/44.sh +@@ -0,0 +1,60 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait some seconds and then change setting ++sleep 30; ++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=yes -c fmode=reflectiverelay -c capabilities="rte ecp vdp" ++rc=$? ++if [ $rc -ne 0 ] ++then ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=yes ..." ++ exit $rc ++fi ++ ++sleep 20 ++# Command must not succeed ++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=yes >/dev/null ++rc=$? ++if [ $rc -ne 1 ] ++then ++ rc=4 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=yes" ++ exit $rc ++fi ++rc=0 ++ ++sleep 30 ++lines="$(fgrep 'enableTx = true;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)" ++if [ "x$lines" != x1 ] ++then ++ rc=5 ++ echo $rc "FAILURE:lldptool -V evbcfg/evb -c enabletx=yes" ++fi ++exit $rc +diff --git a/test/qbg22/evb22/45-lldpad.conf b/test/qbg22/evb22/45-lldpad.conf +new file mode 100644 +index 0000000..12b2304 +--- /dev/null ++++ b/test/qbg22/evb22/45-lldpad.conf +@@ -0,0 +1,53 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid001b3f00 : ++ { ++ enableTx = true; ++ fmode = "reflectiverelay"; ++ capabilities = "rte ecp vdp"; ++ }; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/45.evb b/test/qbg22/evb22/45.evb +new file mode 100644 +index 0000000..bdcd955 +--- /dev/null ++++ b/test/qbg22/evb22/45.evb +@@ -0,0 +1,56 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Do nothing, send data and expect no response. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++35 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 +diff --git a/test/qbg22/evb22/45.sh b/test/qbg22/evb22/45.sh +new file mode 100755 +index 0000000..a4dacf7 +--- /dev/null ++++ b/test/qbg22/evb22/45.sh +@@ -0,0 +1,40 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait some seconds and then change setting ++sleep 30; ++rc=0 ++hit="$(fgrep 'evb22_ifup:veth0 evb draft 0.2 protocol already enabled' /tmp/$(basename $0 .sh)-lldpad.conf.out )" ++if [ -z "$hit" ] ++then ++ rc=4 ++ echo $rc "FAILURE:lldpad configuration file has evb and evb22 enabled" ++fi ++exit $rc +diff --git a/test/qbg22/evb22/46-lldpad.conf b/test/qbg22/evb22/46-lldpad.conf +new file mode 100644 +index 0000000..ec9b520 +--- /dev/null ++++ b/test/qbg22/evb22/46-lldpad.conf +@@ -0,0 +1,43 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ }; ++}; +diff --git a/test/qbg22/evb22/46.evb b/test/qbg22/evb22/46.evb +new file mode 100644 +index 0000000..d0b552e +--- /dev/null ++++ b/test/qbg22/evb22/46.evb +@@ -0,0 +1,59 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - Do nothing, send data and expect no response. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++35 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++65 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++95 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 ++125 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 +diff --git a/test/qbg22/evb22/46.sh b/test/qbg22/evb22/46.sh +new file mode 100755 +index 0000000..49142b4 +--- /dev/null ++++ b/test/qbg22/evb22/46.sh +@@ -0,0 +1,60 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait some seconds and then change setting ++sleep 30; ++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=yes ++rc=$? ++if [ $rc -ne 0 ] ++then ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=yes ..." ++ exit $rc ++fi ++ ++sleep 20 ++# command must not succeed ++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=yes -c fmode=reflectiverelay -c capabilities="rte ecp vdp" > /dev/null ++rc=$? ++if [ $rc -ne 1 ] ++then ++ rc=3 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=yes" ++ exit $rc ++fi ++rc=0 ++ ++sleep 10 ++lines="$(fgrep 'enableTx = true;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)" ++if [ "x$lines" != x1 ] ++then ++ rc=5 ++ echo $rc "FAILURE:lldptool -V evbcfg/evb -c enabletx=yes" ++fi ++exit $rc +diff --git a/test/qbg22/evb22/5-lldpad.conf b/test/qbg22/evb22/5-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/5-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/5.evb b/test/qbg22/evb22/5.evb +new file mode 100644 +index 0000000..8367de0 +--- /dev/null ++++ b/test/qbg22/evb22/5.evb +@@ -0,0 +1,75 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation ++ * - bridge offers support for reflective relay. ++ * - station request it. ++ * - bridge withdraws reflective relay support some time later. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:40:00 end_tlv @evbhead:03:05:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts ++41 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts ++60 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:06:00:40:00 end_tlv @evbhead:00:04:counts ++61 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:04:00:40:00 end_tlv @evbhead:00:04:counts ++62 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:04:00:40:00 end_tlv @evbhead:00:04:counts ++63 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:04:00:40:00 end_tlv @evbhead:00:04:counts ++64 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:04:00:40:00 end_tlv @evbhead:00:04:counts ++ ++75 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/6-lldpad.conf b/test/qbg22/evb22/6-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/6-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/6.evb b/test/qbg22/evb22/6.evb +new file mode 100644 +index 0000000..c01377c +--- /dev/null ++++ b/test/qbg22/evb22/6.evb +@@ -0,0 +1,75 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation ++ * - bridge offers support for reflective relay. ++ * - station request it. ++ * - station withdraws reflective relay support some time later. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_brrr end_tlv @evbhead:02:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:04:00:40:00 end_tlv @evbhead:03:05:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts ++41 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts ++ ++75 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/6.sh b/test/qbg22/evb22/6.sh +new file mode 100755 +index 0000000..557cc60 +--- /dev/null ++++ b/test/qbg22/evb22/6.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds change setting ++sleep 50; ++$1/lldptool -i veth0 -gncb -T -V evb -c evbrrreq=no +diff --git a/test/qbg22/evb22/7-lldpad.conf b/test/qbg22/evb22/7-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/7-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/7.evb b/test/qbg22/evb22/7.evb +new file mode 100644 +index 0000000..ea13107 +--- /dev/null ++++ b/test/qbg22/evb22/7.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. RTE value is higher than on station. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:1f:40:00 end_tlv @evbhead:00:04:7f:88:08 ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:1f:40:00 end_tlv @evbhead:00:04:7f:88:08 ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:1f:40:00 end_tlv @evbhead:00:04:7f:88:08 ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:1f:40:00 end_tlv @evbhead:00:04:7f:88:08 ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/8-lldpad.conf b/test/qbg22/evb22/8-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/8-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/8.evb b/test/qbg22/evb22/8.evb +new file mode 100644 +index 0000000..26b10c7 +--- /dev/null ++++ b/test/qbg22/evb22/8.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. RTE value is lower than on station. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/80-lldpad.conf b/test/qbg22/evb22/80-lldpad.conf +new file mode 100644 +index 0000000..456da71 +--- /dev/null ++++ b/test/qbg22/evb22/80-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/80.evb b/test/qbg22/evb22/80.evb +new file mode 100644 +index 0000000..12924b9 +--- /dev/null ++++ b/test/qbg22/evb22/80.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/80.sh b/test/qbg22/evb22/80.sh +new file mode 100755 +index 0000000..fb8e3fa +--- /dev/null ++++ b/test/qbg22/evb22/80.sh +@@ -0,0 +1,47 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++# Replace newlines by blanks for easier comparison ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c | tr '\n' ' ') ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ #echo out ":$out:" ++ if [ "$out" != "vdprka=8 vdprwd=8 ecprte=8 ecpretries=3 evbrrreq=yes evbrrcap=no evbgpid=yes evbmode=station enableTx=yes " ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" +diff --git a/test/qbg22/evb22/81-lldpad.conf b/test/qbg22/evb22/81-lldpad.conf +new file mode 100644 +index 0000000..456da71 +--- /dev/null ++++ b/test/qbg22/evb22/81-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/81.evb b/test/qbg22/evb22/81.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/81.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/81.sh b/test/qbg22/evb22/81.sh +new file mode 100755 +index 0000000..03490ca +--- /dev/null ++++ b/test/qbg22/evb22/81.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c enabletx=no ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=no" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c enabletx) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "enableTx=no" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/82-lldpad.conf b/test/qbg22/evb22/82-lldpad.conf +new file mode 100644 +index 0000000..456da71 +--- /dev/null ++++ b/test/qbg22/evb22/82-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/82.evb b/test/qbg22/evb22/82.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/82.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/82.sh b/test/qbg22/evb22/82.sh +new file mode 100755 +index 0000000..4db9e0b +--- /dev/null ++++ b/test/qbg22/evb22/82.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c evbmode=bridge ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c evbmode=bridge" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c evbmode) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "evbmode=bridge" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/83-lldpad.conf b/test/qbg22/evb22/83-lldpad.conf +new file mode 100644 +index 0000000..456da71 +--- /dev/null ++++ b/test/qbg22/evb22/83-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/83.evb b/test/qbg22/evb22/83.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/83.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/83.sh b/test/qbg22/evb22/83.sh +new file mode 100755 +index 0000000..fbdce26 +--- /dev/null ++++ b/test/qbg22/evb22/83.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c evbrrreq=no ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c evbrrreq=no" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c evbrrreq) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "evbrrreq=no" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/84-lldpad.conf b/test/qbg22/evb22/84-lldpad.conf +new file mode 100644 +index 0000000..20ef072 +--- /dev/null ++++ b/test/qbg22/evb22/84-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/84.evb b/test/qbg22/evb22/84.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/84.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/84.sh b/test/qbg22/evb22/84.sh +new file mode 100755 +index 0000000..092f35a +--- /dev/null ++++ b/test/qbg22/evb22/84.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c evbrrcap=no ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c evbrrcap=no" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c evbrrcap) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "evbrrcap=no" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/85-lldpad.conf b/test/qbg22/evb22/85-lldpad.conf +new file mode 100644 +index 0000000..20ef072 +--- /dev/null ++++ b/test/qbg22/evb22/85-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/85.evb b/test/qbg22/evb22/85.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/85.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/85.sh b/test/qbg22/evb22/85.sh +new file mode 100755 +index 0000000..597a3ff +--- /dev/null ++++ b/test/qbg22/evb22/85.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c evbgpid=no ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c evbgpid=no" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c evbgpid) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "evbgpid=no" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/86-lldpad.conf b/test/qbg22/evb22/86-lldpad.conf +new file mode 100644 +index 0000000..20ef072 +--- /dev/null ++++ b/test/qbg22/evb22/86-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/86.evb b/test/qbg22/evb22/86.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/86.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/86.sh b/test/qbg22/evb22/86.sh +new file mode 100755 +index 0000000..882220f +--- /dev/null ++++ b/test/qbg22/evb22/86.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c ecpretries=7 ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c ecpretries=7" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c ecpretries) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "ecpretries=7" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/87-lldpad.conf b/test/qbg22/evb22/87-lldpad.conf +new file mode 100644 +index 0000000..20ef072 +--- /dev/null ++++ b/test/qbg22/evb22/87-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/87.evb b/test/qbg22/evb22/87.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/87.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/87.sh b/test/qbg22/evb22/87.sh +new file mode 100755 +index 0000000..17f7b96 +--- /dev/null ++++ b/test/qbg22/evb22/87.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c ecprte=31 ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c ecprte=31" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c ecprte) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "ecprte=31" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/88-lldpad.conf b/test/qbg22/evb22/88-lldpad.conf +new file mode 100644 +index 0000000..20ef072 +--- /dev/null ++++ b/test/qbg22/evb22/88-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/88.evb b/test/qbg22/evb22/88.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/88.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/88.sh b/test/qbg22/evb22/88.sh +new file mode 100755 +index 0000000..3474e77 +--- /dev/null ++++ b/test/qbg22/evb22/88.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c vdprwd=31 ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c vdprwd=31" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c vdprwd) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "vdprwd=31" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/89-lldpad.conf b/test/qbg22/evb22/89-lldpad.conf +new file mode 100644 +index 0000000..20ef072 +--- /dev/null ++++ b/test/qbg22/evb22/89-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/89.evb b/test/qbg22/evb22/89.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/89.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/89.sh b/test/qbg22/evb22/89.sh +new file mode 100755 +index 0000000..a10330e +--- /dev/null ++++ b/test/qbg22/evb22/89.sh +@@ -0,0 +1,58 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++$1/lldptool -i veth0 -gncb -T -V evb -c vdprka=31 ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ let rc=98 ++ echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c vdprka=31" ++ exit $rc ++fi ++ ++sleep 3 ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb -c vdprka) ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "vdprka=31" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/9-lldpad.conf b/test/qbg22/evb22/9-lldpad.conf +new file mode 100644 +index 0000000..ebe91e0 +--- /dev/null ++++ b/test/qbg22/evb22/9-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/9.evb b/test/qbg22/evb22/9.evb +new file mode 100644 +index 0000000..46ce2b6 +--- /dev/null ++++ b/test/qbg22/evb22/9.evb +@@ -0,0 +1,60 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge does not support reflective relay but station ++ * requests it. RKA value is higher than on station. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:04:1f end_tlv @evbhead:00:04:68:88:3f ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:04:1f end_tlv @evbhead:00:04:68:88:3f ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:04:1f end_tlv @evbhead:00:04:68:88:3f ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:00:00:00:04:1f end_tlv @evbhead:00:04:68:88:3f ++15 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/90-lldpad.conf b/test/qbg22/evb22/90-lldpad.conf +new file mode 100644 +index 0000000..20ef072 +--- /dev/null ++++ b/test/qbg22/evb22/90-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "0452540050244E"; ++ }; ++ tlvid00000002 : ++ { ++ info = "0352540050244E"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 8; ++ vdprwd = 8; ++ vdprka = 8; ++ }; ++ }; ++}; +diff --git a/test/qbg22/evb22/90.evb b/test/qbg22/evb22/90.evb +new file mode 100644 +index 0000000..3b88d6c +--- /dev/null ++++ b/test/qbg22/evb22/90.evb +@@ -0,0 +1,72 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - bridge offers support for reflective relay and station ++ * requests it. Bridge and station set group id bit. ++ */ ++ ++#include "defines.evb" ++ ++5 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts ++6 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts ++7 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++8 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++9 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts ++51 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++52 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++53 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++54 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++55 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evbhead:07:05:00:40:00 end_tlv ++80 lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/90.sh b/test/qbg22/evb22/90.sh +new file mode 100755 +index 0000000..1492d3b +--- /dev/null ++++ b/test/qbg22/evb22/90.sh +@@ -0,0 +1,47 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single task on the machine running lldpad ++# ++ ++# Wait 50 seconds before executing command ++sleep 50; ++ ++out=$($1/lldptool -i veth0 -gncb -t -V evb | tr -d '\t\n') ++rc=$? ++if [ "$rc" -eq 0 ] ++then ++ # echo out ":$out:" ++ if [ "$out" != "EVB Configuration TLVbridge:bgid,rrcap,rrctr(0x7)station:sgid,rrreq,rrstat(0xd)retries:3 rte:8mode:station r/l:0 rwd:8r/l:0 rka:8" ] ++ then ++ rc=99 ++ fi ++fi ++# First field contains exit code of shell script, 0 for success anything else ++# for failure. ++echo $rc ":$out:" ++exit $rc +diff --git a/test/qbg22/evb22/README b/test/qbg22/evb22/README +new file mode 100644 +index 0000000..f9814b4 +--- /dev/null ++++ b/test/qbg22/evb22/README +@@ -0,0 +1,142 @@ ++# ++# Implementation of EVB according to IEEE 802.1Qbg ratified standard ++# (c) Copyright IBM Corp. 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# The full GNU General Public License is included in this distribution in ++# the file called "COPYING". ++# ++ ++ ++Test cases for IEEE802.1Qbg ratified standard EVB module. ++To test this setup: ++- on bridge_ns 'qbg22sim -v -v -v -d 30 veth2' to display any messages. ++- on 'qbg22sim -v -v -v -d 20 veth0 brtest.evb' to send 5 messages. ++On netns2 name space messages with EVB TLV should be displayed. ++ ++Files ++===== ++There are 3 shell scripts which are executed on f18a ++allevb.sh: Runs all test cases with file names [1-9]*.evb. Uses ++ runevb.sh to execute one test case. ++ On success the exit code is zero, on failure none zero. ++ A none zero exit code termintes the evball.sh immediately. ++runevb.sh Runs one test case. ++ Return 0 on success and none zero otherwise. ++ Uses ssh for remote communication between virtual machines ++ and predefined pathes/IP addresses. ++24.sh .sh contain shell scripts to be executed ++ on the remote virtual machine. Usually done to change some ++ lldpad configuration settings during execution of lldpad. ++ ++Tests ++===== ++The following test cases are executed. Each test case has a number. ++All test cases need a lldpad.conf configuration file and an qbg22sim input ++file: ++- The qbg22sim input files have the extension .evb. ++- The lldpad configuration file has the extension -lldpad.conf ++ ++The purpose is to trigger an EVB DU exchange between qbg22sim and llpdad. ++The exchanged data can be inspected automaticly with little inteligence ++(see qbg22sim.1) or manually. ++ ++Test Description ++1 Neither station nor bridge support refective-relay. ++2 Station denies reflective-relay but bridge offers it. ++3 Station request reflective-relay but bridge does not support it. ++4 Station request reflective-relay and bridge supports it. ++5 Station request reflective-relay and bridge supports it. After some ++ time bridge turns off reflective relay support. ++6 Station request reflective-relay and bridge supports it. After some ++ time station does not request reflective relay support anymore. ++7 Use different RTE value. Local value is higher. ++8 Use different RTE value. Local value is lower. ++9 Use different RKA value. Local value is higher. ++10 Use different RKA value. Local value is lower. ++11 Use different RWD value. Local value is lower. ++12 Use different RWD value. Local value is higher. ++13 Use different retry value. Local value is higher. ++14 Use different retry value. Local value is lower. ++20 Station request reflective-relay and bridge supports it. Bridge sets ++ group id support, but station denies this. ++21 Station request reflective-relay and bridge supports it. Station sets ++ group id support, but bridge denies this. ++22 Station request reflective-relay and bridge supports it. Bridge sets ++ group id support, station sets group id support. ++23 Station request reflective-relay and bridge supports it. Bridge sets ++ group id support, station sets group id support. Bridge turns it off. ++24 Station request reflective-relay and bridge supports it. Bridge sets ++ group id support, station sets group id support. Station turns it off. ++25 Station request reflective-relay and bridge supports it. EVB TLV ++ transmission turned off. ++26 Station request reflective-relay and bridge supports it. EVB TLV ++ changed after 30 seconds via lldptool on station side ++30 Lldpad runs as bridge no reflective relay support. ++31 Lldpad runs as bridge with reflective relay support. ++32 Lldpad runs as bridge with reflective relay support and bgid support. ++33 Lldpad runs as bridge with reflective relay support and bgid support. ++ Station runs with reflective relay and sgid support ++41 Check for creation of evb.enableTx=off and evb22.enableTx=off ++42 Check for creation of evb.enableTx=on and evb22.enableTx=off ++43 Check for creation of evb.enableTx=off and evb22.enableTx=on ++44 Check for creation of evb.enableTx=on and evb22.enableTx=on ++45 Check for evb.enableTx=on and evb22.enableTx=on in config file ++46 Check for creation of evb22.enableTx=on and evb.enableTx=on ++80 Check for lldptool command using evb22 protocol display evb22 (-c only) ++90 Check for lldptool command using evb22 protocol display evb22 ++81-89 Check for lldptool command using evb22 protocol turn off various parms ++ ++Remarks: ++On some tests the warning "expect_reply reply to message sent (xx sec) missing ++may appear or not. This is randon, sometime all tests run without any warning ++at all, sometimes several tests display this warning. ++The warning can be ignored. The warning is displayed be the qbg22sim program ++only when an expected reply has not been received in time (1 second). ++The reason is: ++1. qbg22sim sends out and LLDP message ++2. lldpad receives the message and updates its MIB ++3. lldpad waits about 900ms until it sends out its updated LLDP TLS ++4. Mostly qbg22sim gets the reply from lldpad before it sends the next EVB TLV ++ one second later. In vary rare cases the TLVs are received after the timer ++ in qbg22sim expired and the next message is sent. When the next message is ++ sent and no reply received, the warning is issue. ++5. This is no problem at all. The LLDP standard says the messages are exchanged ++ in 1 second intervals without any handshaking at all. Each party simply ++ transmit its current status. ++ ++Test Execution ++============== ++Directory structure: ++The following directory structure is assumed: ++/home/richter/dcn/qbg/mywork/open-lldp --> lldpad ++/home/richter/dcn/qbg/mywork/open-lldp --> qbg22sim ++/home/richter/dcn/qbg/mywork/nstest/qbg22/evb22 --> EVB protocol test cases ++ ++To allow flexibility the path to execute the executables can be specified. ++Set the PATH variable properly. ++ ++Select the qbg22sim simulation program by adding a symbolic link ++directory ++1. cd /home/richter/dcn/qbg/mywork/test/qbg22/evb22 ++2. Create a symbolic link to the qbg22sim program ++ to use. Something like 'ln -s ../../../open-lldp-new/qbg22sim' ++3. Add the environment variable LLDPAD_DIR=abc to select an different lldpad ++ executable. For example the invocation ++ LLDPAD_DIR=open-lldp-new evball.sh ++ selects the file /home/richter/dcn/qbg/mywork/open-lldp-new/lldpad ++ for execution. +diff --git a/test/qbg22/evb22/allevb.sh b/test/qbg22/evb22/allevb.sh +new file mode 100755 +index 0000000..62b3fb2 +--- /dev/null ++++ b/test/qbg22/evb22/allevb.sh +@@ -0,0 +1,64 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Configuration file for unknwon vsi data test cases ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute the complete evb test suite. ++# ++ ++runcommand() ++{ ++ # echo parameter $@ ++ cmd=$1 ++ file=$2 ++ ++ echo "start testcase $number" ++ $cmd $file $@ 2>&1 ++ rc="$?" ++ if [ "$rc" -ne 0 ] ++ then ++ echo -en "\\033[1;31m" # Failures in red ++ echo "ERROR $file exit with $rc" ++ echo -en "\\033[0;39m" ++ exit 2 ++ fi ++ echo -en "\\033[1;32m" # Success in green ++ echo "OK testcase $file" ++ echo -en "\\033[0;39m" ++ return 0 ++} ++ ++if ! which runevb.sh 2>/dev/null ++then ++ export PATH=$PATH:$PWD ++fi ++ ++echo "Start testsuite at $(date)" ++for i in $(ls [1-9]*.evb|sort -n) ++do ++ runcommand runevb.sh $i ++done ++echo "Stop testsuite at $(date)" ++exit 0 +diff --git a/test/qbg22/evb22/brtest.evb b/test/qbg22/evb22/brtest.evb +new file mode 100644 +index 0000000..8871830 +--- /dev/null ++++ b/test/qbg22/evb22/brtest.evb +@@ -0,0 +1,69 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ * The first column defines the run time of the test program in seconds ++ * when the remaining data on this line will be sent. The rest of the line are ++ * data fields which define the TLVs. ++ * Line limit is 5KB, long lines can be split with \\ as last character. ++ * ++ * The files are preprocessed with cpp before being read by the test program. ++ * ++ * The data fields per line are ++ * 1. time ++ * 2. destination MAC ++ * 3. source MAC (dash(-) replaced by the senders MAC address) ++ * 4. ethertype ++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are ++ * chassis-id, port-id, ttl and end) ++ * 6. Optional. Several TLVs starting with @ which are expected results. ++ * Its an error is it is missing in the reply or TLV differs. ++ */ ++/* ++ * EVB negotiation - test virtual bridge forwards mac multicast to ++ * nearest customer bridge (01:80:c2:00:00:00). ++ */ ++ ++#define dst_mac 01:80:c2:00:00:00 ++#define lldp_type 88:cc ++#define chassis_tlv 02:07:06:64:75:6d:6d:79:00 ++#define port_tlv 04:05:05:65:74:68:30 ++#define ttl_tlv120 06:02:00:78 ++#define ttl_tlv0 06:02:00:00 ++#define end_tlv 00:00 ++ ++#define evbhead fe:09:00:80:c2:0d ++#define evb_norr evbhead:00:00:00:40:00 ++ ++5 dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv ++6 dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv ++7 dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv ++8 dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\ ++ evb_norr end_tlv ++15 dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv +diff --git a/test/qbg22/evb22/defines.evb b/test/qbg22/evb22/defines.evb +new file mode 100644 +index 0000000..7e01a75 +--- /dev/null ++++ b/test/qbg22/evb22/defines.evb +@@ -0,0 +1,53 @@ ++/* ++ * Implementation of EVB according to IEEE 802.1Qbg ++ * (c) Copyright IBM Corp. 2014 ++ * ++ * Author(s): Thomas Richter ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set ++ * is needed for each transmission. ++ */ ++/* ++ * Very common defines ++ */ ++ ++#define lldpad_mac 01:80:c2:00:00:00 ++#define lldp_type 88:cc ++#define chassis_tlv 02:07:06:64:75:6d:6d:79:00 ++#define port_tlv 04:05:05:65:74:68:30 ++#define ttl_tlv120 06:02:00:78 ++#define ttl_tlv0 06:02:00:00 ++#define end_tlv 00:00 ++ ++#define evbhead fe:09:00:80:c2:0d ++#define counts 68:88:08 ++#define stcounts a6:58:18 ++ ++/* No Reflective Relay on bridge */ ++#define evb_norr evbhead:00:00:00:40:00 ++#define evb_norr_ack evbhead:00:00:counts ++/* Bridge offers reflective-relay */ ++#define evb_brrr evbhead:02:00:00:40:00 ++#define evb_brrr_ack evbhead:02:00:counts ++/* Station request reflective relay */ ++#define evb_norr2 evbhead:00:04:00:40:00 ++#define evb_strr_ack evbhead:00:04:counts +diff --git a/test/qbg22/evb22/runevb.sh b/test/qbg22/evb22/runevb.sh +new file mode 100755 +index 0000000..c4cc88c +--- /dev/null ++++ b/test/qbg22/evb22/runevb.sh +@@ -0,0 +1,152 @@ ++#!/bin/bash ++# ++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single test. Parameter is the name of the test file ++# ++ ++# Check if lldpad is up and running. Return pid or 0 if not running. ++# Note that lldpad may be started without creating a PID file. If no PID file ++# exists, use the lldptool to query the PID of lldpad. ++function lldpad_up() ++{ ++ if [ ! -r /var/run/lldpad.pid ] ++ then ++ pidfile=$(../../../lldptool -p 2>/dev/null) ++ if [ "$?" -ne 0 ] ++ then ++ return 0 ++ fi ++ else ++ pidfile="$(cat /var/run/lldpad.pid)" ++ fi ++ if [ -z "$pidfile" ] ++ then ++ return 0 ++ else ++ ps -p $pidfile -o pid --no-header > /dev/null ++ if [ $? -ne 0 ] ++ then ++ return 0 ++ fi ++ fi ++ echo "LLDPAD running pid $pidfile" ++ return $pidfile ++} ++ ++function lldpad_down() ++{ ++ if [ ! -r /var/run/lldpad.pid ] ++ then ++ pidfile=$(../../../lldptool -p 2>/dev/null) ++ if [ "$?" -ne 0 ] ++ then ++ return 1 ++ fi ++ else ++ pidfile="$(cat /var/run/lldpad.pid)" ++ fi ++ if [ -z "$pidfile" ] ++ then ++ return 1 ++ fi ++ kill -s SIGTERM $pidfile ++ sleep 1 ++ ps -p $pidfile -o pid --no-header > /dev/null ++ if [ $? -ne 1 ] ++ then ++ kill -s SIGKILL $pidfile ++ fi ++ return 0 ++} ++ ++# Use the correct lldpad configuration file and start lldpad. ++# Parameter 1: path to lldpad to use ++# Parameter 2: name of configuration file ++function lldpad_start() ++{ ++ if lldpad_up ++ then ++ rm -f /var/lib/lldpad/lldpad.conf ./lldpad.conf ++ cp $2 /tmp/$2 ++ $1/lldpad -V7 -f /tmp/$2 >/tmp/$2.out 2>&1 & ++ sleep 1 ++ if lldpad_up ++ then ++ echo "$0:lldpad not started or terminated unexpectedly" ++ exit 1 ++ fi ++ else ++ exit 1 ++ fi ++ return 0 ++} ++ ++if ! which runevb.sh 1>/dev/null 2>/dev/null ++then ++ export PATH=$PATH:$PWD ++fi ++ ++# Extract type of test case from last 3 characters of invocation ++type=$(basename $0) ++type=".${type:3:3}" ++ ++testfile=$1 ++no=$(basename $testfile $type) ++ ++# Start lldpad using this name space ++if ! lldpad_start ../../.. $no-lldpad.conf ++then ++ echo "$0:can not start lldpad" ++ exit 1 ++fi ++ ++# Check for shell script to run in parallel ++if [ -r "./$no.sh" -a -x "./$no.sh" ] ++then ++ ./$no.sh ../../.. > /tmp/$no.sh.out & ++fi ++ ++# get the duration from the last entry in the test file. ++duration=$(cpp $testfile | cut -f1 -d' ' | sed '/^$/d' | tail -1) ++let duration=duration+5 ++ ++# run the test with output save to /tmp/testfile.out ++ip netns exec bridge_ns ../../../qbg22sim -v -v -v -T 5000000 -d $duration veth2 $testfile > /tmp/$testfile.out ++rc=$? ++ ++# Stop lldpad ++if ! lldpad_down ++then ++ echo "$0:can not stop lldpad" ++ exit 1 ++fi ++ ++# Check for output file script to test result of test case ++if [ -r "/tmp/$no.sh.out" ] ++then ++ rc=$(cut -f1 -d' ' "/tmp/$no.sh.out") ++fi ++ ++exit $rc +diff --git a/test/qbg22/vdp22/100-lldpad.conf b/test/qbg22/vdp22/100-lldpad.conf +new file mode 100644 +index 0000000..9c76b9c +--- /dev/null ++++ b/test/qbg22/vdp22/100-lldpad.conf +@@ -0,0 +1,55 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = false; ++ evbmode = "station"; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/100.nlc b/test/qbg22/vdp22/100.nlc +new file mode 100755 +index 0000000..5d746ba +--- /dev/null ++++ b/test/qbg22/vdp22/100.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc/de-assoc test. Station has no EVB TLV disabled ++# Expect failure ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1,e=-93 -s,w=10 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/100.vdp b/test/qbg22/vdp22/100.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/100.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/101-lldpad.conf b/test/qbg22/vdp22/101-lldpad.conf +new file mode 100644 +index 0000000..ff35cc7 +--- /dev/null ++++ b/test/qbg22/vdp22/101-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "bridge"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/101.nlc b/test/qbg22/vdp22/101.nlc +new file mode 100755 +index 0000000..b63c8a5 +--- /dev/null ++++ b/test/qbg22/vdp22/101.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc and expect error because lldpad runs in bridge role. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1,e=-95 -s,w=5 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/101.vdp b/test/qbg22/vdp22/101.vdp +new file mode 100644 +index 0000000..9ae4eaa +--- /dev/null ++++ b/test/qbg22/vdp22/101.vdp +@@ -0,0 +1,57 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/102-lldpad.conf b/test/qbg22/vdp22/102-lldpad.conf +new file mode 100644 +index 0000000..2ea4e18 +--- /dev/null ++++ b/test/qbg22/vdp22/102-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = false; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/102.nlc b/test/qbg22/vdp22/102.nlc +new file mode 100755 +index 0000000..8dd7558 +--- /dev/null ++++ b/test/qbg22/vdp22/102.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc/de-assoc test. Station has no RR capabililty requested. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1 -s,w=30 -d vm1 -s,w=10 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/102.vdp b/test/qbg22/vdp22/102.vdp +new file mode 100644 +index 0000000..1f56138 +--- /dev/null ++++ b/test/qbg22/vdp22/102.vdp +@@ -0,0 +1,47 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ } ++}; +diff --git a/test/qbg22/vdp22/103-lldpad.conf b/test/qbg22/vdp22/103-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/103-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/103.nlc b/test/qbg22/vdp22/103.nlc +new file mode 100755 +index 0000000..69fbdbc +--- /dev/null ++++ b/test/qbg22/vdp22/103.nlc +@@ -0,0 +1,35 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc/de-assoc test. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -s,w=30 -a vm1,w=20 -s,w=60 -d vm1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/103.vdp b/test/qbg22/vdp22/103.vdp +new file mode 100644 +index 0000000..5b1f36a +--- /dev/null ++++ b/test/qbg22/vdp22/103.vdp +@@ -0,0 +1,47 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/104-lldpad.conf b/test/qbg22/vdp22/104-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/104-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/104.nlc b/test/qbg22/vdp22/104.nlc +new file mode 100755 +index 0000000..ea3c17c +--- /dev/null ++++ b/test/qbg22/vdp22/104.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute two simple assoc/de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1 -s,w=5 -a vm2 -s,w=60 -d vm1 -d vm2 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/104.vdp b/test/qbg22/vdp22/104.vdp +new file mode 100644 +index 0000000..5de5046 +--- /dev/null ++++ b/test/qbg22/vdp22/104.vdp +@@ -0,0 +1,45 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/105-lldpad.conf b/test/qbg22/vdp22/105-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/105-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/105.nlc b/test/qbg22/vdp22/105.nlc +new file mode 100755 +index 0000000..4ee9d30 +--- /dev/null ++++ b/test/qbg22/vdp22/105.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc/de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm1 -s,w=45 -d vm1 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/105.vdp b/test/qbg22/vdp22/105.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/105.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/106-lldpad.conf b/test/qbg22/vdp22/106-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/106-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/106.nlc b/test/qbg22/vdp22/106.nlc +new file mode 100755 +index 0000000..833051a +--- /dev/null ++++ b/test/qbg22/vdp22/106.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute two pre-assoc/de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm1 -s,w=5 -p vm2 -s,w=60 -d vm1 -d vm2 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/106.vdp b/test/qbg22/vdp22/106.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/106.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/107-lldpad.conf b/test/qbg22/vdp22/107-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/107-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/107.nlc b/test/qbg22/vdp22/107.nlc +new file mode 100755 +index 0000000..99d80a0 +--- /dev/null ++++ b/test/qbg22/vdp22/107.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc-rr/de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -r vm1 -s,w=45 -d vm1 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/107.vdp b/test/qbg22/vdp22/107.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/107.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/108-lldpad.conf b/test/qbg22/vdp22/108-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/108-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/108.nlc b/test/qbg22/vdp22/108.nlc +new file mode 100755 +index 0000000..8381135 +--- /dev/null ++++ b/test/qbg22/vdp22/108.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc/pre-assoc test. Expect error. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1 -s,w=45 -p vm1,e=-22 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/108.vdp b/test/qbg22/vdp22/108.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/108.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/110-lldpad.conf b/test/qbg22/vdp22/110-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/110-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/110.nlc b/test/qbg22/vdp22/110.nlc +new file mode 100755 +index 0000000..7878340 +--- /dev/null ++++ b/test/qbg22/vdp22/110.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc/pre-assoc-rr/assoc/de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm1 -s,w=30 -r vm1 -s,w=30 -a vm1 -s,w=30 -d vm1 -s,w=10 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/110.vdp b/test/qbg22/vdp22/110.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/110.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/111-lldpad.conf b/test/qbg22/vdp22/111-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/111-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/111.nlc b/test/qbg22/vdp22/111.nlc +new file mode 100755 +index 0000000..4f15b28 +--- /dev/null ++++ b/test/qbg22/vdp22/111.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc/pre-assoc/de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm1 -s,w=30 -p vm1 -s,w=30 -d vm1 -s,w=10 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/111.vdp b/test/qbg22/vdp22/111.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/111.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/112-lldpad.conf b/test/qbg22/vdp22/112-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/112-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/112.nlc b/test/qbg22/vdp22/112.nlc +new file mode 100755 +index 0000000..6b14209 +--- /dev/null ++++ b/test/qbg22/vdp22/112.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc-rr/pre-assoc-rr/de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -r vm1 -s,w=30 -r vm1 -s,w=30 -d vm1 -s,w=10 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/112.vdp b/test/qbg22/vdp22/112.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/112.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/113-lldpad.conf b/test/qbg22/vdp22/113-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/113-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/113.nlc b/test/qbg22/vdp22/113.nlc +new file mode 100755 +index 0000000..bd53ba6 +--- /dev/null ++++ b/test/qbg22/vdp22/113.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc/assoc/de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1 -s,w=36 -a vm1 -s,w=37 -d vm1 -s,w=10 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/113.vdp b/test/qbg22/vdp22/113.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/113.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/114-lldpad.conf b/test/qbg22/vdp22/114-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/114-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/114.nlc b/test/qbg22/vdp22/114.nlc +new file mode 100755 +index 0000000..97ba73a +--- /dev/null ++++ b/test/qbg22/vdp22/114.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple de-assoc test. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -d vm1,e=-22 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/114.vdp b/test/qbg22/vdp22/114.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/114.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/115-lldpad.conf b/test/qbg22/vdp22/115-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/115-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/115.nlc b/test/qbg22/vdp22/115.nlc +new file mode 100755 +index 0000000..58af2db +--- /dev/null ++++ b/test/qbg22/vdp22/115.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with error returned ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm201,e=2 -s,w=5 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/115.vdp b/test/qbg22/vdp22/115.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/115.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/116-lldpad.conf b/test/qbg22/vdp22/116-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/116-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/116.nlc b/test/qbg22/vdp22/116.nlc +new file mode 100755 +index 0000000..da6448a +--- /dev/null ++++ b/test/qbg22/vdp22/116.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc with error returned after 1. keep alive message. ++# Expect de-assoc response after first KA message ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -Cnew=vmxxx,name=vm201,typeidver=2 -i veth0 -a vmxxx -g,e=1,w=60 -s,w=20 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/116.vdp b/test/qbg22/vdp22/116.vdp +new file mode 100644 +index 0000000..1f56138 +--- /dev/null ++++ b/test/qbg22/vdp22/116.vdp +@@ -0,0 +1,47 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ } ++}; +diff --git a/test/qbg22/vdp22/117-lldpad.conf b/test/qbg22/vdp22/117-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/117-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/117.nlc b/test/qbg22/vdp22/117.nlc +new file mode 100755 +index 0000000..89864df +--- /dev/null ++++ b/test/qbg22/vdp22/117.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with unsolicited de-assoc message from switch ++# Expect unsolicited message from lldpad. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm200 -g,e=1,w=90 -s,w=20 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/117.vdp b/test/qbg22/vdp22/117.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/117.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/118-lldpad.conf b/test/qbg22/vdp22/118-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/118-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/118.nlc b/test/qbg22/vdp22/118.nlc +new file mode 100755 +index 0000000..32083a6 +--- /dev/null ++++ b/test/qbg22/vdp22/118.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc with error returned ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm201,e=2 -s,w=5 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/118.vdp b/test/qbg22/vdp22/118.vdp +new file mode 100644 +index 0000000..171d0a0 +--- /dev/null ++++ b/test/qbg22/vdp22/118.vdp +@@ -0,0 +1,44 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/119-lldpad.conf b/test/qbg22/vdp22/119-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/119-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/119.nlc b/test/qbg22/vdp22/119.nlc +new file mode 100755 +index 0000000..b46ff6b +--- /dev/null ++++ b/test/qbg22/vdp22/119.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc-rr with error returned after 1. keep alive message. ++# Expect unsolicited message from lldpad. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -Cnew=vm999,name=vm201,typeidver=2 -i veth0 -r vm999 -g,e=1,w=60 -s,w=20 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/119.vdp b/test/qbg22/vdp22/119.vdp +new file mode 100644 +index 0000000..48d5499 +--- /dev/null ++++ b/test/qbg22/vdp22/119.vdp +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/120-lldpad.conf b/test/qbg22/vdp22/120-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/120-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/120.nlc b/test/qbg22/vdp22/120.nlc +new file mode 100755 +index 0000000..ea8d2cb +--- /dev/null ++++ b/test/qbg22/vdp22/120.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc with unsolicited de-assoc message from switch ++# Expect unsolicited message from lldpad. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm200 -g,e=1,w=90 -s,w=20 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/120.vdp b/test/qbg22/vdp22/120.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/120.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/121-lldpad.conf b/test/qbg22/vdp22/121-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/121-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/121.nlc b/test/qbg22/vdp22/121.nlc +new file mode 100755 +index 0000000..761dec4 +--- /dev/null ++++ b/test/qbg22/vdp22/121.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with keep-error returned after 1. keep alive message. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm202 -g,e=1,w=60 -s,w=20 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/121.vdp b/test/qbg22/vdp22/121.vdp +new file mode 100644 +index 0000000..48d5499 +--- /dev/null ++++ b/test/qbg22/vdp22/121.vdp +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/122-lldpad.conf b/test/qbg22/vdp22/122-lldpad.conf +new file mode 100644 +index 0000000..fdbb132 +--- /dev/null ++++ b/test/qbg22/vdp22/122-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/122.nlc b/test/qbg22/vdp22/122.nlc +new file mode 100755 +index 0000000..c2fc425 +--- /dev/null ++++ b/test/qbg22/vdp22/122.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple pre-assoc with hard-error returned from switch ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -Cnew=vmxxx,name=vm201,typeid=203 -p vmxxx,e=18 -s,w=5 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/122.vdp b/test/qbg22/vdp22/122.vdp +new file mode 100644 +index 0000000..48d5499 +--- /dev/null ++++ b/test/qbg22/vdp22/122.vdp +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/123-lldpad.conf b/test/qbg22/vdp22/123-lldpad.conf +new file mode 100644 +index 0000000..7e61fbc +--- /dev/null ++++ b/test/qbg22/vdp22/123-lldpad.conf +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ tlvid0080c20d : ++ { ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = false; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 15; ++ vdprka = 20; ++ }; ++ }; ++}; +diff --git a/test/qbg22/vdp22/123.nlc b/test/qbg22/vdp22/123.nlc +new file mode 100755 +index 0000000..006a1b6 +--- /dev/null ++++ b/test/qbg22/vdp22/123.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc test and expect resource wait delay timeout ++# from bridge. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm199,w=15000,d=12000 -s,w=30 ++rc=$? ++exit $rc +diff --git a/test/qbg22/vdp22/123.vdp b/test/qbg22/vdp22/123.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/123.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/200-lldpad.conf b/test/qbg22/vdp22/200-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/200-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/200.nlc b/test/qbg22/vdp22/200.nlc +new file mode 100755 +index 0000000..88e3112 +--- /dev/null ++++ b/test/qbg22/vdp22/200.nlc +@@ -0,0 +1,35 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc/de-assoc test. Use command line interface ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_1 -s,w=30 -d vm2_1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/200.vdp b/test/qbg22/vdp22/200.vdp +new file mode 100644 +index 0000000..171d0a0 +--- /dev/null ++++ b/test/qbg22/vdp22/200.vdp +@@ -0,0 +1,44 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/201-lldpad.conf b/test/qbg22/vdp22/201-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/201-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/201.nlc b/test/qbg22/vdp22/201.nlc +new file mode 100755 +index 0000000..2791190 +--- /dev/null ++++ b/test/qbg22/vdp22/201.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with group id support requested and not supportted by ++# bridge and station. ++# ++ ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++# Must: Wait some time for lldpad to start up and initialize ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xxx,name=vm2_1,map=13-52:bb:cc:dd:ee:ff-222 -i veth0 -s,w=30 -a vm2_xxx,e=1 -s,w=30 ++exit $? +diff --git a/test/qbg22/vdp22/201.vdp b/test/qbg22/vdp22/201.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/201.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/202-lldpad.conf b/test/qbg22/vdp22/202-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/202-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/202.nlc b/test/qbg22/vdp22/202.nlc +new file mode 100755 +index 0000000..9cd3a90 +--- /dev/null ++++ b/test/qbg22/vdp22/202.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Assign VID by bridge and report back to caller. ++# Caller then de-assoc with wrong vid. ++# ++ ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++# Must: Wait some time for lldpad to start up and initialize ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xxx,name=vm2_205,map=0/205 -i veth0 -s,w=30 -a vm2_xxx -s,w=30 -d vm2_xxx,e=1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/202.vdp b/test/qbg22/vdp22/202.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/202.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/203-lldpad.conf b/test/qbg22/vdp22/203-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/203-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/203.nlc b/test/qbg22/vdp22/203.nlc +new file mode 100755 +index 0000000..6afe8f8 +--- /dev/null ++++ b/test/qbg22/vdp22/203.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Assign VID by bridge and report back to caller, caller de-assoc with correct ++# filter. ++# ++ ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++# Must: Wait some time for lldpad to start up and initialize ++../../../vdptest -n -v -v -v -F vm2.cfg -Cnew=vm2_xxx,name=vm2_205,map=0/205 -i veth0 -s,w=30 -a vm2_xxx -s,w=30 -Cnew=vm2_yyy,name=vm2_205,map=205 -d vm2_yyy -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/203.vdp b/test/qbg22/vdp22/203.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/203.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/204-lldpad.conf b/test/qbg22/vdp22/204-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/204-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/204.nlc b/test/qbg22/vdp22/204.nlc +new file mode 100755 +index 0000000..2e515ba +--- /dev/null ++++ b/test/qbg22/vdp22/204.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Assign QoS by bridge and report back to caller, caller de-assoc with incorrect ++# QoS. ++# ++ ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++# Must: Wait some time for lldpad to start up and initialize ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=2/61442 -i veth0 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_206,map=2 -d vm2_xx2,e=1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/204.vdp b/test/qbg22/vdp22/204.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/204.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/205-lldpad.conf b/test/qbg22/vdp22/205-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/205-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/205.nlc b/test/qbg22/vdp22/205.nlc +new file mode 100755 +index 0000000..084ef12 +--- /dev/null ++++ b/test/qbg22/vdp22/205.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Assign QoS by bridge and report back to caller, caller de-assoc with correct ++# QoS. ++# ++ ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++# Must: Wait some time for lldpad to start up and initialize ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=2/61442 -i veth0 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_206,map=61442 -d vm2_xx2 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/205.vdp b/test/qbg22/vdp22/205.vdp +new file mode 100644 +index 0000000..171d0a0 +--- /dev/null ++++ b/test/qbg22/vdp22/205.vdp +@@ -0,0 +1,44 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/206-lldpad.conf b/test/qbg22/vdp22/206-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/206-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/206.nlc b/test/qbg22/vdp22/206.nlc +new file mode 100755 +index 0000000..0704a25 +--- /dev/null ++++ b/test/qbg22/vdp22/206.nlc +@@ -0,0 +1,35 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Provoke invalid Filter data response from bridge ++# ++ ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=2/61440,typeidver=0x15 -i veth0 -s,w=30 -a vm2_xx1,e=5 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/206.vdp b/test/qbg22/vdp22/206.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/206.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/207-lldpad.conf b/test/qbg22/vdp22/207-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/207-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/207.nlc b/test/qbg22/vdp22/207.nlc +new file mode 100755 +index 0000000..99a6800 +--- /dev/null ++++ b/test/qbg22/vdp22/207.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Assign QoS by bridge and report back to caller, caller does not expected ++# changed QoS. ++# ++ ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=2,e=250 -i veth0 -s,w=30 -a vm2_xx1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/207.vdp b/test/qbg22/vdp22/207.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/207.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/208-lldpad.conf b/test/qbg22/vdp22/208-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/208-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/208.nlc b/test/qbg22/vdp22/208.nlc +new file mode 100755 +index 0000000..e7d953f +--- /dev/null ++++ b/test/qbg22/vdp22/208.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Send VLAN/QoS to bridge and report back to caller. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_1,map=0x8002 -i veth0 -s,w=30 -a vm2_xx1 -s,w=30 -d vm2_xx1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/208.vdp b/test/qbg22/vdp22/208.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/208.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/209-lldpad.conf b/test/qbg22/vdp22/209-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/209-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/209.nlc b/test/qbg22/vdp22/209.nlc +new file mode 100755 +index 0000000..41ddb21 +--- /dev/null ++++ b/test/qbg22/vdp22/209.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Send VLAN/QoS to bridge and report back to caller. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=0x8002 -i veth0 -s,w=30 -a vm2_xx1,e=5 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/209.vdp b/test/qbg22/vdp22/209.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/209.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/210-lldpad.conf b/test/qbg22/vdp22/210-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/210-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/210.nlc b/test/qbg22/vdp22/210.nlc +new file mode 100755 +index 0000000..7b6a457 +--- /dev/null ++++ b/test/qbg22/vdp22/210.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Send many VIDs (one VID is zero) and expect error as VID 0 must be the only ++# VID in the list. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xxx,name=vm2_205a -i veth0 -s,w=30 -a vm2_xxx,e=1 -s,w=30 -d vm2_xxx,e=1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/210.vdp b/test/qbg22/vdp22/210.vdp +new file mode 100644 +index 0000000..171d0a0 +--- /dev/null ++++ b/test/qbg22/vdp22/210.vdp +@@ -0,0 +1,44 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/211-lldpad.conf b/test/qbg22/vdp22/211-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/211-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/211.nlc b/test/qbg22/vdp22/211.nlc +new file mode 100755 +index 0000000..ac978bf +--- /dev/null ++++ b/test/qbg22/vdp22/211.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Send many VIDs and expect QoS for VID indexed 3 changed ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_206b -s,w=30 -Cnew=vm2_xxx,name=vm2_206b,map=10,map=11,map=12,map=0xd00d,map=14,map=15 -d vm2_xxx -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/211.vdp b/test/qbg22/vdp22/211.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/211.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/212-lldpad.conf b/test/qbg22/vdp22/212-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/212-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/212.nlc b/test/qbg22/vdp22/212.nlc +new file mode 100755 +index 0000000..91d856c +--- /dev/null ++++ b/test/qbg22/vdp22/212.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Send many VIDs (filter format VID/MAC) and expect VID 0 replaced. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_208 -s,w=30 -Cnew=vm2_xxx,name=vm2_208,map=10-aa:bb:00:00:00:10,map=20-aa:bb:00:00:00:11,map=0xb0d0-aa:bb:00:00:00:22 -d vm2_xxx,e=1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/212.vdp b/test/qbg22/vdp22/212.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/212.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/213-lldpad.conf b/test/qbg22/vdp22/213-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/213-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/213.nlc b/test/qbg22/vdp22/213.nlc +new file mode 100755 +index 0000000..cd011d5 +--- /dev/null ++++ b/test/qbg22/vdp22/213.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Send many VIDs (filter format VID/MAC) and expect VID 0 replaced. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_208 -s,w=30 -Cnew=vm2_xxx,name=vm2_208,map=10-aa:bb:00:00:00:10,map=0xb0d0-aa:bb:00:00:00:11,map=0xb0d0-aa:bb:00:00:00:22 -d vm2_xxx -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/213.vdp b/test/qbg22/vdp22/213.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/213.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/220-lldpad.conf b/test/qbg22/vdp22/220-lldpad.conf +new file mode 100644 +index 0000000..c75f7f2 +--- /dev/null ++++ b/test/qbg22/vdp22/220-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/220.nlc b/test/qbg22/vdp22/220.nlc +new file mode 100755 +index 0000000..a7a83fe +--- /dev/null ++++ b/test/qbg22/vdp22/220.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with group id support on bridge and station. ++# Send 1 VIDs (filter format VID/MAC/GPID) and expect no VID replacement. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_1,map=13-52:bb:cc:dd:ee:ff-1024 -s,w=30 -a vm2_xx1 -s,w=30 -d vm2_xx1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/220.vdp b/test/qbg22/vdp22/220.vdp +new file mode 100644 +index 0000000..0f29fa0 +--- /dev/null ++++ b/test/qbg22/vdp22/220.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/221-lldpad.conf b/test/qbg22/vdp22/221-lldpad.conf +new file mode 100644 +index 0000000..c75f7f2 +--- /dev/null ++++ b/test/qbg22/vdp22/221-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/221.nlc b/test/qbg22/vdp22/221.nlc +new file mode 100755 +index 0000000..1b85957 +--- /dev/null ++++ b/test/qbg22/vdp22/221.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with group id support on bridge and station. ++# Send 1 VIDs (filter format VID/MAC/GPID) and expect VID replaced. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_207,map=0/1014-aa:bb:cc:00:00:ff-1014 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_207,map=1014-aa:bb:cc:00:00:ff-1014 -d vm2_xx2 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/221.vdp b/test/qbg22/vdp22/221.vdp +new file mode 100644 +index 0000000..0f29fa0 +--- /dev/null ++++ b/test/qbg22/vdp22/221.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/222-lldpad.conf b/test/qbg22/vdp22/222-lldpad.conf +new file mode 100644 +index 0000000..c75f7f2 +--- /dev/null ++++ b/test/qbg22/vdp22/222-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/222.nlc b/test/qbg22/vdp22/222.nlc +new file mode 100755 +index 0000000..cc1fbd9 +--- /dev/null ++++ b/test/qbg22/vdp22/222.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with group id support on bridge and station. ++# Send many VIDs (filter format VID/MAC/GPID) and expect no VID replacement. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_1,map=13-52:bb:cc:dd:ee:ff-1024,map=14-52:bb:cc:dd:ee:10-1025,map=15-52:bb:cc:dd:ee:00-1025 -s,w=30 -a vm2_xx1 -s,w=30 -d vm2_xx1 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/222.vdp b/test/qbg22/vdp22/222.vdp +new file mode 100644 +index 0000000..0f29fa0 +--- /dev/null ++++ b/test/qbg22/vdp22/222.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/223-lldpad.conf b/test/qbg22/vdp22/223-lldpad.conf +new file mode 100644 +index 0000000..c75f7f2 +--- /dev/null ++++ b/test/qbg22/vdp22/223-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/223.nlc b/test/qbg22/vdp22/223.nlc +new file mode 100755 +index 0000000..587b08a +--- /dev/null ++++ b/test/qbg22/vdp22/223.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with group id support on bridge and station. ++# Send many VIDs (filter format VID/MAC//GPID) and expect VID 0 replaced. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_208,typeidver=0,map=0/1014-aa:bb:cc:00:00:ff-1014,map=0/1024-aa:bb:cc:00:00:dd-1024,map=1024-aa:bb:cc:00:00:aa-1024 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_208,typeidver=0,map=1014-aa:bb:cc:00:00:ff-1014,map=1024-aa:bb:cc:00:00:dd-1024,map=1024-aa:bb:cc:00:00:aa-1024 -d vm2_xx2 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/223.vdp b/test/qbg22/vdp22/223.vdp +new file mode 100644 +index 0000000..0f29fa0 +--- /dev/null ++++ b/test/qbg22/vdp22/223.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/224-lldpad.conf b/test/qbg22/vdp22/224-lldpad.conf +new file mode 100644 +index 0000000..c75f7f2 +--- /dev/null ++++ b/test/qbg22/vdp22/224-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/224.nlc b/test/qbg22/vdp22/224.nlc +new file mode 100755 +index 0000000..864cb76 +--- /dev/null ++++ b/test/qbg22/vdp22/224.nlc +@@ -0,0 +1,36 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with group id support on bridge and station. ++# Send many VIDs (filter format VID/MAC/GPID) and expect QoS (fid 1) set. ++# ++ ++sleep 30 # Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_206,typeidver=0x11,map=1014-aa:bb:cc:00:00:ff-1014,map=1024/0x9400-aa:bb:cc:00:00:dd-1024,map=1024-aa:bb:cc:00:00:aa-1024 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_206,typeidver=0x11,map=1014-aa:bb:cc:00:00:ff-1014,map=0x9400-aa:bb:cc:00:00:dd-1024,map=1024-aa:bb:cc:00:00:aa-1024 -d vm2_xx2 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/224.vdp b/test/qbg22/vdp22/224.vdp +new file mode 100644 +index 0000000..0f29fa0 +--- /dev/null ++++ b/test/qbg22/vdp22/224.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/225-lldpad.conf b/test/qbg22/vdp22/225-lldpad.conf +new file mode 100644 +index 0000000..c75f7f2 +--- /dev/null ++++ b/test/qbg22/vdp22/225-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/225.nlc b/test/qbg22/vdp22/225.nlc +new file mode 100755 +index 0000000..ffc209e +--- /dev/null ++++ b/test/qbg22/vdp22/225.nlc +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc with group id support on bridge and station. ++# Send many VIDs (filter format VID/MAC/GPID) and expect VID 0 replaced and ++# QoS set. ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_208,map=0/0xb3f6-aa:bb:cc:00:00:ff-0x3f6,map=0/0xb400-aa:bb:cc:00:00:dd-0x400 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_208,map=0xb3f6-aa:bb:cc:00:00:ff-0x3f6,map=0xb400-aa:bb:cc:00:00:dd-0x400 -d vm2_xx2 -s,w=10 ++exit $? +diff --git a/test/qbg22/vdp22/225.vdp b/test/qbg22/vdp22/225.vdp +new file mode 100644 +index 0000000..0f29fa0 +--- /dev/null ++++ b/test/qbg22/vdp22/225.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_groupid.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/240-lldpad.conf b/test/qbg22/vdp22/240-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/240-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/240.nlc b/test/qbg22/vdp22/240.nlc +new file mode 100755 +index 0000000..2a0de5a +--- /dev/null ++++ b/test/qbg22/vdp22/240.nlc +@@ -0,0 +1,43 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Check for hint bit support ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++testcase=$(basename $outfile .nlc) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_1 -s,w=30 -d vm2_1 -s,w=10 ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ exit $rc ++fi ++fgrep -q '06 21 10 00 00 01 00 05 a1 41 28 57' /tmp/$testcase-lldpad.conf.out ++exit $? +diff --git a/test/qbg22/vdp22/240.vdp b/test/qbg22/vdp22/240.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/240.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/241-lldpad.conf b/test/qbg22/vdp22/241-lldpad.conf +new file mode 100644 +index 0000000..d22aa2b +--- /dev/null ++++ b/test/qbg22/vdp22/241-lldpad.conf +@@ -0,0 +1,46 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station rule configuration file ++# ++ ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth0 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "stevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/241.nlc b/test/qbg22/vdp22/241.nlc +new file mode 100755 +index 0000000..b508e8a +--- /dev/null ++++ b/test/qbg22/vdp22/241.nlc +@@ -0,0 +1,43 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014 ++# ++# Execute a simple assoc without group id support in bridge and station. ++# Check for hint bit support ++# ++ ++# Must: Wait some time for lldpad to start up and initialize ++outfile=$(basename $0) ++dirfile=$(dirname $0) ++testcase=$(basename $outfile .nlc) ++cd $dirfile ++ ++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_1,hints=from -s,w=30 -a vm2_xx1 -s,w=30 -d vm2_xx1 -s,w=10 ++rc=$? ++if [ "$rc" -ne 0 ] ++then ++ exit $rc ++fi ++fgrep -q '06 21 20 00 00 01 00 05 a1 41 28 57' /tmp/$testcase-lldpad.conf.out ++exit $? +diff --git a/test/qbg22/vdp22/241.vdp b/test/qbg22/vdp22/241.vdp +new file mode 100644 +index 0000000..fa3efbd +--- /dev/null ++++ b/test/qbg22/vdp22/241.vdp +@@ -0,0 +1,43 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2014 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013 ++# lldpad bridge mode configuration file ++dcbx : ++{ ++ version = "1.0"; ++ dcbx_version = 2; ++}; ++nearest_customer_bridge : ++{ ++ veth2 : ++ { ++ tlvid00000001 : ++ { ++ info = "04C68829509676"; ++ }; ++ tlvid00000002 : ++ { ++ info = "03C68829509676"; ++ }; ++ adminStatus = 3; ++ @include "brevb_default.res" ++ }; ++}; +diff --git a/test/qbg22/vdp22/README b/test/qbg22/vdp22/README +new file mode 100644 +index 0000000..f58df8a +--- /dev/null ++++ b/test/qbg22/vdp22/README +@@ -0,0 +1,148 @@ ++ ++(c) Copyright IBM Corp. 2012, 2013 ++ ++Thomas Richter, IBM Research and Development, Germany, Mar 2013 ++ ++Test cases for IEEE802.1Qbg ratified standard VDP module. ++ ++14-Jun-2013 ++=========== ++Some test cases run the lldpad program in station mode and in bridge mode ++This is achieved via namespaces for network and IPC. Additionally the ++lldpad in bridge mode does not create a pid run time file /var/run/lldpad.pid. ++Use the network name space bridge_ns and then create an unnamed IPC namespace ++and execute lldpad in bridge mode. ++ ++Files ++===== ++ns_unshare Executes a command and with prior set of namespaces. Used to ++ set up an unnamed IPC namespace so 2 shared memory segments can ++ coexist for both lldpads (station and bridge role). ++runvdp.sh Runs one test case. ++ Return 0 on success and none zero otherwise. Uses qbg22sim as ++ bridge simulator. Test case result is determined by the ++ qbg22sim program. ++vm.cfg Configuration file for vdptest ++vm2.cfg Configuration file for vdptest using netlink format 2 ++ ++Tests ++===== ++The following test cases are executed. Each test case has a number. ++All test cases need a lldpad.conf configuration file, a VDP test input ++file and a netlink command file to send request to lldpad: ++- The VDP test input files have the extension .vdp. The test case number ++ is the base file name. This can be a qbg22sim input file or an lldpad ++ bridge-role configuration file. ++- The lldpad configuration file has the extension -lldpad.conf ++- The netlink command file has the extension .nlc ++ ++The purpose is to trigger an VDP DU exchange between qbg22sim and llpdad. ++The exchanged data can be inspected automaticly with little inteligence ++(see qbg22sim.1) or manually. ++ ++All test case with numbers 1 to 99 use lldpad as station role and numbers ++higher then 100 use lldpad as station and bridge role. ++ ++Test cases with number 200 and higher use netlink message format 2 to ++communicate between vdptest and llpdad. ++ ++Test cases with number 300 and higher use lldptool to trigger VDP22 protocol. ++ ++A (M) indication manual checking via lldpad trace output file inspection. ++ ++Test Description ++ ++100 Run assoc test with EVB22 disabled ++101 Check if netlink message is ignored in bridge role. ++102 Run assoc test with RR disabled ++103 Run a simple assoc and de-assoc test ++104 Run two simple assoc and de-assoc test ++105 Run a simple pre-assoc and de-assoc test ++106 Run two simple pre-assoc and de-assoc test ++107 Run a simple pre-assoc-rr and de-assoc test ++108 Run assoc --> pre-assoc test ++110 Run pre-assoc --> pre-assoc-rr --> assoc --> de-assoc test ++111 Run pre-assoc --> pre-assoc -- de-assoc test ++112 Run pre-assoc-rr --> pre-assoc-rr -- de-assoc test ++113 Run assoc --> assoc -- de-assoc test ++114 Run de-assoc test ++ ++115 Run assoc test with error response from switch ++116 Run pre-assoc test with error response in first keep alive from switch ++117 Run assoc test with de-assoc response in unsolicited message from switch ++118 Run pre-assoc test with error response from switch ++119 Run pre-assoc-rr test with error response in first keep alive from ++ switch ++120 Run pre-assoc test with de-assoc response in unsolicited message from ++ switch ++121 Run assoc test with keep-error response in first keep alive from switch ++122 Run pre-assoc test with hard-error response from switch switch ++123 Run assoc test with resource wait delay timeout on bridge. ++124 Run assoc test with keep alive timeout on bridge. ++ ++200 Run assoc/de-assoc test with long manager-id ++201 Run assoc/de-assoc test with gpid and group support turned off ++202 Run assoc/de-assoc test with vlan 0 replacement (fif 1) ++ de-assoc fails due to wrong filter ++203 Run assoc/de-assoc test with vlan 0 replacement (fif 1) ++ de-assoc succeeds due to correct filter ++204 Run assoc/de-assoc test with qos 0 replacement (fif 1) ++ de-assoc fails due to incorrect filter ++205 Run assoc/de-assoc test with qos 0 replacement (fif 1) ++ de-assoc succeeds due to correct filter ++206 Run assoc/de-assoc test with qos 0 replacement (fif 1) ++ fails due to wrong filter index ++207 Run assoc/de-assoc test with qos 0 replacement (fif 1) ++ fails due to unexpected QoS returned ++208 Run assoc/de-assoc test with vlan/qos requested by caller (fif 1) ++209 Run assoc/de-assoc test with vlan/qos requested by caller but not ++ confirmed by swtich (fif 1) ++210 Run assoc/de-assoc with multiple VID and one VID set to zero (fif 1) ++ fails because only one VID entry allowed, which is 0. ++211 Run assoc/de-assoc with multiple VIDs and expect QoS changed ++ for entry 4 (fif 1) ++212 Run assoc/de-assoc with multiple MAC/VIDs and expect all VLAN ID 0 ++ changed (fif 2). De-assoc fails because of wrong filter. ++213 Run assoc/de-assoc with multiple MAC/VIDs and expect all VLAN ID 0 ++ changed (fif 2). De-assoc succeeds. ++ ++Tests with group identifer support ++220 Run assoc/de-assoc test with 1 filter entry (fif 4) ++221 Run assoc/de-assoc test with 1 vlan 0 replacement (fif 4) ++222 Run assoc/de-assoc test with several filter entries (fif 4) ++223 Run assoc/de-assoc test with several vlan 0 replacement (fif 4) ++224 Run assoc/de-assoc test with QoS replacement (fif 4) ++225 Run assoc/de-assoc test with several vlan 0 and QoS replacement (fif 4) ++ ++Test with hint bits ++240 Run assoc/de-assoc test with suspend hints ++241 Run assoc/de-assoc test with migrate hints ++ ++TODO ++Test case with multiple filter entries. Combiniation of filter data. ++Run assoc(1) and assoc(2) with deassoc(1,2) ++ ++Run ethernet interface up/down tests while VSI actives ++Add filter info data to an existing VSI ++ ++ ++Remarks: ++ ++Test Execution ++============== ++Directory structure: ++ ++The following directory structure is assumed: ++/home/richter/dcn/qbg/mywork/open-lldp --> lldpad to test on target f18b ++/home/richter/dcn/qbg/mywork/test/qbg22/evb22 --> EVB protocol test cases ++/home/richter/dcn/qbg/mywork/test/qbg22/ecp22 --> ECP protocol test cases ++/home/richter/dcn/qbg/mywork/test/qbg22/vdp22 --> VDP protocol test cases ++ ++On local machine f18a: ++Select the evttest program by adding the path relative to test directory ++1. cd /home/richter/dcn/qbg/mywork/test/qbg22/vdp22 ++2. Use a symbolic link such as ./qbg22sim --> ../../../xxx/qbg22sim. ++3. Add the environment variable LLDPAD_DIR=abc to select an different lldpad ++ executable. For example the invocation ++ LLDPAD_DIR=new vdprun.sh 1.vdp ++ selects the file /home/richter/dcn/qbg/mywork/new/lldpad for execution. +diff --git a/test/qbg22/vdp22/allvdp.sh b/test/qbg22/vdp22/allvdp.sh +new file mode 100755 +index 0000000..0012618 +--- /dev/null ++++ b/test/qbg22/vdp22/allvdp.sh +@@ -0,0 +1,66 @@ ++#!/bin/bash ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013 ++# ++# Execute the complete vdp test suite. ++# ++ ++runcommand() ++{ ++ # echo parameter $@ ++ cmd=$1 ++ file=$2 ++ ++ echo "start testcase $number" ++ $cmd $file 2>&1 ++ rc="$?" ++ if [ "$rc" -ne 0 ] ++ then ++ echo -en "\\033[1;31m" # Failures in red ++ echo "ERROR $file exit with $rc" ++ echo -en "\\033[0;39m" ++ exit 2 ++ fi ++ echo -en "\\033[1;32m" # Success in green ++ echo "OK testcase $file" ++ echo -en "\\033[0;39m" ++ return 0 ++} ++ ++# Extract type of test case from the first 3 characters of invocation file ++type=$(basename $0) ++type="${type:3:3}" ++ ++if ! which run$type.sh 2>/dev/null ++then ++ export PATH=$PATH:. ++fi ++ ++echo "Start testsuite at $(date)" ++for i in $(ls [1-9]*.$type|sort -n) ++do ++ runcommand run$type.sh $i ++done ++echo "Stop testsuite at $(date)" ++exit 0 +diff --git a/test/qbg22/vdp22/brevb_default.res b/test/qbg22/vdp22/brevb_default.res +new file mode 100644 +index 0000000..c626be1 +--- /dev/null ++++ b/test/qbg22/vdp22/brevb_default.res +@@ -0,0 +1,36 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD bridge mode default resource file ++# ++tlvid0080c20d : ++{ ++ enableTx = true; ++ evbmode = "bridge"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++}; +diff --git a/test/qbg22/vdp22/brevb_groupid.res b/test/qbg22/vdp22/brevb_groupid.res +new file mode 100644 +index 0000000..3651381 +--- /dev/null ++++ b/test/qbg22/vdp22/brevb_groupid.res +@@ -0,0 +1,36 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD bridge mode default resource file ++# ++tlvid0080c20d : ++{ ++ enableTx = true; ++ evbmode = "bridge"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++}; +diff --git a/test/qbg22/vdp22/ns_unshare.c b/test/qbg22/vdp22/ns_unshare.c +new file mode 100644 +index 0000000..cbc322a +--- /dev/null ++++ b/test/qbg22/vdp22/ns_unshare.c +@@ -0,0 +1,54 @@ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++ ++/* A simple error-handling function: print an error message based ++ on the value in 'errno' and terminate the calling process */ ++ ++#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ ++ } while (0) ++ ++static void ++usage(char *pname) ++{ ++ fprintf(stderr, "Usage: %s [options] program [arg...]\n", pname); ++ fprintf(stderr, "Options can be:\n"); ++ fprintf(stderr, " -i unshare IPC namespace\n"); ++ fprintf(stderr, " -m unshare mount namespace\n"); ++ fprintf(stderr, " -n unshare network namespace\n"); ++ fprintf(stderr, " -p unshare PID namespace\n"); ++ fprintf(stderr, " -u unshare UTS namespace\n"); ++ fprintf(stderr, " -U unshare user namespace\n"); ++ exit(EXIT_FAILURE); ++} ++ ++int ++main(int argc, char *argv[]) ++{ ++ int flags, opt; ++ ++ flags = 0; ++ ++ while ((opt = getopt(argc, argv, "imnpuU")) != -1) { ++ switch (opt) { ++ case 'i': flags |= CLONE_NEWIPC; break; ++ case 'm': flags |= CLONE_NEWNS; break; ++ case 'n': flags |= CLONE_NEWNET; break; ++ case 'p': flags |= CLONE_NEWPID; break; ++ case 'u': flags |= CLONE_NEWUTS; break; ++ case 'U': flags |= CLONE_NEWUSER; break; ++ default: usage(argv[0]); ++ } ++ } ++ ++ if (optind >= argc) ++ usage(argv[0]); ++ ++ if (unshare(flags) == -1) ++ errExit("unshare"); ++ ++ execvp(argv[optind], &argv[optind]); ++ errExit("execvp"); ++} +diff --git a/test/qbg22/vdp22/runvdp.sh b/test/qbg22/vdp22/runvdp.sh +new file mode 100755 +index 0000000..538c956 +--- /dev/null ++++ b/test/qbg22/vdp22/runvdp.sh +@@ -0,0 +1,186 @@ ++#!/bin/bash ++# ++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012 ++# ++# Execute a single test. Parameter is the name of the test file. ++# Run 2 lldpad instances in parallel using 2 network name spaces ++# ++ ++# Check if lldpad (bridge role) is up and running. Do not use the pid file. ++# Return 0 is not running and 1 if running (pid returned as string) ++function lldpad_brpid() ++{ ++ PID_lldpbr=$(ps -ef | fgrep lldpad | fgrep -- .vdp | awk '{ print $2 }') ++ if [ -z "$PID_lldpbr" ] ++ then ++ return 0 ++ fi ++ return 1 ++} ++ ++# Check if lldpad is up and running. Return pid or 0 if not running. ++function lldpad_pid() ++{ ++ PID_lldp=$(ps -ef | fgrep lldpad | fgrep -- .conf | awk '{ print $2 }') ++ if [ -z "$PID_lldp" ] ++ then ++ return 0 ++ fi ++ return 1 ++} ++ ++function lldpad_stop() ++{ ++ if [ "$1" -eq 0 ] ++ then ++ echo "$0:lldpad $2 terminated unexpectedly" ++ return 1 ++ fi ++ kill -s SIGTERM $1 ++ sleep 1 ++ ps -p $1 -o pid --no-header > /dev/null ++ if [ $? -ne 1 ] ++ then ++ kill -s SIGKILL $1 ++ fi ++ return 0 ++} ++ ++function cp_include() ++{ ++ for i in $(fgrep @include $1 | awk '{ print $2 }' | sed 's-"--gp') ++ do ++ cp $i /tmp ++ done ++} ++ ++# Use the correct lldpad configuration file and start lldpad. ++# Parameter 1: path to lldpad to use ++# Parameter 2: name of configuration file ++function lldpad_start() ++{ ++ if lldpad_pid ++ then ++ rm -f /var/lib/lldpad/lldpad.conf ./lldpad.conf ++ cp $2 /tmp/$2 ++ $1/lldpad -V7 -f /tmp/$2 >/tmp/$2.out 2>&1 & ++ sleep 1 ++ if lldpad_pid ++ then ++ echo "$0:lldpad not started or terminated unexpectedly" ++ exit 1 ++ else ++ echo "LLDPAD running pid $PID_lldp" ++ fi ++ else ++ exit 1 ++ fi ++ return 0 ++} ++ ++# Start lldpad in bridge role ++# Testfile is an lldpad configuration file with bridge settings. ++# Run lldpad without creating the /var/run/lldpad.pid file ++function lldpad_brstart() ++{ ++ if lldpad_brpid ++ then ++ cp $2 /tmp/$2 ++ cp_include $2 ++ cmd="./ns_unshare -i -- ../../../lldpad -p -V7 -f /tmp/$2" ++ ip netns exec bridge_ns $cmd > /tmp/$2.out 2>&1 & ++ sleep 1 ++ if lldpad_brpid ++ then ++ echo "$0:lldpad bridge role not started or terminated unexpectedly" ++ return 1 ++ else ++ echo "LLDPAD bridge role running pid $PID_lldpbr" ++ fi ++ else ++ return 1 ++ fi ++ return 0 ++} ++ ++if ! ip netns list | fgrep -qi bridge_ns ++then ++ echo "$0:bridge_ns network name space missing" ++ exit 1 ++fi ++ ++if ! which runvdp.sh 1>/dev/null 2>/dev/null ++then ++ export PATH=$PATH:$PWD ++fi ++ ++# Extract type of test case from last 3 characters of invocation ++type=$(basename $0) ++type=".${type:3:3}" ++ ++testfile=$1 ++no=$(basename $testfile $type) ++ ++# Find out if test case file is a lldpad configuration file to run lldpad ++# in bridge mode ++if ! egrep -qi tlvid0080c20d $testfile && egrep -qi 'evbmode[ \t]*=[ \t]*"?bridge"?' $testfile ++then ++ echo "$0:use qbg22sim as bridge simulator" ++ exit 1 ++fi ++ ++# Start lldpad using this name space ++if ! lldpad_start ../../.. $no-lldpad.conf ++then ++ echo "$0:can not start lldpad" ++ exit 1 ++fi ++ ++# Start lldpad bridge role ++if ! lldpad_brstart ../../.. $no.vdp ++then ++ echo "$0:can not start lldpad in bridge role" ++ # Stop lldpad ++ lldpad_stop $PID_lldp "station role" ++ exit 1 ++fi ++ ++# Check for shell script to run in parallel ++if [ -r "./$no.sh" -a -x "./$no.sh" ] ++then ++ ./$no.sh ../../.. & ++fi ++ ++# Start vdptest test program ++if [ -r "$no.nlc" ] ++then ++ ./$no.nlc >/tmp/$no.nlc.out 2>&1 ++ rc=$? ++fi ++ ++# Stop lldpad ++lldpad_stop $PID_lldpbr "bridge role" ++lldpad_stop $PID_lldp "station role" ++ ++exit $rc +diff --git a/test/qbg22/vdp22/stevb_default.res b/test/qbg22/vdp22/stevb_default.res +new file mode 100644 +index 0000000..2dbf8f8 +--- /dev/null ++++ b/test/qbg22/vdp22/stevb_default.res +@@ -0,0 +1,36 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station mode default resource file ++# ++tlvid0080c20d : ++{ ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = false; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++}; +diff --git a/test/qbg22/vdp22/stevb_groupid.res b/test/qbg22/vdp22/stevb_groupid.res +new file mode 100644 +index 0000000..f83e241 +--- /dev/null ++++ b/test/qbg22/vdp22/stevb_groupid.res +@@ -0,0 +1,36 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2013 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013 ++# ++# LLDPAD station mode default resource file ++# ++tlvid0080c20d : ++{ ++ enableTx = true; ++ evbmode = "station"; ++ evbrrcap = true; ++ evbrrreq = true; ++ evbgpid = true; ++ ecpretries = 3; ++ ecprte = 14; ++ vdprwd = 20; ++ vdprka = 20; ++}; +diff --git a/test/qbg22/vdp22/vm.cfg b/test/qbg22/vdp22/vm.cfg +new file mode 100644 +index 0000000..cf5c21e +--- /dev/null ++++ b/test/qbg22/vdp22/vm.cfg +@@ -0,0 +1,56 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2012 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2012 ++# ++# Configuration file for vsi data test cases ++# ++ ++name=vm1,mgrid=1,typeid=1,typeidver=1,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\ ++ map=2-52:54:00:8e:aa:11 ++name=vm3,mgrid=1,typeid=1,typeidver=1,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\ ++ map=2-52:54:00:8e:aa:1a ++name=vm2,mgrid=1,typeid=1,typeidver=1,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53dd,\ ++ map=2-52:54:00:8e:aa:22 ++name=vm1u3,mgrid=1,typeid=1,typeidver=1,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\ ++ map=2-52:54:00:8e:aa:11, \ ++ map=2-52:54:00:8e:aa:1a ++ ++# Used type ID 199 and check for bridge resource wait delay timeout ++name=vm199,mgrid=1,typeid=199,typeidver=1,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\ ++ map=3-52:54:00:8e:aa:33 ++# Used type ID 200 and check for bridge unsolicited deassoc message ++name=vm200,mgrid=1,typeid=200,typeidver=3,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\ ++ map=3-52:54:00:8e:aa:33 ++# Used type ID 201 and check if bridge return error response ++name=vm201,mgrid=1,typeid=201,typeidver=1,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\ ++ map=4-52:54:00:8e:aa:44 ++# Used type ID 202 and check if bridge return keep-error response ++name=vm202,mgrid=1,typeid=202,typeidver=3,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\ ++ map=202-52:54:00:8e:aa:44 +diff --git a/test/qbg22/vdp22/vm2.cfg b/test/qbg22/vdp22/vm2.cfg +new file mode 100644 +index 0000000..c27a08b +--- /dev/null ++++ b/test/qbg22/vdp22/vm2.cfg +@@ -0,0 +1,58 @@ ++# ++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg ++# ++# Copyright (c) International Business Machines Corp., 2012 ++# ++# Author(s): Thomas Richter ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms and conditions of the GNU General Public License, ++# version 2, as published by the Free Software Foundation. ++# ++# This program is distributed in the hope it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++# more details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., ++# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++# ++# ++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 21-Sep-2013 ++# ++# Configuration file for vsi data test cases. Use new netlink message format 2 ++# supporting features from the vdptest program: ++# - new group notation in the filter information: vlan-mac-group ++# - vlan id zero ++# - new long mgrid ++# - hint flags for VM migration support. ++ ++# Test new message format, filter info format 2 ++name=vm2_1,2mgrid=blabla,typeid=1,typeidver=0,hints=to,\ ++ uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\ ++ map=13-52:bb:cc:dd:ee:ff ++# Test VLAN 0 return. Bridge returns typeid as vlan. ++name=vm2_205,2mgrid=vlantest,typeid=205,typeidver=0,\ ++ uuid=00000000-1111-2222-3333-aabbccddeeff,\ ++ map=14 ++name=vm2_205a,2mgrid=vlantesta,typeid=205,typeidver=0,\ ++ uuid=00000000-1111-2222-3333-aabbccddeeff,\ ++ map=3,map=0/205,map=2,map=32 ++name=vm2_208,2mgrid=vlantestb,typeid=208,typeidver=0x13,\ ++ uuid=00000000-1111-2222-3333-aabbccddeeff,\ ++ map=10-aa:bb:00:00:00:10,map=0/0xb0d0-aa:bb:00:00:00:11,\ ++ map=0/0xb0d0-aa:bb:00:00:00:22 ++# Test QoS return. Bridge returns typeidver as qos (lower 3 bits). ++# Typeidver upper nibble used as index in fid array. ++name=vm2_206,2mgrid=qostest,typeid=206,typeidver=7,\ ++ uuid=00000000-1111-2222-3333-aabbccddeeff,\ ++ map=14 ++name=vm2_206b,2mgrid=qostest,typeid=206,typeidver=0x35,\ ++ uuid=00000000-1111-2222-3333-aabbccddeeff,\ ++ map=10,map=11,map=12,map=13/0xd00d,map=14,map=15 ++# Test VLAN assigned by bridge using group-id. ++# Typeidver upper nibble used as index in fid array. ++name=vm2_207,2mgrid=groupidtest,typeid=207,typeidver=0,\ ++ uuid=00000000-1111-2222-3333-aabbccddeeff,\ ++ map=2 +diff --git a/test/qbg22/veth-setup.sh b/test/qbg22/veth-setup.sh +new file mode 100755 +index 0000000..be94fa1 +--- /dev/null ++++ b/test/qbg22/veth-setup.sh +@@ -0,0 +1,45 @@ ++#!/bin/bash ++# ++# Thomas Richter, DCN Linux Technology Center, IBM Research, Germany 29-Apr-2013 ++# ++# Setup a lldpad test environment with 2 virtual ethernet device in 2 different ++# network name spaces. ++# lldpad runs in default name space and the qbg22sim runs in the newly created ++# bridge_ns name space. veth0 is in the default net name space where as ++# interface veth2 is in the bridge_ns name space ++# ++ ++# Check if the name space already exists. Also check if the interface veth0 ++# has been defined. ++if ip netns list | fgrep -qi bridge_ns ++then ++ if ip link | fgrep -qi veth0 ++ then ++ if ip netns exec bridge_ns ip link | fgrep -qi veth2 ++ then ++ exit 0 # veth0 and veth2 exists ++ else ++ echo interface veth2 missing ++ ip netns del bridge_ns ++ fi ++ else ++ ip netns del bridge_ns ++ fi ++fi ++ ++# create veth pair(veth0, veth2) ++# with this mac address on veth0 e6:f1:20:5a:b0:e6 for evb testing ++ip link add veth0 address e6:f1:20:5a:b0:e6 type veth peer name veth2 ++ip link set veth0 up ++ip addr add 50.0.0.1/24 dev veth0 ++ ++# create a new network namespace bridge_ns, bring up veth0 and assign an ip addr ++ip netns add bridge_ns ++ ++# move veth2 to bridge_ns ++ip link set veth2 netns bridge_ns ++ip netns exec bridge_ns ip link set veth2 up ++ip netns exec bridge_ns ip addr add 50.0.0.2/24 dev veth2 ++ ++# exec bash in bridge_ns ++# ip netns exec bridge_ns bash +diff --git a/test/qbg22sim.c b/test/qbg22sim.c +index eeafd7e..9ca227b 100644 +--- a/test/qbg22sim.c ++++ b/test/qbg22sim.c +@@ -59,7 +59,7 @@ + #define MYDEBUG 0 + #define DIM(x) (sizeof(x)/sizeof(x[0])) + #define ETH_P_LLDP 0x88cc +-#define ETH_P_ECP 0x8890 ++#define ETH_P_ECP 0x8940 + #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + #define MAC2STR(a) (a)[0] & 0xff, (a)[1] & 0xff, (a)[2] & 0xff, \ + (a)[3] & 0xff, (a)[4] & 0xff, (a)[5] & 0xff +@@ -70,7 +70,7 @@ + + static char *progname; + static unsigned char eth_p_lldp[2] = { 0x88, 0xcc }; +-static unsigned char eth_p_ecp[2] = { 0x88, 0x90 }; ++static unsigned char eth_p_ecp[2] = { ETH_P_ECP >> 8, ETH_P_ECP & 0xff }; + + static int verbose; + static char *tokens[1024]; /* Used to parse command line params */ +@@ -118,7 +118,7 @@ struct lldp { /* LLDP DUs */ + unsigned long runtime; /* Program run time in seconds */ + static struct lldp *lldphead; /* List of commands */ + static struct lldp *er_ecp; /* Expected replies ECP protocol */ +-static struct lldp *er_evb; /* Expected replies ECP protocol */ ++static struct lldp *er_evb; /* Expected replies EVB protocol */ + + struct ecphdr { /* ECP header received */ + unsigned char version; /* Version number */ +@@ -534,7 +534,10 @@ static int addone(void) + exit(3); + p->opr = valid_cmd(); + if (p->opr) { +- p->ether = validate("88:90", 0); ++ char ecp_str[8]; ++ ++ sprintf(ecp_str, "%02x:%02x", eth_p_ecp[0], eth_p_ecp[1]); ++ p->ether = validate(ecp_str, 0); + goto out; + } + p->dst = validate(tokens[1], 0); +diff --git a/test/vdptest.1 b/test/vdptest.1 +index 81a2e60..5f1a1b9 100644 +--- a/test/vdptest.1 ++++ b/test/vdptest.1 +@@ -1,5 +1,5 @@ + .PU +-.TH vdptest 1 "LLDPAD" "Revision: 0.1" ++.TH vdptest 1 "LLDPAD" "Revision: 0.2" + .SH NAME + vdptest \- VDP/VSI Protocol Test Program for LLDPAD + .SH SYNOPSIS +@@ -89,12 +89,16 @@ terminates. + .br + .B vdptest + should be used for testing and debug purposes only. ++It should be noted that there is no state stored in vdptest between calls, but ++will be stored in lldpad (until the process restarts). ++A profile must be created and acted upon on in the same vdptest command. + .SS Profiles + .br + Profile is a comma separated list of key '=' value + pairs describing the VSI profile data. + Profiles consists of the following keywords, +-they are all mandatory: ++they are all mandatory with the execption of ++hints: + .TP + name: + Defines the name of the entry. +@@ -105,10 +109,20 @@ starting + with a character. + .TP + mgrid: +-Defines the manager identifier for this entry. ++Defines the 1 byte manager identifier for this entry ++as defined by the IEEE 802.1 Qbg draft version 0.2. + The value should be a number in the + range of 0..255 inclusive. + .TP ++2mgrid: ++Defines the 16 byte manager identifier for this entry ++as defined by the IEEE 802.1 Qbg ratified standard. ++Either the ++.B mgrid ++or the ++.B 2mgrid ++should be used for an entry. ++.TP + typeid: + Defines the type identifier for this entry. + The value should be a number in the +@@ -130,26 +144,77 @@ The string is converted into 16 byte UUID + with 2 nibbles converted into one byte. + .TP + map: +-Defines a VLAN-MAC address pair for this entry. ++Defines a VLAN-MAC-GROUP address triple for this entry. + The value is of the following format: + .EX +-vlanid-aa:bb:cc:dd:ee:ff ++vlanid[/newvid][-[aa:bb:cc:dd:ee:ff][-grid]] + .EE + Vlandid is converted into a number ranging +-from 0..4095. +-Following the vlanid is a dash (\-) and +-an MAC address. ++from 0..65535. ++If the vlanid is followed by an option slash ('/') ++the number following the slash is the new vlan identifier ++expected from the switch. ++Following the vlanid is an optional dash (\-) and ++a MAC address. + The MAC address is a 6 byte value, each byte + delimited by a colon (':'). ++A second optional dash (\-) can be ++specified to supply a group identifier. ++If omitted the group identifier is assumed to ++be zero and is ignored. + This keyword can be listed several times to allow +-multiple MAC-VLAN pairs per entry. ++multiple MAC-VLAN-GROUP triples per entry. ++.sp 1 ++The form of this entry determines the format of the ++filter information data send to the switch. ++The input ++.EX ++map=1 ++.EE ++is converted to filter information format ++.IR VID . ++The input ++.EX ++map=1--123 ++.EE ++is converted to filter information format ++.IR GROUP/VID . ++The input ++.EX ++map=1-11:22:33:44:55:66 ++.EE ++is converted to filter information format ++.IR VID/MAC . ++The input ++.EX ++map=1-11:22:33:44:55:66-123 ++.EE ++is converted to filter information format ++.IR GROUP/VID/MAC . ++Note that filter information formats can not be mixed in ++a single entry. Multiple ++map entries have to be of the same format. ++.TP ++hints: ++This keyword is optional and if omitted defaults to ++.IR none . ++Indicates support for IEEE 802.1 Qbg ratified standard ++virtual machine migration. ++Valid keywords are ++.I none ++(no indicate no migration support), ++.I to ++(to indicate the virtual machine is migrating to this VSI) ++and ++.I from ++(to indicate the virtual machine is migrating from this VSI). + .TP + Example: + Here is an example of a profile definition: + .EX +-name=thomas2,mgrid=1,typeid=123452,typeidver=1,\(rs ++name=thomas2,mgrid=1,typeid=123452,typeidver=1,hints=none\(rs + uuid=a1412857-60f7-4ce1-e95a-2164943f53dd,\(rs +- map=2-52:54:00:8e:50:53 ++ map=2-52:54:00:8e:50:53-9999,map=0/10-52:54:00:8e:50:54-8888 + .EE + .SS Commands + Command is an option character followed +@@ -272,12 +337,12 @@ Several definitions using the same + .I name + are not allowed. + .TP +-.B "\-C\fIname,new=new-name,changes\fP" ++.B "\-C\fInew=new-name,name=old-name,changes\fP" + Copy the profile entry named +-.I name +-and assign it ++.I old-name ++and assign it to + .IR new-name. +-After the first comma, list the fields which ++After the second comma list the fields which + are to be changed using the same syntax as in + the profile definition. + If an error is encountered during keyword parsing +@@ -401,17 +466,13 @@ flag. If this option is not set then the following default values + are used: delaytime (1 second), waittime (1 second) and number of acknowledgements + reads (1). + .SH "EXAMPLES" ++Define a profile and show its definition. ++.sp 1 + .EX + vdptest -Aname=thomas2,mgrid=1,typeid=123452,typeidver=1, + uuid=a1412857-60f7-4ce1-e95a-2164943f53dd,map=2-52:54:00:8e:50:53 -S + .EE + .sp 1 +-Define a profile and show its definition. +-.sp 1 +-.EX +-vdptest -C thomas2,new=unknown,typeid=99999 +-.EE +-.sp 1 + Copies the entry named + .I thomas2 + and assigns its contents to the name +@@ -425,7 +486,7 @@ is the + field. + .sp 1 + .EX +-vdptest -i eth2 -F vdptest.cfg -a unknown,w=10,r=2,e=3 -s ++vdptest -Cnew=unknown,name=thomas2,typeid=99999 + .EE + .sp 1 + Use interface eth2 and read the VSI configuration from file +@@ -434,12 +495,13 @@ Use the VSI definition named + .I unknown + and send an ASSOCIATION command to the switch. + Wait up to 10 seconds for the status confirmation 2 +-times and expected the error code 3 from the switch. ++times and expected the error code 3 from the switch ++(NOTE that this will cause vdptest to return FAILURE under ++normal conditions). + Wait one second before termintation. + .sp 1 + .EX +-vdptest -i eth2 -F vdptest.cfg -Cthomas2,new=x1,mgrid=2 \(rs +- -athomas2,w=10,r=2,e=3 -s -a x1,w=5 ++vdptest -i eth2 -F vdptest.cfg -a unknown,w=10,r=2,e=3 -s + .EE + .sp 1 + Use interface eth2 and read the VSI configuration from file +@@ -455,12 +517,17 @@ Send an ASSOCIATION command with parameters stored in + wait one second and + send an ASSOCIATION command with parameters stored in + .IR x1 . ++.sp 1 ++.EX ++vdptest -i eth2 -F vdptest.cfg -Cnew=x1,name=thomas2,2mgrid=blabla \(rs ++ -a thomas2,w=10,r=2,e=3 -s -a x1,w=5 ++.EE + .SH FILES +-/var/run/lldpad.pid ++/var/run/lldpad.pid, /var/lib/lldpad/lldpad.conf + .SH "ENVIRONMENT" +-Linux RHEL ++Linux + .SH "SEE ALSO" +-lldpad(8), lldptool(8) ++lldpad(8), lldptool(8), libvirtd(8) + .SH DIAGNOSTICS + Exit status is zero on success and non zero on failure or mismatch. + .SH AUTHOR +diff --git a/test/vdptest.c b/test/vdptest.c +index 8447c6c..8a423fb 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 +@@ -40,7 +60,10 @@ + #include + #include + #include ++#include ++#include + ++#include + #include + #include + +@@ -48,15 +71,17 @@ + #include + #include + ++#include + #include + + #include "clif.h" + #include "clif_msgs.h" ++#include "include/qbg22.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 COPY_OP "new=" ++#define KEYLEN 16 + #define CMD_ASSOC 'a' /* Association */ + #define CMD_DEASSOC 'd' /* DE-Association */ + #define CMD_PREASSOC 'p' /* pre-Association */ +@@ -67,23 +92,710 @@ + #define CMD_EXTERN 'E' /* External command */ + #define CMD_SETDF 'X' /* Change defaults */ + ++#define BAD_FILTER 250 /* VLAN error in filter data */ ++ ++#define DIM(x) (sizeof(x)/sizeof(x[0])) ++ ++/* ++ * New version, implemented as library function and header file in lldpad-devel ++ * package. ++ * ++ * Netlink message for QBG 2.2 ratified standard ++ */ ++ ++enum { /* 802.1Qbg VDP ratified standard */ ++ IFLA_PORT_VSI_TYPE22 = IFLA_PORT_MAX, ++ IFLA_PORT_VSI_FILTER, ++ __IFLA_PORT_MAX_NEW ++}; ++ ++#undef IFLA_PORT_MAX ++#define IFLA_PORT_MAX (__IFLA_PORT_MAX_NEW - 1) ++ ++/* ++ * Filter information data. Valid fields are determined by the ++ * filter information format type member named 'vsi_filter_fmt'. The ++ * number of the entries available is stored in the member named ++ * 'vsi_filter_num', see below. ++ */ ++struct ifla_port_vsi_filter { ++ __u32 gpid; /* Group Identifier*/ ++ __u16 vlanid; /* Vlan id and QoS */ ++ __u8 mac[6]; /* MAC address */ ++}; ++ ++struct ifla_port_vsi22 { /* 802.1 Qbg Ratified standard */ ++ __u8 vsi_mgrid[PORT_UUID_MAX]; /* Manager identifier */ ++ __u8 vsi_uuid[PORT_UUID_MAX]; /* VSI identifier */ ++ __u8 vsi_uuidfmt; /* Format of UUID string */ ++ __u8 vsi_type_id[3]; /* Type identifier */ ++ __u8 vsi_type_version; /* Type version identifier */ ++ __u8 vsi_hints; /* Hint bits */ ++ __u8 vsi_filter_fmt; /* Filter information format */ ++ __u16 vsi_filter_num; /* # of filter data entries */ ++}; ++ ++/* ++ * 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; ++} ++ ++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->vsi_idfmt) { ++ 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->vsi_idfmt; ++ 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; ++} ++ + /* +- * Set the define MYDEBUG to any value for detailed debugging ++ * 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, + f_typeid, + f_typeidver, +- f_uuid ++ f_uuid, ++ f_hints, ++ 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 short vlanid; /* VLAN Id */ ++ unsigned long gpid; /* Group */ ++ unsigned short newvid; /* New vlan id returned from switch */ ++ unsigned char flags; /* Tested? */ + }; + ++#define CMDTABSZ 32 /* Table size for VSI commands */ + static struct vdpdata { + char key[KEYLEN]; /* Profile name */ + unsigned char modified; /* Field altered */ +@@ -91,9 +803,20 @@ 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 uuid[PORT_UUID_MAX]; /* Instance ID */ ++ unsigned char mgrid2[PORT_UUID_MAX]; /* Manager ID VDP22 */ + struct macvlan addr[10]; /* Pairs of MAC/VLAN */ +-} vsidata[32]; ++ unsigned char fif; /* Filter info format */ ++ unsigned char hints; /* Migrate to/from hits */ ++ unsigned char nlmsg_v; /* Version of netlink message to use */ ++} vsidata[CMDTABSZ]; ++ ++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 */ +@@ -104,8 +827,9 @@ 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 */ ++} cmds[CMDTABSZ], defaults = { /* Default values in structure */ + .waittime = 1, + .repeats = 1, + .delay = 1000 +@@ -119,24 +843,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) + { +@@ -146,167 +852,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; +- +- addit("\tIFLA_VF_MAC=%02x:%02x:%02x:" +- " %02x:%02x:%02x\n", +- m[0], m[1], m[2], m[3], m[4], m[5]); +- } +- +- if (vf[IFLA_VF_VLAN]) { +- struct ifla_vf_vlan *vlan = RTA_DATA(vf[IFLA_VF_VLAN]); ++ int i; ++ struct macvlan *mac = vdp->addr; ++ ++ 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); ++} + +- addit("\tIFLA_VF_VLAN=%d\n", vlan->vlan); ++static int test_fid(struct vdpnl_mac *new, struct vdpdata *vdp) ++{ ++ int i; ++ struct macvlan *mac = vdp->addr; ++ ++ 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; +- +- 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); ++ int rc = 0, i; ++ ++ 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; ++ int rc = 0; + +- 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; +- +- addit("\tfound IFLA_VF_PORTS\n"); +- nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) { +- +- 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; ++ if (verbose >= 2) { ++ char uuidbuf[64]; + +- 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; + } + + /* +@@ -314,35 +947,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", +@@ -353,88 +989,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) +-{ +- int rc = 0; +- unsigned int cnt; +- +- for (cnt = 0; cnt < cp->repeats && rc >= 0; ++cnt) +- if ((rc = waitmsg(cp, 0))) { +- cp->rc = 1; +- break; +- } +- return rc; +-} +- + /* +- * Construct the GETLINK message to lldpad. ++ * Find out which vdp this unsolicited message was sent for. + */ +-static int mk_nlas(char *buf) ++static struct vdpdata *finduuid(unsigned char *uuid) + { +- int total; +- struct nlattr *nlap; +- char *cp; +- struct ifinfomsg *to = (struct ifinfomsg *)buf; ++ unsigned int i; + +- 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; ++ for (i = 0; i < DIM(vsidata); ++i) ++ if (!memcmp(vsidata[i].uuid, uuid, sizeof(vsidata[i].uuid))) ++ return &vsidata[i]; ++ return 0; ++} ++ ++static int trigger_test(struct vdpnl_vsi *p) ++{ ++ char uuid[64]; ++ int rc = -1; ++ ++ 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 = 0; ++ 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) +@@ -445,195 +1112,219 @@ 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 vdpnl_getreply_error(unsigned char *, size_t, int *); ++int vdpnl_getreply_parse(struct vdpnl_vsi *, unsigned char *, size_t); ++ ++static int lldp_recv(struct command *cp, struct vdpnl_vsi *p) + { +- int bytes; +- int status; +- +- bytes = getlink(); +- if (bytes <= 0) +- return bytes; +- bytes = waitmsg(cp, &status); +- if (bytes <= 0) +- return bytes; +- cp->rc = status; ++ 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; ++ } ++ } ++ } ++ return 2; ++} ++ ++static int check_sendack(struct nlmsghdr *nlh, int *ack) ++{ ++ struct nlmsgerr *err = NLMSG_DATA(nlh); ++ ++ if (nlh->nlmsg_type != NLMSG_ERROR) ++ return -1; + if (verbose) +- printf("%s lldp_ack status:%d\n", progname, cp->rc); +- return bytes; +-} +- +-static int addvfs(struct nl_msg *nl_msg, struct vdpdata *vdp, unsigned char cmd) +-{ +- 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; +- } +- +- 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; +- +- 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); ++ printf("%s setlink response:%d\n", progname, err->error); ++ *ack = err->error; + return 0; + } + +-static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp) +-{ +- int i; +- struct nlattr *vfinfolist, *vfinfo; +- +- 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->addr[i].mac) { +- 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; +- } +- +- if (vdp->addr[i].vlanid) { +- struct ifla_vf_vlan ifla_vf_vlan = { +- .vf = PORT_SELF_VF, +- .vlan = vdp->addr[i].vlanid, +- .qos = 0, +- }; +- +- if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof ifla_vf_vlan, +- &ifla_vf_vlan) < 0) +- return -ENOMEM; +- } +- nla_nest_end(nl_msg, vfinfo); +- } +- nla_nest_end(nl_msg, vfinfolist); +- return 0; +-} +- +-/* +- * Build the netlink message, return total length of message +- */ +-static int buildmsg(unsigned char *buf, size_t len, 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; +-} +- + /* + * 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 lldp_send(struct command *cp, struct vdpdata *vdp) ++static int lldp_send(struct vdpnl_vsi *vsi, int waittime, int *ack) + { +- 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; ++ 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; + +- memset(&d_nladdr, 0, sizeof d_nladdr); +- d_nladdr.nl_family = AF_NETLINK; +- d_nladdr.nl_pid = lldpad; /* Target PID */ ++ 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; ++ } + +- 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; ++ iov.iov_len = nlh->nlmsg_len; /* Set msg length */ + rc = sendmsg(my_sock, &msg, 0); +- if (rc < 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; ++ 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; + } + ++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; ++ } ++ return PORT_REQUEST_PREASSOCIATE; ++} ++ ++/* ++ * Convert vdp to vsi structure. ++ */ ++static void vdp2vsi(struct vdpnl_vsi *p, unsigned char cmd, struct vdpdata *vdp) ++{ ++ 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->vsi_idfmt = VDP22_ID_UUID; ++ 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; ++} ++ ++/* ++ * 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 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); ++ } ++} ++ + /* + * Open netlink socket to talk to lldpad daemon. + */ +@@ -689,13 +1380,14 @@ static void lldpad_pid(void) + static unsigned long getnumber(char *key, char *word, char stopchar, int *ec) + { + char *endp; +- unsigned long no = strtoul(word, &endp, 0); ++ unsigned long no; + + if (word == 0 || *word == '\0') { + fprintf(stderr, "key %s has missing number\n", key); + *ec = 1; + return 0; + } ++ no = strtoul(word, &endp, 0); + #ifdef MYDEBUG + printf("%s:stopchar:%c endp:%c\n", __func__, stopchar, *endp); + #endif +@@ -759,37 +1451,78 @@ static struct vdpdata *nextfree() + + static int check_map(char *value, struct vdpdata *profile) + { +- char *delim = strchr(value, '-'); +- unsigned long vlan; +- int i, ec, x[ETH_ALEN]; ++ char *delim2 = 0, *slash, *delim = strchr(value, '-'); ++ unsigned long vlan, newvlan = 0, gpid = 0; ++ int fif, i, ec, x[ETH_ALEN]; ++ int have_mac = 1, have_gpid = 1; + +- if (!delim) { +- fprintf(stderr, "%s invalid map format %s\n", progname, value); +- return -1; ++ if (!delim) ++ have_gpid = have_mac = 0; ++ else { ++ *delim = '\0'; ++ delim2 = strchr(delim + 1, '-'); ++ if (!delim2) ++ have_gpid = 0; ++ else { ++ *delim2 = '\0'; ++ if (delim + 1 == delim2) /* -- and no mac */ ++ have_mac = 0; ++ } + } +- vlan = getnumber("map", value, '-', &ec); ++ memset(x, 0, sizeof(x)); ++ slash = strchr(value, '/'); ++ if (slash) { /* Expect replacement vid incl. changed QoS */ ++ *slash = '\0'; ++ newvlan = getnumber("map", slash + 1, '\0', &ec); ++ if (ec) { ++ fprintf(stderr, "%s invalid new vlanid %s\n", progname, ++ value); ++ return -1; ++ } ++ if (newvlan >= 0x10000) { ++ fprintf(stderr, "%s new vlanid %#lx too high\n", ++ progname, newvlan); ++ return -1; ++ } ++ profile->nlmsg_v = vdpnl_nlf2; ++ } ++ vlan = getnumber("map", value, '\0', &ec); + if (ec) { + fprintf(stderr, "%s invalid vlanid %s\n", progname, value); + return -1; + } +- if (vlan >= 4095) { ++ if (vlan >= 0x10000) { + fprintf(stderr, "%s vlanid %ld too high\n", progname, vlan); + return -1; + } +- ++delim; +- ec = sscanf(delim, "%02x:%02x:%02x:%02x:%02x:%02x", &x[0], &x[1], +- &x[2], &x[3], &x[4], &x[5]); +- if (ec != ETH_ALEN) { +- fprintf(stderr, "%s mac %s invalid\n", progname, delim); +- return -1; ++ 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]); ++ if (ec != ETH_ALEN) { ++ fprintf(stderr, "%s mac %s invalid\n", progname, delim); ++ return -1; ++ } ++ /* Check for last character */ ++ delim = strrchr(delim + 1, ':') + 2; ++ if (*delim && (strchr("0123456789abcdefABCDEF", *delim) == 0 ++ || *(delim + 1) != '\0')) { ++ fprintf(stderr, "%s last mac part %s invalid\n", ++ progname, delim); ++ return -1; ++ } ++ fif = VDP22_FFMT_MACVID; + } +- /* Check for last character */ +- delim = strrchr(value, ':') + 2; +- if (*delim && (strchr("0123456789abcdefABCDEF", *delim) == 0 +- || *(delim + 1) != '\0')) { +- fprintf(stderr, "%s last mac part %s invalid\n", progname, +- delim); +- return -1; ++ /* Check for optional group identifier */ ++ if (have_gpid && *(delim2 + 1)) { ++ gpid = getnumber("group", delim2 + 1, '\0', &ec); ++ if (ec) { ++ fprintf(stderr, "%s invalid groupid %s\n", progname, ++ delim2 + 1); ++ return -1; ++ } ++ fif += 2; ++ profile->nlmsg_v = vdpnl_nlf2; + } + #ifdef MYDEBUG + for (i = 0; i < ETH_ALEN; ++i) +@@ -797,18 +1530,34 @@ static int check_map(char *value, struct vdpdata *profile) + puts(""); + + #endif ++ if (profile->fif && profile->fif != fif) { ++ fprintf(stderr, "%s invalid filter info format %d use %d\n", ++ progname, fif, profile->fif); ++ return -1; ++ } ++ profile->fif = fif; + for (ec = 0; ec < profile->pairs; ++ec) { +- 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 (DIM(profile->addr) == i) { ++ fprintf(stderr, "%s too many filter addresses\n", ++ progname); + return -1; + } ++ 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++; + profile->addr[ec].vlanid = vlan; ++ profile->addr[ec].newvid = newvlan; ++ profile->addr[ec].gpid = gpid; + for (i = 0; i < ETH_ALEN; ++i) + profile->addr[ec].mac[i] = x[i]; + profile->modified |= 1 << f_map; +@@ -818,7 +1567,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", +@@ -828,11 +1577,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; + } +@@ -858,7 +1607,7 @@ static int check_typeid(char *value, struct vdpdata *profile) + progname, no); + } + #ifdef MYDEBUG +- printf("%s:typeid:%d ec:%d\n", __func__, profile->mgrid, ec); ++ printf("%s:typeid:%d ec:%d\n", __func__, profile->typeid, ec); + #endif + } + return ec; +@@ -880,7 +1629,8 @@ static int check_typeidversion(char *value, struct vdpdata *profile) + progname, no); + } + #ifdef MYDEBUG +- printf("%s:typeidver:%d ec:%d\n", __func__, profile->mgrid, ec); ++ printf("%s:typeidver:%d ec:%d\n", __func__, profile->typeidver, ++ ec); + #endif + } + return ec; +@@ -891,11 +1641,17 @@ static int check_mgrid(char *value, struct vdpdata *profile) + unsigned long no; + int ec; + ++ 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) { ++ if (no <= 255 && no > 0) { ++ profile->nlmsg_v = vdpnl_nlf1; + profile->mgrid = no; + profile->modified |= 1 << f_mgrid; ++ memset(profile->mgrid2, 0, sizeof(profile->mgrid2)); + } else { + ec = -1; + fprintf(stderr, "%s: invalid mgrid %ld\n", progname, +@@ -908,6 +1664,44 @@ static int check_mgrid(char *value, struct vdpdata *profile) + return ec; + } + ++static int check_2mgrid(char *value, struct vdpdata *profile) ++{ ++ if (profile->nlmsg_v == vdpnl_nlf1) { ++ fprintf(stderr, "%s: mgrid and 2mgrid specified\n", progname); ++ return -1; ++ } ++ 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 = vdpnl_nlf2; ++ return 0; ++} ++ ++static int check_hints(char *value, struct vdpdata *profile) ++{ ++ int rc = 0; ++ ++ if(!strcmp(value, "to")) { ++ profile->hints = VDP22_MIGTO; ++ profile->modified |= 1 << f_hints; ++ profile->nlmsg_v = vdpnl_nlf2; ++ } else if(!strcmp(value, "from")) { ++ profile->hints = VDP22_MIGFROM; ++ profile->modified |= 1 << f_hints; ++ profile->nlmsg_v = vdpnl_nlf2; ++ } else if(!strcmp(value, "none")) { ++ profile->hints = 0; ++ profile->modified |= 1 << f_hints; ++ profile->nlmsg_v = vdpnl_nlf2; ++ } else { ++ fprintf(stderr, "%s: invalid hints %s\n", progname, value); ++ rc = -1; ++ } ++ return rc; ++} ++ ++ + /* + * Return true if the character is valid for a key + */ +@@ -956,7 +1750,9 @@ static char *keytable[] = { + "typeidver", + "typeid", + "uuid", +- "name" ++ "name", ++ "2mgrid", ++ "hints" + }; + + static int findkeyword(char *word) +@@ -995,6 +1791,12 @@ static int checkword(char *word, char *value, struct vdpdata *profile) + case 5: + rc = check_name(value, profile); + break; ++ case 6: ++ rc = check_2mgrid(value, profile); ++ break; ++ case 7: ++ rc = check_hints(value, profile); ++ break; + } + #ifdef MYDEBUG + printf("%s word:%s value:%s rc:%d\n", __func__, word, value, rc); +@@ -1034,14 +1836,22 @@ static int has_key(struct vdpdata *found) + static void print_pairs(struct vdpdata *found) + { + int i; +- char buf[32]; + + for (i = 0; i < found->pairs; ++i) { +- unsigned char *xp = found->addr[i].mac; ++ printf("\t%hu", found->addr[i].vlanid); ++ if (found->addr[i].newvid) ++ printf("/%hu", found->addr[i].newvid); ++ if (found->fif == VDP22_FFMT_MACVID || ++ found->fif == VDP22_FFMT_GROUPMACVID) { ++ unsigned char *xp = found->addr[i].mac; + +- sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", +- xp[0], xp[1], xp[2], xp[3], xp[4], xp[5]); +- printf("\t%hd %s\n", found->addr[i].vlanid, buf); ++ printf(" %02x:%02x:%02x:%02x:%02x:%02x", ++ xp[0], xp[1], xp[2], xp[3], xp[4], xp[5]); ++ } ++ if (found->fif == VDP22_FFMT_GROUPVID || ++ found->fif == VDP22_FFMT_GROUPMACVID) ++ printf(" %ld", found->addr[i].gpid); ++ printf("\n"); + } + } + +@@ -1049,8 +1859,16 @@ static void print_profile(struct vdpdata *found) + { + char uuid[64]; + +- printf("key:%s mgrid:%d typeid:%#x typeidver:%d\n", +- found->key, found->mgrid, found->typeid, found->typeidver); ++ if (found->mgrid) ++ sprintf(uuid, "%d", found->mgrid); ++ else ++ strcpy(uuid, (char *)found->mgrid2); ++ printf("key:%s version:%d fif:%d mgrid:%s typeid:%#x typeidver:%d", ++ found->key, found->nlmsg_v, found->fif, uuid, found->typeid, ++ found->typeidver); ++ if (found->hints) ++ printf(" hints:%s", found->hints == VDP22_MIGTO ? "to" : "from"); ++ printf("\n"); + uuid2buf(found->uuid, uuid); + printf("\tuuid:%s\n", uuid); + if (found->pairs) +@@ -1063,17 +1881,23 @@ static int change_profile(struct vdpdata *change, struct vdpdata *alter) + printf("%s alter->modified:%#x\n", __func__, alter->modified); + #endif + if ((alter->modified & (1 << f_map))) { ++ change->fif = alter->fif; + change->pairs = alter->pairs; + memcpy(change->addr, alter->addr, sizeof alter->addr); + } +- if ((alter->modified & (1 << f_mgrid))) ++ if ((alter->modified & (1 << f_mgrid))) { + change->mgrid = alter->mgrid; ++ memcpy(change->mgrid2, alter->mgrid2, sizeof(change->mgrid2)); ++ } + if ((alter->modified & (1 << f_typeid))) + change->typeid = alter->typeid; + if ((alter->modified & (1 << f_typeidver))) + change->typeidver = alter->typeidver; + if ((alter->modified & (1 << f_uuid))) + memcpy(change->uuid, alter->uuid, sizeof change->uuid); ++ if ((alter->modified & (1 << f_hints))) ++ change->hints = alter->hints; ++ change->nlmsg_v = alter->nlmsg_v; + return 0; + } + +@@ -1094,7 +1918,7 @@ static void show_profiles(char *thisone) + + /* + * Parse the profile string of the form +- * key=###,mgrid=###,typeid=###,typeidver=###,uuid=###,mac=xxx,vlan=xxx{1,10} ++ * key=###,mgrid=###|2mgrid=xxx,typeid=###,typeidver=###,uuid=xxx,map=xxx{1,10} + */ + static int parse_profile(char *profile, struct vdpdata *target) + { +@@ -1158,20 +1982,34 @@ static void find_field(unsigned char mode, char *buf) + strcat(buf, ","); + strcat(buf, "uuid"); + } ++ if ((mode & (1 << f_hints)) == 0) { ++ if (comma) ++ strcat(buf, ","); ++ strcat(buf, "hints"); ++ } + } + +-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 | +- 1 << f_typeid | 1 << f_typeidver | 1 << f_uuid; ++ 1 << f_typeid | 1 << f_typeidver | 1 << f_uuid; ++ unsigned char optmode = 1 << f_hints; + +- if (vdp->modified != mode) { ++ if ((vdp->modified & ~optmode) != mode) { + find_field(vdp->modified, buf); + 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) +@@ -1199,16 +2037,22 @@ static int make_profiles(char *profile, char *newkey) + progname, nextone.key); + return -1; + } ++ if (!strcmp(newkey, found->key) || findkey(newkey)) { ++ fprintf(stderr, "%s target key %s already exits\n", ++ progname, newkey); ++ return -1; ++ } + if (!(vdp = nextfree())) { + fprintf(stderr, "%s too many profiles\n", progname); + return -1; + } + *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) +@@ -1233,7 +2077,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); +@@ -1500,6 +2344,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) +@@ -1542,40 +2391,282 @@ static void cmd_sleep(struct command *cmdp) + cmdp->rc |= sleep(cmdp->waittime); + } + +-static int rc_ok(struct command *cmdp) ++/* ++ * Code to use the command line interface via clif_xxx functions. ++ */ ++static int tool_use; ++static struct clif *tool_conn; ++ ++static void tool_open() ++{ ++ tool_conn = clif_open(); ++ if (!tool_conn) { ++ fprintf(stderr, "%s can not open connection to LLDPAD\n", ++ progname); ++ exit(5); ++ } ++ if (clif_attach(tool_conn, "80c4")) { ++ fprintf(stderr, "%s can not attach to LLDPAD\n", ++ progname); ++ clif_close(tool_conn); ++ tool_conn = NULL; ++ exit(5); ++ } ++} ++ ++static void tool_close(void) ++{ ++ if (tool_conn) { ++ clif_detach(tool_conn); ++ clif_close(tool_conn); ++ tool_conn = NULL; ++ } ++} ++ ++/* ++ * Convert VSI command mode to string. ++ */ ++static unsigned int request2tlvid(unsigned char cmd) ++{ ++ switch (cmd) { ++ case CMD_ASSOC: ++ return VDP22_ASSOC; ++ case CMD_DEASSOC: ++ return VDP22_DEASSOC; ++ case CMD_PREASSOC: ++ return VDP22_PREASSOC; ++ case CMD_RRPREASSOC: ++ return VDP22_PREASSOC_WITH_RR; ++ } ++ return 0; ++} ++ ++static const char *request2str(unsigned char cmd) ++{ ++ switch (cmd) { ++ case CMD_ASSOC: ++ return "assoc"; ++ case CMD_DEASSOC: ++ return "deassoc"; ++ case CMD_PREASSOC: ++ return "preassoc"; ++ case CMD_RRPREASSOC: ++ return "preassoc-rr"; ++ } ++ return "unknown"; ++} ++ ++/* ++ * Convert hint bits to string. ++ */ ++static const char *hints2str(unsigned char hint) ++{ ++ switch (hint) { ++ case VDP22_MIGTO: ++ return "to"; ++ case VDP22_MIGFROM: ++ return "from"; ++ default: ++ return "none"; ++ } ++} ++ ++/* ++ * Create a command string understood by vdp22 module to forward it to ++ * the vdp22 module. ++ */ ++static size_t vdp2str(char *cmd, size_t cmd_len, char oper, struct vdpdata *vdp) + { + int i; ++ size_t len; ++ char uuidbuf[64], mgrid[64]; + +- for (i = 0; i < cmdp->no_err; ++i) +- if (cmdp->rc == cmdp->errors[i]) +- return 1; ++ uuid2buf(vdp->uuid, uuidbuf); ++ if (vdp->nlmsg_v == vdpnl_nlf1) ++ sprintf(mgrid, "%d", vdp->mgrid); ++ else ++ strcpy(mgrid, (char *)vdp->mgrid2); ++ snprintf(cmd, cmd_len, "%s,%s,%d,%d,%s,%s", ++ request2str(oper), mgrid, vdp->typeid, ++ vdp->typeidver, uuidbuf, hints2str(vdp->hints)); ++ ++ /* Add Filter information data */ ++ for (i = 0; i < vdp->pairs; ++i) { ++ len = strlen(cmd); ++ snprintf(cmd + len, cmd_len - len, ",%d", ++ vdp->addr[i].vlanid); ++ if (vdp->fif == VDP22_FFMT_MACVID || ++ vdp->fif == VDP22_FFMT_GROUPMACVID) { ++ len = strlen(cmd); ++ snprintf(cmd + len, cmd_len - len, ++ "-%02x:%02x:%02x:%02x:%02x:%02x", ++ vdp->addr[i].mac[0], vdp->addr[i].mac[1], ++ vdp->addr[i].mac[2], vdp->addr[i].mac[3], ++ vdp->addr[i].mac[4], vdp->addr[i].mac[5]); ++ } ++ if (vdp->fif == VDP22_FFMT_GROUPVID || ++ vdp->fif == VDP22_FFMT_GROUPMACVID) { ++ len = strlen(cmd); ++ snprintf(cmd + len, cmd_len - len, "-%ld", ++ vdp->addr[i].gpid); ++ } ++ } ++ return strlen(cmd); ++} ++ ++/* ++ * Convert ascii string to vdp. Return command. ++ */ ++static char *str2vdp(char *ok, struct vdpdata *p, int *response) ++{ ++ int i, ec; ++ char *token, *cmd = NULL; ++ ++ for (i = 0, token = strtok(ok, ","); token; ++ ++i, token = strtok(NULL, ",")) { ++ if (i == 0) ++ cmd = token; ++ if (i == 1) { ++ char *myend; ++ unsigned long x = strtol(token, &myend, 10); ++ ++ if (*myend || x > 255) ++ strcpy((char *)p->mgrid2, token); ++ else ++ p->mgrid = x; ++ } ++ if (i == 2) { ++ p->typeid = getnumber("typeid", token, '\0', &ec); ++ if (ec) ++ return NULL; ++ } ++ if (i == 3) { ++ p->typeidver = getnumber("typeidver", token, '\0', &ec); ++ if (ec) ++ return NULL; ++ } ++ if (i == 4 && check_uuid(token, p)) ++ return NULL; ++ /* Hints field contains response */ ++ if (i == 5) { ++ char *myend; ++ unsigned long x = strtol(token, &myend, 10); ++ ++ if (*myend) ++ return NULL; ++ *response = x; ++ } ++ if (i >= 6 && check_map(token, p)) ++ return NULL; ++ } ++ p->modified = 0; ++ return cmd; ++} ++ ++/* ++ * Test data of association. ++ */ ++static int check_vsi(struct vdpdata *p, struct vdpdata *back) ++{ ++ int i; ++ ++ if (p->mgrid && p->mgrid != back->mgrid) { ++ if (verbose >= 2) ++ printf("invalid mgrid identifer %d (expected %d)\n", ++ back->mgrid, p->mgrid); ++ return -EINVAL; ++ } ++ if (p->pairs != back->pairs) { ++ if (verbose >= 2) ++ printf("invalid fid pairs %d (expected %d)\n", ++ back->pairs, p->pairs); ++ return -ENFILE; ++ } ++ for (i = 0; i < p->pairs; ++i) { ++ if (p->addr[i].newvid) { ++ if (p->addr[i].newvid != back->addr[i].vlanid) { ++ if (verbose >= 2) { ++ printf("invalid vlanid[%d]:%#hx " ++ "(expected %#hx)\n", ++ i, back->addr[i].vlanid, ++ p->addr[i].newvid); ++ return -EMFILE; ++ } ++ } ++ } else if (p->addr[i].vlanid) { ++ if (p->addr[i].vlanid != back->addr[i].vlanid) { ++ if (verbose >= 2) { ++ printf("unexpected vlanid[%d]:%#hx " ++ "(expected %#hx)\n", ++ i, back->addr[i].vlanid, ++ p->addr[i].vlanid); ++ return -ENOTTY; ++ } ++ } ++ } else { ++ printf("invalid vlanid input[%d]:%#hx " ++ "(expected %#hx)\n", ++ i, back->addr[i].vlanid, ++ p->addr[i].newvid); ++ return -ETXTBSY; ++ } ++ } + return 0; + } + ++static void tool_lldp(struct command *cmdp, struct vdpdata *vdp) ++{ ++ char cmd[MAX_CLIF_MSGBUF], ok[MAX_CLIF_MSGBUF]; ++ size_t ok_len = sizeof(ok); ++ struct vdpdata back; ++ ++ memset(&back, 0, sizeof(back)); ++ cmdp->sys_rc = cmdp->rc = 0; ++ vdp2str(cmd, sizeof(cmd), cmdp->cmd, vdp); ++ cmdp->rc = clif_vsiwait(tool_conn, ifname, request2tlvid(cmdp->cmd), ++ cmd, ok, &ok_len, cmdp->waittime); ++ if (!cmdp->rc) { ++ char *cmd = str2vdp(ok, &back, &cmdp->rc); ++ if (!cmd) ++ cmdp->rc = -EINVAL; ++ if (!strcmp(cmd, request2str(cmdp->cmd)) && !cmdp->rc) ++ cmdp->rc = check_vsi(vdp, &back); ++ } ++} ++ ++/* ++ * 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; +- } +- } ++ if (vdp->nlmsg_v == vdpnl_nlf2 || tool_use) ++ tool_lldp(cmdp, vdp); ++ else ++ cmd_lldp(cmdp, vdp); ++} ++ ++/* ++ * Wait for unsolicited messsage from lldpad vdp22 module. ++ */ ++static void tool_wait(struct command *cmdp) ++{ ++ char ok[MAX_CLIF_MSGBUF]; ++ size_t ok_len = sizeof(ok); ++ ++ cmdp->sys_rc = cmdp->rc = 0; ++ cmdp->rc = clif_vsievt(tool_conn, ok, &ok_len, cmdp->waittime); ++ if (cmdp->rc == -EAGAIN) /* No message received */ ++ cmdp->rc = 0; ++ else if (cmdp->rc == 0 && !strncmp(ok, "deassoc", strlen("deassoc"))) ++ /* Data received and dessaoc command */ ++ cmdp->rc = 1; + } + + static int runcmds() +@@ -1604,7 +2695,10 @@ static int runcmds() + cmd_echo(&cmds[i]); + break; + case CMD_GETMSG: +- lldp_wait(&cmds[i]); ++ if (tool_use) ++ tool_wait(&cmds[i]); ++ else ++ lldp_wait(&cmds[i]); + break; + } + rc = cmd_checkrc(&cmds[i]); +@@ -1614,6 +2708,29 @@ static int runcmds() + return rc; + } + ++/* ++ * Check for VSI draft 0.2 and draft 2.2 input format on one command line. ++ */ ++static void inputformats(void) ++{ ++ int f1 = 0, f2 = 0; ++ unsigned int i; ++ ++ for (i = 0; i < DIM(cmds) && i < cmdidx; ++i) { ++ if (vsidata[i].nlmsg_v == vdpnl_nlf1) ++ ++f1; ++ if (vsidata[i].nlmsg_v == vdpnl_nlf2) ++ ++f2; ++ } ++ if (f1 && f2) { ++ fprintf(stderr, "%s mixed input format of VSI draft 0.2" ++ " and draft 2.2 not supported\n", progname); ++ exit(1); ++ } ++ if (!f1) /* Draft 2,2 with clif only */ ++ tool_use = 1; ++} ++ + #include + + int main(int argc, char **argv) +@@ -1624,7 +2741,7 @@ int main(int argc, char **argv) + char *slash, mybuf[32]; + + progname = (slash = strrchr(argv[0], '/')) ? slash + 1 : argv[0]; +- while ((ch = getopt(argc, argv, ":A:C:D:F:S::a:d:e:E:g:p:r:s::i:v")) ++ while ((ch = getopt(argc, argv, ":A:C:D:F:S::a:d:e:E:g:p:r:s::i:vn")) + != EOF) + switch (ch) { + case '?': +@@ -1635,6 +2752,9 @@ int main(int argc, char **argv) + fprintf(stderr, "%s missing option argument for -%c\n", + progname, optopt); + exit(1); ++ case 'n': ++ tool_use = 1; ++ break; + case 'F': + read_profiles(optarg); + break; +@@ -1663,8 +2783,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; +@@ -1683,6 +2803,7 @@ int main(int argc, char **argv) + for (; optind < argc; ++optind) + printf("%d %s\n", optind, argv[optind]); + #endif ++ inputformats(); + if (!needif) + exit(0); + if (!ifname) { +@@ -1690,14 +2811,27 @@ int main(int argc, char **argv) + progname); + exit(2); + } +- lldpad_pid(); +- if ((my_sock = open_socket(NETLINK_ROUTE)) < 0) +- exit(4); +- if (verbose >= 2) ++ if (tool_use) ++ tool_open(); ++ else { ++ lldpad_pid(); ++ if ((my_sock = open_socket(NETLINK_ROUTE)) < 0) ++ exit(4); ++ } ++ 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 (tool_use) ++ tool_close(); ++ else ++ close(my_sock); ++ if (verbose >= 2) { ++ printf("\nSummary:\n"); + show_commands(1); ++ } + return rc; + } +diff --git a/tlv_dcbx.c b/tlv_dcbx.c +index 14eab58..bae9b51 100644 +--- a/tlv_dcbx.c ++++ b/tlv_dcbx.c +@@ -107,7 +107,7 @@ struct unpacked_tlv *bld_dcbx1_tlv(struct dcbx_tlvs *dcbx) + struct unpacked_tlv *tlv = create_tlv(); + struct packed_tlv *ptlv = NULL; + u8 oui[DCB_OUI_LEN] = INIT_DCB_OUI; +- u8 subtype = dcbx_subtype1; ++ u8 subtype = DCBX_SUBTYPE1; + u32 offset = 0; + + if (!tlv) +@@ -211,7 +211,7 @@ struct unpacked_tlv *bld_dcbx2_tlv(struct dcbx_tlvs *dcbx) + struct unpacked_tlv *tlv = create_tlv(); + struct packed_tlv *ptlv = NULL; + u8 oui[DCB_OUI_LEN] = INIT_DCB_OUI; +- u8 subtype = dcbx_subtype2; ++ u8 subtype = DCBX_SUBTYPE2; + u32 offset = 0; + + if (!tlv) +@@ -448,14 +448,14 @@ struct unpacked_tlv *bld_dcbx2_pg_tlv(struct dcbx_tlvs *dcbx, bool *success) + + for (j=0,k=0 ; k < MAX_BANDWIDTH_GROUPS; j++, k=k+2) { + tmpbyte = 0; +- if (pg_cfg.tx.up[k].strict_priority == dcb_link) ++ if (pg_cfg.tx.up[k].strict_priority == DCB_LINK) + tmpbyte = 0xf; + else + tmpbyte = pg_cfg.tx.up[k].pgid & 0xf; + + tmpbyte <<= 4; + +- if (pg_cfg.tx.up[k+1].strict_priority == dcb_link) ++ if (pg_cfg.tx.up[k+1].strict_priority == DCB_LINK) + tmpbyte |= 0xf; + else + tmpbyte |= (pg_cfg.tx.up[k+1].pgid & 0xf); +@@ -873,7 +873,7 @@ bool unpack_dcbx1_tlvs(struct port *port, struct lldp_agent *agent, + break; + case DCB_PRIORITY_GROUPS_TLV: + /* store if subtype 2 is not present */ +- if (agent->rx.dcbx_st == dcbx_subtype1) { ++ if (agent->rx.dcbx_st == DCBX_SUBTYPE1) { + if (tlvs->manifest->dcbx_pg == NULL) { + tlvs->dcbdu |= RCVD_DCBX_TLV_PG; + tlvs->manifest->dcbx_pg = dcbtlv; +@@ -888,7 +888,7 @@ bool unpack_dcbx1_tlvs(struct port *port, struct lldp_agent *agent, + break; + case DCB_PRIORITY_FLOW_CONTROL_TLV: + /* store if subtype 2 is not present */ +- if (agent->rx.dcbx_st == dcbx_subtype1) { ++ if (agent->rx.dcbx_st == DCBX_SUBTYPE1) { + if (tlvs->manifest->dcbx_pfc == NULL) { + tlvs->dcbdu |= RCVD_DCBX_TLV_PFC; + tlvs->manifest->dcbx_pfc = dcbtlv; +@@ -903,7 +903,7 @@ bool unpack_dcbx1_tlvs(struct port *port, struct lldp_agent *agent, + break; + case DCB_APPLICATION_TLV: + /* store if subtype 2 is not present */ +- if ((agent->rx.dcbx_st == dcbx_subtype1) && ++ if ((agent->rx.dcbx_st == DCBX_SUBTYPE1) && + (dcbtlv->info[DCBX_HDR_SUB_TYPE_OFFSET] + == APP_FCOE_STYPE)) { + if (tlvs->manifest->dcbx_app == NULL) { +@@ -1213,7 +1213,7 @@ bool process_dcbx_pg_tlv(struct port *port, struct lldp_agent *agent) + if (agent == NULL) + return false; + +- if (agent->rx.dcbx_st == dcbx_subtype2) { ++ if (agent->rx.dcbx_st == DCBX_SUBTYPE2) { + if (tlvs->manifest->dcbx_pg->length != DCBX2_PG_LEN) { + LLDPAD_DBG("process_dcbx2_pg_tlv: ERROR - len\n"); + return(false); +@@ -1258,7 +1258,7 @@ bool process_dcbx_pg_tlv(struct port *port, struct lldp_agent *agent) + peer_pg.protocol.Error_Flag |= DUP_DCBX_TLV_PG; + } + +- if (agent->rx.dcbx_st == dcbx_subtype2) { ++ if (agent->rx.dcbx_st == DCBX_SUBTYPE2) { + memset(used, false, sizeof(used)); + for (j=0,k=0 ; k < MAX_BANDWIDTH_GROUPS; j++, k=k+2) { + u8 tmpbyte = tlvs->manifest->dcbx_pg->info +@@ -1268,14 +1268,14 @@ bool process_dcbx_pg_tlv(struct port *port, struct lldp_agent *agent) + peer_pg.tx.up[k].pgid = (tmpbyte >> 4) & 0xf; + peer_pg.rx.up[k].pgid = (tmpbyte >> 4) & 0xf; + if (peer_pg.tx.up[k+1].pgid == LINK_STRICT_PGID) { +- peer_pg.tx.up[k+1].strict_priority = dcb_link; +- peer_pg.rx.up[k+1].strict_priority = dcb_link; ++ peer_pg.tx.up[k+1].strict_priority = DCB_LINK; ++ peer_pg.rx.up[k+1].strict_priority = DCB_LINK; + } else { + used[peer_pg.tx.up[k+1].pgid] = true; + } + if (peer_pg.tx.up[k].pgid == LINK_STRICT_PGID) { +- peer_pg.tx.up[k].strict_priority = dcb_link; +- peer_pg.rx.up[k].strict_priority = dcb_link; ++ peer_pg.tx.up[k].strict_priority = DCB_LINK; ++ peer_pg.rx.up[k].strict_priority = DCB_LINK; + } else { + used[peer_pg.tx.up[k].pgid] = true; + } +@@ -1360,7 +1360,7 @@ bool process_dcbx_pfc_tlv(struct port *port, struct lldp_agent *agent) + if (agent == NULL) + return false; + +- if (agent->rx.dcbx_st == dcbx_subtype2) { ++ if (agent->rx.dcbx_st == DCBX_SUBTYPE2) { + if (tlvs->manifest->dcbx_pfc->length != DCBX2_PFC_LEN) { + LLDPAD_DBG("process_dcbx2_pfc_tlv: ERROR - len\n"); + return(false); +@@ -1410,7 +1410,7 @@ bool process_dcbx_pfc_tlv(struct port *port, struct lldp_agent *agent) + temp = tlvs->manifest->dcbx_pfc->info[DCBX_PFC_MAP_OFFSET]; + peer_pfc.admin[i] = (pfc_type)((temp >> i) & BIT0); + } +- if (agent->rx.dcbx_st == dcbx_subtype2) { ++ if (agent->rx.dcbx_st == DCBX_SUBTYPE2) { + peer_pfc.num_tcs = tlvs->manifest->dcbx_pfc->info + [DCBX2_PFC__NUM_TC_OFFSET]; + } +@@ -1437,7 +1437,7 @@ bool process_dcbx_app_tlv(struct port *port, struct lldp_agent *agent) + return false; + + len = tlvs->manifest->dcbx_app->length; +- if (agent->rx.dcbx_st == dcbx_subtype2) { ++ if (agent->rx.dcbx_st == DCBX_SUBTYPE2) { + if (len < DCBX2_APP_LEN) { + LLDPAD_DBG("process_dcbx2_app_tlv: ERROR - len\n"); + return(false); +@@ -1481,7 +1481,7 @@ bool process_dcbx_app_tlv(struct port *port, struct lldp_agent *agent) + peer_app.protocol.Error_Flag |= DUP_DCBX_TLV_APP; + } + +- if (agent->rx.dcbx_st == dcbx_subtype2) { ++ if (agent->rx.dcbx_st == DCBX_SUBTYPE2) { + /* processs upper layer protocol IDs until we + * match Selector Field, FCoE or FIP ID and OUI */ + len -= DCBX2_APP_DATA_OFFSET; +@@ -1550,7 +1550,7 @@ bool process_dcbx_app_tlv(struct port *port, struct lldp_agent *agent) + put_peer_app(port->ifname, APP_ISCSI_STYPE, &peer_app); + if (!fip) + put_peer_app(port->ifname, APP_FIP_STYPE, &peer_app); +- } else if (agent->rx.dcbx_st == dcbx_subtype1) { ++ } else if (agent->rx.dcbx_st == DCBX_SUBTYPE1) { + sub_type = pBuf[DCBX_HDR_SUB_TYPE_OFFSET]; + len = tlvs->manifest->dcbx_app->length - + sizeof(struct dcbx_tlv_header); diff --git a/SOURCES/lldpad-0.9.46-migrate-properly-with-vepa.patch b/SOURCES/lldpad-0.9.46-migrate-properly-with-vepa.patch deleted file mode 100644 index 3c77abc..0000000 --- a/SOURCES/lldpad-0.9.46-migrate-properly-with-vepa.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/lldp_vdp.c b/lldp_vdp.c -index 57133d1..2a6e828 100644 ---- a/lldp_vdp.c -+++ b/lldp_vdp.c -@@ -1479,13 +1479,18 @@ struct vsi_profile *vdp_add_profile(struct vdp_data *vd, - } - profile = p; - } else { -- -- profile->response = VDP_RESPONSE_NO_RESPONSE; -+ /* Libvirt sends dis-assoc command and no profile active */ -+ if (profile->mode == VDP_MODE_DEASSOCIATE) { -+ profile->response = VDP_RESPONSE_SUCCESS; -+ LLDPAD_DBG("%s: dis-assoc without profile\n", __func__); -+ } else -+ profile->response = VDP_RESPONSE_NO_RESPONSE; - - LIST_INSERT_HEAD(&vd->profile_head, profile, profile); - } - -- vdp_somethingChangedLocal(profile, true); -+ if (profile->response != VDP_RESPONSE_SUCCESS) -+ vdp_somethingChangedLocal(profile, true); - - return profile; - } diff --git a/SOURCES/lldpad-0.9.46-multiple-vm-support.patch b/SOURCES/lldpad-0.9.46-multiple-vm-support.patch deleted file mode 100644 index 6b05b09..0000000 --- a/SOURCES/lldpad-0.9.46-multiple-vm-support.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/qbg/lldp_vdpnl.c b/qbg/lldp_vdpnl.c ---- a/qbg/lldp_vdpnl.c -+++ b/qbg/lldp_vdpnl.c -@@ -351,14 +351,15 @@ - return vdpnl_error(rc, nlh, len); - vdpnl_reply1(&p, nlh, len); - vf_ports = mynla_nest_start(nlh, IFLA_VF_PORTS); -- vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); - /* Iterate over all profiles */ - do { - rc = vdp_status(++i, &p); -- if (rc == 1) -+ if (rc == 1) { -+ vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); - vdpnl_reply2(&p, nlh); -- if (rc == 0) { - mynla_nest_end(nlh, vf_port); -+ } -+ if (rc == 0) { - mynla_nest_end(nlh, vf_ports); - } - } while (rc == 1); diff --git a/SOURCES/lldpad-correct-IEEE-DCBX-capabilities-check.patch b/SOURCES/lldpad-correct-IEEE-DCBX-capabilities-check.patch deleted file mode 100644 index e84c17c..0000000 --- a/SOURCES/lldpad-correct-IEEE-DCBX-capabilities-check.patch +++ /dev/null @@ -1,1607 +0,0 @@ -From 52a375cc60c2cb0da88198916322d4c957251f8d Mon Sep 17 00:00:00 2001 -From: John Fastabend -Date: Mon, 8 Jul 2013 12:15:44 -0700 -Subject: [PATCH] lldpad: correct IEEE DCBX capabilities check - -Only need to check if the agent is managed by firmware otherwise -the software lldpad agent can drive the IEEE DCBX version. - -Also if the hardware does not support the IEEE DCBNL operations -return an error operation not supported and abort initializing -the IEEE DCBX module. The theory here is if the hardware can't -support this query it likely won't support the other IEEE DCBNL -operations. - -Signed-off-by: John Fastabend ---- - include/lldp_8021qaz.h | 1 + - lldp_8021qaz.c | 2 +- - lldp_8021qaz_cmds.c | 646 +++++++++++++++++++++++++------------------------ - lldp_dcbx_cmds.c | 16 +- - lldp_evb_cmds.c | 138 +++++------ - lldp_mand_cmds.c | 24 +- - lldp_util.c | 2 +- - lldp_vdp_cmds.c | 37 +-- - lldptool_cmds.c | 6 +- - 9 files changed, 421 insertions(+), 451 deletions(-) - -diff --git a/include/lldp_8021qaz.h b/include/lldp_8021qaz.h -index 461cca2..55353b8 100644 ---- a/include/lldp_8021qaz.h -+++ b/include/lldp_8021qaz.h -@@ -238,5 +238,6 @@ inline int ieee8021qaz_clif_cmd(void *data, struct sockaddr_un *from, - socklen_t fromlen, char *ibuf, int ilen, - char *rbuf); - int ieee8021qaz_check_operstate(void); -+int get_dcbx_hw(const char *ifname, __u8 *dcbx); - - #endif /* _LLDP_8021QAZ_H */ -diff --git a/lldp_8021qaz.c b/lldp_8021qaz.c -index fb7843c..b14703a 100644 ---- a/lldp_8021qaz.c -+++ b/lldp_8021qaz.c -@@ -419,7 +419,7 @@ inline void set_prio_map(u32 *prio_map, u8 prio, int tc) - * - * Returns 0 on success, error value otherwise. - */ --static int get_dcbx_hw(const char *ifname, __u8 *dcbx) -+int get_dcbx_hw(const char *ifname, __u8 *dcbx) - { - int err = 0; - struct nlattr *attr; -diff --git a/lldp_8021qaz_cmds.c b/lldp_8021qaz_cmds.c -index 1414a78..fb6ba85 100644 ---- a/lldp_8021qaz_cmds.c -+++ b/lldp_8021qaz_cmds.c -@@ -132,7 +132,6 @@ static int - get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, - char *obuf, int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; - char buf[250] = ""; - - if (cmd->cmd != cmd_gettlv) -@@ -147,10 +146,6 @@ get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- - switch (lldpad_shm_get_dcbx(cmd->ifname)) { - case dcbx_subtype0: - snprintf(buf, sizeof(buf), "auto"); -@@ -173,11 +168,32 @@ get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, - return cmd_success; - } - -+#define MAX_DCBX_HW_RETRIES 5 -+ -+static bool is_dcbx_hw(const char *ifname) -+{ -+ __u8 dcbx = 0; -+ int err, tries = 0; -+ -+query_retry: -+ err = get_dcbx_hw(ifname, &dcbx); -+ -+ if (err == -ENOMEM && tries < MAX_DCBX_HW_RETRIES) { -+ tries++; -+ goto query_retry; -+ } -+ -+ if (err < 0 || -+ !(dcbx & DCB_CAP_DCBX_VER_IEEE) || -+ dcbx & DCB_CAP_DCBX_LLD_MANAGED) -+ return false; -+ -+ return true; -+} -+ - static int set_arg_dcbx_mode(struct cmd *cmd, UNUSED char *args, - char *arg_value, char *obuf, int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- - if (cmd->cmd != cmd_settlv) - return cmd_invalid; - -@@ -190,12 +206,12 @@ static int set_arg_dcbx_mode(struct cmd *cmd, UNUSED char *args, - return cmd_not_applicable; - } - -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; -+ - if (strcmp(arg_value, "reset")) - return cmd_invalid; - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; - - lldpad_shm_set_dcbx(cmd->ifname, dcbx_subtype0); - snprintf(obuf, obuf_len, "mode = %s\n", arg_value); -@@ -214,8 +230,8 @@ test_arg_dcbx_mode(UNUSED struct cmd *cmd, UNUSED char *args, - static int get_arg_willing(struct cmd *cmd, char *args, - UNUSED char *arg_value, char *obuf, int obuf_len) - { -- int willing = 0; -- struct ieee8021qaz_tlvs *tlvs; -+ char arg_path[256]; -+ int willing, err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -230,26 +246,20 @@ static int get_arg_willing(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- switch (cmd->tlvid) { -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- willing = tlvs->ets->cfgl->willing; -- break; -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: -- willing = tlvs->pfc->local.willing; -- break; -- } -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -+ cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &willing, -+ CONFIG_TYPE_INT); - -- if (willing) -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(args), args, -- (unsigned int) strlen(VAL_YES), VAL_YES); -+ if (err) -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - else - snprintf(obuf, obuf_len, "%02x%s%04x%s", - (unsigned int) strlen(args), args, -- (unsigned int) strlen(VAL_NO), VAL_NO); -+ willing ? (unsigned int)strlen(VAL_YES) : -+ (unsigned int)strlen(VAL_NO), -+ willing ? VAL_YES : VAL_NO); - - return cmd_success; - } -@@ -264,8 +274,6 @@ static int _set_arg_willing(struct cmd *cmd, char *args, - if (cmd->cmd != cmd_settlv) - return cmd_invalid; - -- -- - /* To remain backward compatible and make it easier - * for everyone use to {0|1} notation we still support - * this but also support english variants as well -@@ -297,20 +305,23 @@ static int _set_arg_willing(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- if (test) -+ -+ if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - return cmd_success; -+ } - - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- -- switch (cmd->tlvid) { -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- tlvs->ets->cfgl->willing = !!willing; -- break; -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: -- tlvs->pfc->local.willing = !!willing; -- break; -+ if (tlvs) { -+ switch (cmd->tlvid) { -+ case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -+ tlvs->ets->cfgl->willing = !!willing; -+ break; -+ case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: -+ tlvs->pfc->local.willing = !!willing; -+ break; -+ } - } - - snprintf(obuf, obuf_len, "willing = %s\n", -@@ -340,7 +351,9 @@ static int test_arg_willing(struct cmd *cmd, char *args, - static int get_arg_numtc(struct cmd *cmd, char *args, - UNUSED char *arg_value, char *obuf, int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -+ char arg_path[256]; -+ int max_tcs = 0; -+ int err = 0; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -356,12 +369,18 @@ static int get_arg_numtc(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; - -- snprintf(obuf, obuf_len, "%02x%s%04x%i", -- (unsigned int) strlen(args), args, 1, tlvs->ets->cfgl->max_tcs); -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -+ cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, -+ arg_path, &max_tcs, CONFIG_TYPE_INT); -+ -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%i", -+ (unsigned int) strlen(args), args, 1, max_tcs); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -377,10 +396,9 @@ static int get_arg_up2tc(struct cmd *cmd, char *args, - UNUSED char *arg_value, - char *obuf, UNUSED int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- char buf[250] = ""; -- u32 *pmap = NULL; -- int i; -+ char arg_path[256] = ""; -+ const char *buf = ""; -+ int err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -395,33 +413,18 @@ static int get_arg_up2tc(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- switch (cmd->tlvid) { -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- pmap = &tlvs->ets->cfgl->prio_map; -- break; -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: -- pmap = &tlvs->ets->recl->prio_map; -- break; -- } -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -+ cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, -+ arg_path, &buf, CONFIG_TYPE_STRING); - -- for (i = 0; i < 8; i++) { -- char cat[5]; -- -- if (i) -- snprintf(cat, sizeof(cat), ",%i:%i", i, -- get_prio_map(*pmap, i)); -- else -- snprintf(cat, sizeof(cat), "%i:%i", i, -- get_prio_map(*pmap, i)); -- strncat(buf, cat, sizeof(buf) - strlen(buf) - 1); -- } -- -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(args), args, -- (unsigned int) strlen(buf), buf); -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int) strlen(args), args, -+ (unsigned int) strlen(buf), buf); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -433,35 +436,33 @@ _set_arg_up2tc(struct cmd *cmd, char *args, const char *arg_value, - struct ieee8021qaz_tlvs *tlvs; - char arg_path[256]; - char *toked_maps, *parse; -- u32 *pmap; -- u32 save_pmap; -- u8 max; -- int i, err = cmd_success; -+ u32 *pmap = NULL; -+ u8 max = MAX_TCS; -+ int err = cmd_success; - - if (cmd->cmd != cmd_settlv) - return cmd_invalid; - -+ tlvs = ieee8021qaz_data(cmd->ifname); -+ - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- pmap = &tlvs->ets->cfgl->prio_map; -- max = tlvs->ets->cfgl->max_tcs; -+ if (tlvs) { -+ pmap = &tlvs->ets->cfgl->prio_map; -+ max = tlvs->ets->cfgl->max_tcs; -+ } - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- pmap = &tlvs->ets->recl->prio_map; -- max = MAX_TCS; -+ if (tlvs) { -+ pmap = &tlvs->ets->recl->prio_map; -+ max = MAX_TCS; -+ } - break; - case INVALID_TLVID: - return cmd_invalid; - default: - return cmd_not_applicable; - } -- save_pmap = *pmap; - - parse = strdup(arg_value); - if (!parse) -@@ -526,29 +527,25 @@ _set_arg_up2tc(struct cmd *cmd, char *args, const char *arg_value, - } - - mask = ~(0xffffffff & (0xF << (4 * (7-prio)))); -- *pmap &= mask; -- *pmap |= tc << (4 * (7-prio)); -+ if (pmap && !test) { -+ *pmap &= mask; -+ *pmap |= tc << (4 * (7-prio)); -+ } - toked_maps = strtok(NULL, ","); - } -- } else { -+ } else if (pmap && !test) { - *pmap = 0; - } - - if (test) { -- *pmap = save_pmap; -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - free(parse); - return cmd_success; - } - - /* Build output buffer */ -- strncat(obuf, "up2tc = ", obuf_len - strlen(obuf) - 1); -- for (i = 0; i < 8; i++) { -- char cat[5]; -- -- snprintf(cat, sizeof(cat), "%i:%i ", i, get_prio_map(*pmap, i)); -- strncat(obuf, cat, obuf_len - strlen(obuf) - 1); -- } -- strncat(obuf, "\n", obuf_len - strlen(obuf) - 1); -+ snprintf(obuf, obuf_len, "up2tc = %s\n", arg_value); - - /* Update configuration file with new attribute */ - snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -@@ -576,26 +573,17 @@ static int test_arg_up2tc(struct cmd *cmd, char *args, - static int get_arg_tcbw(struct cmd *cmd, char *args, - UNUSED char *arg_value, char *obuf, UNUSED int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- char buf[250] = ""; -- int i; -- u8 *bmap; -+ char arg_path[250] = ""; -+ const char *buf = ""; -+ int err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; - - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- bmap = tlvs->ets->cfgl->tc_bw; - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- bmap = tlvs->ets->recl->tc_bw; - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -603,17 +591,18 @@ static int get_arg_tcbw(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- for (i = 0; i < 8; i++) { -- char cat[6]; -- if (i) -- snprintf(cat, sizeof(cat), ",%i", bmap[i]); -- else -- snprintf(cat, sizeof(cat), "%i", bmap[i]); -- strncat(buf, cat, sizeof(buf) - strlen(buf) - 1); -- } -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -+ cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &buf, -+ CONFIG_TYPE_STRING); - -- snprintf(obuf, obuf_len, "%02x%s%04x%s", (unsigned int) strlen(args), -- args, (unsigned int) strlen(buf), buf); -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int) strlen(args), args, -+ (unsigned int) strlen(buf), buf); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -626,7 +615,7 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, - char arg_path[256]; - char *toked_bw, *parse; - int i, err = cmd_success; -- u8 *tcbw, percent[8] = {0}, total = 0; -+ u8 *tcbw = NULL, percent[8] = {0}, total = 0; - - if (cmd->cmd != cmd_settlv) - return cmd_invalid; -@@ -634,15 +623,13 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tcbw = tlvs->ets->cfgl->tc_bw; -+ if (tlvs) -+ tcbw = tlvs->ets->cfgl->tc_bw; - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tcbw = tlvs->ets->recl->tc_bw; -+ if (tlvs) -+ tcbw = tlvs->ets->recl->tc_bw; - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -668,9 +655,11 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, - err = cmd_invalid; - goto invalid; - } else if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - free(parse); - return cmd_success; -- } else { -+ } else if (tcbw) { - memcpy(tcbw, percent, sizeof(*tcbw) * MAX_TCS); - } - -@@ -708,26 +697,17 @@ static int test_arg_tcbw(struct cmd *cmd, char *args, - static int get_arg_tsa(struct cmd *cmd, char *args, UNUSED char *arg_value, - char *obuf, UNUSED int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- char buf[250] = ""; -- int i; -- u8 *tsa; -+ const char *buf = ""; -+ char arg_path[250] = ""; -+ int err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; - - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tsa = tlvs->ets->cfgl->tsa_map; - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tsa = tlvs->ets->recl->tsa_map; - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -735,40 +715,18 @@ static int get_arg_tsa(struct cmd *cmd, char *args, UNUSED char *arg_value, - return cmd_not_applicable; - } - -- for (i = 0; i < 8; i++) { -- char cnt[4]; -- int space_left; -- -- if (i) -- snprintf(cnt, sizeof(cnt), ",%i:", i); -- else -- snprintf(cnt, sizeof(cnt), "%i:", i); -- strncat(buf, cnt, sizeof(buf) - strlen(buf) - 1); -- -- space_left = sizeof(buf) - strlen(buf) - 1; -- switch (tsa[i]) { -- case IEEE8021Q_TSA_STRICT: -- strncat(buf, "strict", space_left); -- break; -- case IEEE8021Q_TSA_CBSHAPER: -- strncat(buf, "cb_shaper", space_left); -- break; -- case IEEE8021Q_TSA_ETS: -- strncat(buf, "ets", space_left); -- break; -- case IEEE8021Q_TSA_VENDOR: -- strncat(buf, "vendor", space_left); -- break; -- default: -- strncat(buf, "unknown", space_left); -- break; -- } -- } -- -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(args), args, -- (unsigned int) strlen(buf), buf); -- -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &buf, -+ CONFIG_TYPE_STRING); -+ -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int) strlen(args), args, -+ (unsigned int) strlen(buf), buf); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -781,7 +739,7 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, - char arg_path[256]; - char *toked_maps, *parse; - int i, err = cmd_success; -- u8 *tsa; -+ u8 *tsa = NULL; - - if (cmd->cmd != cmd_settlv) - return cmd_invalid; -@@ -789,15 +747,13 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tsa = tlvs->ets->cfgl->tsa_map; -+ if (tlvs) -+ tsa = tlvs->ets->cfgl->tsa_map; - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tsa = tlvs->ets->recl->tsa_map; -+ if (tlvs) -+ tsa = tlvs->ets->recl->tsa_map; - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -840,15 +796,17 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, - goto invalid; - } - -- if (!test) -+ if (!test && tsa) - tsa[tc] = type; - toked_maps = strtok(NULL, ","); - } -- } else if (!test) { -+ } else if (!test && tsa) { - memset(tsa, 0, MAX_TCS); - } - - if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - free(parse); - return cmd_success; - } -@@ -862,22 +820,24 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, - strncat(obuf, cnt, obuf_len - strlen(obuf) - 1); - - space_left = obuf_len - strlen(obuf) - 1; -- switch (tsa[i]) { -- case IEEE8021Q_TSA_STRICT: -- strncat(obuf, "strict ", space_left); -- break; -- case IEEE8021Q_TSA_CBSHAPER: -- strncat(obuf, "cb_shaper ", space_left); -- break; -- case IEEE8021Q_TSA_ETS: -- strncat(obuf, "ets ", space_left); -- break; -- case IEEE8021Q_TSA_VENDOR: -- strncat(obuf, "vendor ", space_left); -- break; -- default: -- strncat(obuf, "unknown ", space_left); -- break; -+ if (tsa) { -+ switch (tsa[i]) { -+ case IEEE8021Q_TSA_STRICT: -+ strncat(obuf, "strict ", space_left); -+ break; -+ case IEEE8021Q_TSA_CBSHAPER: -+ strncat(obuf, "cb_shaper ", space_left); -+ break; -+ case IEEE8021Q_TSA_ETS: -+ strncat(obuf, "ets ", space_left); -+ break; -+ case IEEE8021Q_TSA_VENDOR: -+ strncat(obuf, "vendor ", space_left); -+ break; -+ default: -+ strncat(obuf, "unknown ", space_left); -+ break; -+ } - } - } - strncat(obuf, "\n", obuf_len - strlen(obuf) - 1); -@@ -907,11 +867,8 @@ static int test_arg_tsa(struct cmd *cmd, char *args, char *arg_value, - static int get_arg_enabled(struct cmd *cmd, char *args, UNUSED char *arg_value, - char *obuf, UNUSED int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- char buf[20] = ""; -- int i; -- bool first; -- u8 pfc; -+ char arg_path[256]; -+ int err, pfc; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -925,33 +882,17 @@ static int get_arg_enabled(struct cmd *cmd, char *args, UNUSED char *arg_value, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- -- pfc = tlvs->pfc->local.pfc_enable; -- -- first = true; -- for (i = 0; i < 8; i++) { -- if (pfc & (1 << i)) { -- char val[3]; -- -- if (first) { -- snprintf(val, sizeof(val), "%i", i); -- first = false; -- } else { -- snprintf(val, sizeof(val), ",%i", i); -- } -- strncat(buf, val, sizeof(buf) - strlen(buf) - 1); -- } -- } -- -- if (first) -- strncpy(buf, "none", sizeof(buf)); -- -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(args), args, -- (unsigned int) strlen(buf), buf); -+ snprintf(arg_path, sizeof(arg_path), -+ "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &pfc, -+ CONFIG_TYPE_INT); -+ -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%i", -+ (unsigned int) strlen(args), args, 2, pfc); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - - return cmd_success; -@@ -979,10 +920,6 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- - parse = strdup(arg_value); - if (!parse) - return cmd_failed; -@@ -1014,6 +951,8 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, - } - - if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - free(parse); - return cmd_success; - } -@@ -1040,7 +979,10 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, - "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); - set_config_setting(cmd->ifname, cmd->type, arg_path, &mask, - CONFIG_TYPE_INT); -- tlvs->pfc->local.pfc_enable = mask; -+ -+ tlvs = ieee8021qaz_data(cmd->ifname); -+ if (tlvs) -+ tlvs->pfc->local.pfc_enable = mask; - somethingChangedLocal(cmd->ifname, cmd->type); - invalid: - free(parse); -@@ -1062,7 +1004,9 @@ static int test_arg_enabled(struct cmd *cmd, char *args, - static int get_arg_delay(struct cmd *cmd, char *args, - UNUSED char *arg_value, char *obuf, int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -+ unsigned int delay; -+ char arg_path[256]; -+ int err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -1076,13 +1020,17 @@ static int get_arg_delay(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -+ snprintf(arg_path, sizeof(arg_path), -+ "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &delay, -+ CONFIG_TYPE_INT); - -- snprintf(obuf, obuf_len, "%02x%s%04x%02x", -- (unsigned int) strlen(args), args, 2, -- tlvs->pfc->local.delay); -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%02x", -+ (unsigned int) strlen(args), args, 2, delay); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -1106,14 +1054,15 @@ static int _set_arg_delay(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- -- if (test) -+ if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - return cmd_success; -+ } - -- tlvs->pfc->local.delay = delay; -+ tlvs = ieee8021qaz_data(cmd->ifname); -+ if (tlvs) -+ tlvs->pfc->local.delay = delay; - - snprintf(obuf, obuf_len, "delay = %i\n", delay); - -@@ -1140,13 +1089,38 @@ static int test_arg_delay(struct cmd *cmd, char *args, - return _set_arg_delay(cmd, args, arg_value, obuf, obuf_len, true); - } - -+static void arg_app_strncat_hw(char *new_app, int hw) -+{ -+ switch (hw) { -+ case IEEE_APP_SET: -+ strncat(new_app, "hw (pending set)\n", -+ sizeof(new_app) - strlen(new_app) - 2); -+ break; -+ case IEEE_APP_DEL: -+ strncat(new_app, "hw (pending delete)\n", -+ sizeof(new_app) - strlen(new_app) - 2); -+ break; -+ case IEEE_APP_DONE: -+ strncat(new_app, "hw (set)\n", -+ sizeof(new_app) - strlen(new_app) - 2); -+ break; -+ default: -+ strncat(new_app, " hw (unknown)\n", -+ sizeof(new_app) - strlen(new_app) - 2); -+ break; -+ } -+} -+ - static int get_arg_app(struct cmd *cmd, char *args, UNUSED char *arg_value, - char *obuf, int obuf_len) - { - struct ieee8021qaz_tlvs *tlvs; -- int i = 0; - struct app_obj *np; - char app_buf[2048] = "(prio,sel,proto)\n"; -+ char new_app[80] = ""; -+ const char *app; -+ u8 prio, sel; -+ int proto, hw = -1, i; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -1161,55 +1135,93 @@ static int get_arg_app(struct cmd *cmd, char *args, UNUSED char *arg_value, - } - - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -+ for (i = 0; i < MAX_APP_ENTRIES; i++) { -+ char arg_path[256]; -+ char *parse, *app_tuple; -+ int err; - -- LIST_FOREACH(np, &tlvs->app_head, entry) { -- char new_app[80]; -- char state[15]; -- struct dcb_app *dcb_app = &np->app; -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s%i", -+ TLVID_PREFIX, TLVID_8021(LLDP_8021QAZ_APP), -+ ARG_APP, i); -+ errno = 0; -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, -+ &app, CONFIG_TYPE_STRING); -+ if (err) -+ continue; - -- switch (np->hw) { -- case IEEE_APP_SET: -- strcpy(state, "pending set"); -+ /* Parse cfg file input, bounds checking done on set app cmd */ -+ parse = strdup(app); -+ if (!parse) - break; -- case IEEE_APP_DEL: -- strcpy(state, "pending delete"); -+ app_tuple = strtok(parse, ","); -+ if (!app_tuple) - break; -- case IEEE_APP_DONE: -- strcpy(state, "set"); -+ prio = atoi(app_tuple); -+ app_tuple = strtok(NULL, ","); -+ if (!app_tuple) - break; -- default: -- strcpy(state, "unknown"); -+ sel = atoi(app_tuple); -+ -+ app_tuple = strtok(NULL, ","); -+ if (!app_tuple) - break; -- } - -- if (dcb_app->selector == 1) { -+ /* APP Data can be in hex or integer form */ -+ errno = 0; -+ proto = (int) strtol(app_tuple, NULL, 0); -+ if (sel == 1) { - snprintf(new_app, sizeof(new_app), -- "%i:(%i,%i,0x%04x) %s (%s)\n", i, -- dcb_app->priority, -- dcb_app->selector, -- dcb_app->protocol, -- np->peer ? "peer" : "local", -- state); -+ "%i:(%i,%i,0x%04x) local ", i, -+ prio, sel, proto); - } else { - snprintf(new_app, sizeof(new_app), -- "%i:(%i,%i,%i) %s hw (%s)\n", i, -- dcb_app->priority, -- dcb_app->selector, -- dcb_app->protocol, -- np->peer ? "peer" : "local", -- state); -+ "%i:(%i,%i,%i) local ", i, -+ prio, sel, proto); - } -+ -+ if (tlvs) { -+ LIST_FOREACH(np, &tlvs->app_head, entry) { -+ if (np->app.selector == sel && -+ np->app.protocol == proto && -+ np->app.priority == prio && -+ !np->peer) -+ hw = np->hw; -+ } -+ } -+ -+ arg_app_strncat_hw(new_app, hw); - strncat(app_buf, new_app, sizeof(app_buf) - strlen(app_buf) - 2); -- i++; -+ } -+ -+ if (tlvs) { -+ LIST_FOREACH(np, &tlvs->app_head, entry) { -+ if (!np->peer) -+ continue; -+ -+ if (np->app.selector == 1) { -+ snprintf(new_app, sizeof(new_app), -+ "%i:(%i,%i,0x%04x) peer ", i, -+ np->app.priority, -+ np->app.selector, -+ np->app.protocol); -+ } else { -+ snprintf(new_app, sizeof(new_app), -+ "%i:(%i,%i,%i) peer ", i, -+ np->app.priority, -+ np->app.selector, -+ np->app.protocol); -+ } -+ -+ arg_app_strncat_hw(new_app, np->hw); -+ strncat(app_buf, new_app, -+ sizeof(app_buf) - strlen(app_buf) - 2); -+ } - } - - snprintf(obuf, obuf_len, "%02x%s%04x%s", - (unsigned int) strlen(args), args, - (unsigned int) strlen(app_buf), app_buf); - -- - return cmd_success; - } - -@@ -1242,8 +1254,6 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, - } - - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; - - parse = strdup(arg_value); - if (!parse) -@@ -1298,8 +1308,11 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, - - free(parse); - -- if (test) -+ if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - return cmd_success; -+ } - - snprintf(new_argval, sizeof(new_argval), - "%1u,%1u,%5u", (u8) prio, (u8) sel, (u16)pid); -@@ -1341,6 +1354,9 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, - return cmd_failed; - - /* Build app noting we verified prio, sel, and pid inputs */ -+ if (!tlvs) -+ goto write_app_config; -+ - ieee8021qaz_mod_app(&tlvs->app_head, 0, (u8) prio, (u8) sel, (u16) pid, - (cmd->ops & op_delete) ? op_delete : 0); - ieee8021qaz_app_sethw(cmd->ifname, &tlvs->app_head); -@@ -1348,45 +1364,28 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, - i = 0; - LIST_FOREACH(np, &tlvs->app_head, entry) { - char new_app[80]; -- char state[15]; -- struct dcb_app *dcb_app = &np->app; - -- switch (np->hw) { -- case IEEE_APP_SET: -- strcpy(state, "pending set"); -- break; -- case IEEE_APP_DEL: -- strcpy(state, "pending delete"); -- break; -- case IEEE_APP_DONE: -- strcpy(state, "set"); -- break; -- default: -- strcpy(state, "unknown"); -- break; -- } -- -- if (dcb_app->selector == 1) { -+ if (np->app.selector == 1) { - snprintf(new_app, sizeof(new_app), -- "%i:(%i,%i,0x%04x) %s (%s)\n", i, -- dcb_app->priority, -- dcb_app->selector, -- dcb_app->protocol, -- np->peer ? "peer" : "local", -- state); -+ "%i:(%i,%i,0x%04x) %s ", i, -+ np->app.priority, -+ np->app.selector, -+ np->app.protocol, -+ np->peer ? "peer" : "local"); - } else { - snprintf(new_app, sizeof(new_app), -- "%i:(%i,%i,%i) %s (%s)\n", i, -- dcb_app->priority, -- dcb_app->selector, -- dcb_app->protocol, -- np->peer ? "peer" : "local", -- state); -+ "%i:(%i,%i,%i) %s ", i, -+ np->app.priority, -+ np->app.selector, -+ np->app.protocol, -+ np->peer ? "peer" : "local"); - } -+ arg_app_strncat_hw(new_app, np->hw); - strncat(obuf, new_app, obuf_len - strlen(obuf) - 2); - i++; - } - -+write_app_config: - somethingChangedLocal(cmd->ifname, cmd->type); - - if (cmd->ops & op_delete) -@@ -1434,7 +1433,7 @@ get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, - snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", - TLVID_PREFIX, cmd->tlvid, arg); - -- if (!is_tlv_txdisabled(cmd->ifname, cmd->type, cmd->tlvid)) -+ if (is_tlv_txenabled(cmd->ifname, cmd->type, cmd->tlvid)) - value = true; - else - value = false; -@@ -1500,8 +1499,11 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - err = get_config_setting(cmd->ifname, cmd->type, arg_path, - &curr, CONFIG_TYPE_BOOL); - -- if (test) -+ if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - return cmd_success; -+ } - - snprintf(obuf, obuf_len, "enabled = %s\n", value ? "yes" : "no"); - -diff --git a/lldp_dcbx_cmds.c b/lldp_dcbx_cmds.c -index 9f18512..6cc69b6 100644 ---- a/lldp_dcbx_cmds.c -+++ b/lldp_dcbx_cmds.c -@@ -549,8 +549,8 @@ int dcbx_clif_cmd(void *data, - pfc_attribs pfc_data; - app_attribs app_data; - llink_attribs llink_data; -- struct port *port; - struct dcbx_tlvs *dcbx; -+ int dcb_enable; - - data = (struct clif_data *) data; - -@@ -586,17 +586,13 @@ int dcbx_clif_cmd(void *data, - memcpy(port_id, ibuf+DCB_PORT_OFF, plen); - port_id[plen] = '\0'; - -- /* Confirm port is a lldpad managed port */ -- port = port_find_by_name(port_id); -- if (!port) -- return cmd_device_not_found; -- -- dcbx = dcbx_data(port->ifname); -- if (!dcbx) -- return cmd_device_not_found; -+ if (get_hw_state(port_id, &dcb_enable) < 0) -+ return cmd_not_capable; - -+ dcbx = dcbx_data(port_id); - /* OPER and PEER cmd not applicable while in IEEE-DCBX modes */ -- if (dcbx->active == 0 && (cmd == CMD_GET_PEER || cmd == CMD_GET_OPER)) -+ if ((!dcbx || dcbx->active == 0) && -+ (cmd == CMD_GET_PEER || cmd == CMD_GET_OPER)) - return cmd_not_applicable; - - switch(feature) { -diff --git a/lldp_evb_cmds.c b/lldp_evb_cmds.c -index 923d56d..86e1ef7 100644 ---- a/lldp_evb_cmds.c -+++ b/lldp_evb_cmds.c -@@ -181,17 +181,19 @@ static int - get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { -- struct evb_data *ed; -- char *s; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); -+ char *s, arg_path[EVB_BUF_SIZE]; -+ int value; - - if (good_cmd != cmd_success) - return good_cmd; - -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (ed->txmit) -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, cmd->tlvid, arg); -+ if (get_cfg(cmd->ifname, cmd->type, arg_path, &value, CONFIG_TYPE_BOOL)) -+ value = false; -+ -+ if (value) - s = VAL_YES; - else - s = VAL_NO; -@@ -221,10 +223,11 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) { -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; -+ } -+ - if (test) - return cmd_success; - -@@ -233,12 +236,14 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - - if (set_cfg(cmd->ifname, cmd->type, arg_path, &value, - CONFIG_TYPE_BOOL)){ -- LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", ed->ifname, -+ LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", cmd->ifname, - argvalue); - return cmd_failed; - } -- ed->txmit = value; -- LLDPAD_INFO("%s: changed EVB enabletx (%s)\n", ed->ifname, argvalue); -+ if (ed) -+ ed->txmit = value; -+ -+ LLDPAD_INFO("%s: changed EVB enabletx (%s)\n", cmd->ifname, argvalue); - somethingChangedLocal(cmd->ifname, cmd->type); - - return cmd_success; -@@ -259,20 +264,19 @@ static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - static int get_arg_fmode(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { -- char *s; -- struct evb_data *ed; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); -+ char *s; -+ u8 mode; - - if (good_cmd != cmd_success) - return good_cmd; - -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (ed->policy.smode & LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY) -+ mode = evb_conf_fmode(cmd->ifname, cmd->type); -+ if (mode & LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY) - s = VAL_EVB_FMODE_REFLECTIVE_RELAY; - else - s = VAL_EVB_FMODE_BRIDGE; -+ - snprintf(obuf, obuf_len, "%02x%s%04x%s", - (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); - return cmd_success; -@@ -296,25 +300,28 @@ static int _set_arg_fmode(struct cmd *cmd, const char *argvalue, bool test) - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) { -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; -+ } -+ - if (test) - return cmd_success; - - snprintf(arg_path, sizeof(arg_path), "%s%08x.fmode", - TLVID_PREFIX, cmd->tlvid); - -- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, - CONFIG_TYPE_STRING)) { - LLDPAD_ERR("%s: saving EVB forwarding mode failed\n", -- ed->ifname); -+ cmd->ifname); - return cmd_failed; - } - -- ed->policy.smode = smode; -- LLDPAD_INFO("%s: changed EVB forwarding mode (%s)\n", ed->ifname, -+ if (ed) -+ ed->policy.smode = smode; -+ -+ LLDPAD_INFO("%s: changed EVB forwarding mode (%s)\n", cmd->ifname, - argvalue); - somethingChangedLocal(cmd->ifname, cmd->type); - return cmd_success; -@@ -338,27 +345,25 @@ get_arg_capabilities(struct cmd *cmd, char *arg, UNUSED char *argvalue, - { - int comma = 0; - char t[EVB_BUF_SIZE]; -- struct evb_data *ed; -+ u8 scap; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); - - if (good_cmd != cmd_success) - return good_cmd; -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; - -+ scap = evb_conf_capa(cmd->ifname, cmd->type); - memset(t, 0, sizeof t); -- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) { -+ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) { - strcat(t, VAL_EVB_CAPA_RTE); - comma = 1; - } -- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP) { -+ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP) { - if (comma) - strcat(t, " "); - strcat(t, VAL_EVB_CAPA_ECP); - comma = 1; - } -- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP) { -+ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP) { - if (comma) - strcat(t, " "); - strcat(t, VAL_EVB_CAPA_VDP); -@@ -415,25 +420,25 @@ _set_arg_capabilities(struct cmd *cmd, const char *argvalue, bool test) - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; - if (test) - return cmd_success; - - snprintf(arg_path, sizeof(arg_path), "%s%08x.capabilities", - TLVID_PREFIX, cmd->tlvid); - -- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, - CONFIG_TYPE_STRING)) { - LLDPAD_ERR("%s: saving EVB capabilities (%#x) failed\n", -- ed->ifname, scap); -+ cmd->ifname, scap); - return cmd_failed; - } - -- ed->policy.scap = scap; -- LLDPAD_INFO("%s: changed EVB capabilities (%#x)\n", ed->ifname, scap); -+ if (ed) -+ ed->policy.scap = scap; -+ LLDPAD_INFO("%s: changed EVB capabilities (%#x)\n", cmd->ifname, scap); - somethingChangedLocal(cmd->ifname, cmd->type); - - return cmd_success; -@@ -457,17 +462,15 @@ static int get_arg_rte(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { - char s[EVB_BUF_SIZE]; -- struct evb_data *ed; -+ u8 rte; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); - - if (good_cmd != cmd_success) - return good_cmd; - -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -+ rte = evb_conf_rte(cmd->ifname, cmd->type); - -- if (sprintf(s, "%i", ed->policy.rte) <= 0) -+ if (sprintf(s, "%i", rte) <= 0) - return cmd_invalid; - - snprintf(obuf, obuf_len, "%02x%s%04x%s", -@@ -491,24 +494,24 @@ static int _set_arg_rte(struct cmd *cmd, const char *argvalue, bool test) - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; - if (test) - return cmd_success; - - snprintf(arg_path, sizeof(arg_path), "%s%08x.rte", TLVID_PREFIX, - cmd->tlvid); -- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, - CONFIG_TYPE_STRING)){ -- LLDPAD_ERR("%s: error saving EVB rte (%d)\n", ed->ifname, -+ LLDPAD_ERR("%s: error saving EVB rte (%d)\n", cmd->ifname, - value); - return cmd_failed; - } - -- ed->policy.rte = value; -- LLDPAD_INFO("%s: changed EVB rte (%#x)\n", ed->ifname, value); -+ if (ed) -+ ed->policy.rte = value; -+ LLDPAD_INFO("%s: changed EVB rte (%#x)\n", cmd->ifname, value); - somethingChangedLocal(cmd->ifname, cmd->type); - - return cmd_success; -@@ -530,16 +533,15 @@ static int get_arg_vsis(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { - char s[EVB_BUF_SIZE]; -- struct evb_data *ed; -+ u16 svsi; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); - - if (good_cmd != cmd_success) - return good_cmd; - -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (sprintf(s, "%04i", ed->policy.svsi) <= 0) -+ svsi = evb_conf_vsis(cmd->ifname, cmd->type); -+ -+ if (sprintf(s, "%04i", svsi) <= 0) - return cmd_invalid; - snprintf(obuf, obuf_len, "%02x%s%04x%s", - (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); -@@ -561,24 +563,24 @@ static int _set_arg_vsis(struct cmd *cmd, const char *argvalue, bool test) - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; - if (test) - return cmd_success; - - snprintf(arg_path, sizeof(arg_path), "%s%08x.vsis", TLVID_PREFIX, - cmd->tlvid); -- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, - CONFIG_TYPE_STRING)){ -- LLDPAD_ERR("%s: error saving EVB vsi (%d)\n", ed->ifname, -+ LLDPAD_ERR("%s: error saving EVB vsi (%d)\n", cmd->ifname, - value); - return cmd_failed; - } - -- ed->policy.svsi = htons(value); -- LLDPAD_INFO("%s: changed EVB vsis (%#x)\n", ed->ifname, value); -+ if (ed) -+ ed->policy.svsi = htons(value); -+ LLDPAD_INFO("%s: changed EVB vsis (%#x)\n", cmd->ifname, value); - somethingChangedLocal(cmd->ifname, cmd->type); - - return cmd_success; -diff --git a/lldp_mand_cmds.c b/lldp_mand_cmds.c -index aedb8dc..21ebb97 100644 ---- a/lldp_mand_cmds.c -+++ b/lldp_mand_cmds.c -@@ -78,17 +78,12 @@ static struct arg_handlers arg_handlers[] = { - static int get_mand_subtype(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { -- struct mand_data *md; - int subtype; - char *string, arg_path[256]; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; - -- md = mand_data(cmd->ifname, cmd->type); -- if (!md) -- return cmd_device_not_found; -- - switch (cmd->tlvid) { - case CHASSIS_ID_TLV: - snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -@@ -183,8 +178,6 @@ static int _set_mand_subtype(struct cmd *cmd, char *arg, char *argvalue, - return cmd_invalid; - - md = mand_data(cmd->ifname, cmd->type); -- if (!md) -- return cmd_device_not_found; - - switch (cmd->tlvid) { - case CHASSIS_ID_TLV: -@@ -261,9 +254,11 @@ static int _set_mand_subtype(struct cmd *cmd, char *arg, char *argvalue, - if (test) - return cmd_success; - -- md->read_shm = 1; -- md->rebuild_chassis = 1; -- md->rebuild_portid = 1; -+ if (md) { -+ md->read_shm = 1; -+ md->rebuild_chassis = 1; -+ md->rebuild_portid = 1; -+ } - - snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, - cmd->tlvid, arg); -@@ -652,7 +647,6 @@ int mand_clif_cmd(UNUSED void *data, - char *rbuf, int rlen) - { - struct cmd cmd; -- struct port *port; - u8 len, version; - int ioff, roff; - int rstatus = cmd_invalid; -@@ -727,14 +721,6 @@ int mand_clif_cmd(UNUSED void *data, - (unsigned int)strlen(cmd.ifname), cmd.ifname); - roff = strlen(rbuf); - -- /* Confirm port is a lldpad managed port */ -- port = port_find_by_name(cmd.ifname); -- if (!port) { -- free(argvals); -- free(args); -- return cmd_device_not_found; -- } -- - switch (cmd.cmd) { - case cmd_getstats: - if (numargs) -diff --git a/lldp_util.c b/lldp_util.c -index 4a1cc4a..da210b7 100644 ---- a/lldp_util.c -+++ b/lldp_util.c -@@ -1185,7 +1185,7 @@ int get_arg_val_list(char *ibuf, int ilen, int *ioff, - *ioff += arglen; - *(arglens+i) = arglen; - -- if (ilen - *ioff > 2 * (int)sizeof(argvalue_len)) { -+ if (ilen - *ioff >= 2 * (int)sizeof(argvalue_len)) { - hexstr2bin(ibuf+*ioff, (u8 *)&argvalue_len, - sizeof(argvalue_len)); - argvalue_len = ntohs(argvalue_len); -diff --git a/lldp_vdp_cmds.c b/lldp_vdp_cmds.c -index ec9c49c..e42142f 100644 ---- a/lldp_vdp_cmds.c -+++ b/lldp_vdp_cmds.c -@@ -381,32 +381,23 @@ static int test_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, - static int get_arg_role(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { -- struct vdp_data *vd; -+ char arg_path[VDP_BUF_SIZE]; -+ const char *p; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; - - switch (cmd->tlvid) { - case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -- vd = vdp_data(cmd->ifname); -+ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); - -- if (!vd) { -- LLDPAD_ERR("%s: could not find vdp_data for %s\n", -- __FILE__, cmd->ifname); -- return cmd_device_not_found; -- } -+ if (get_cfg(cmd->ifname, cmd->type, -+ arg_path, &p, CONFIG_TYPE_STRING)) -+ p = VAL_STATION; - -- if (vd->role == VDP_ROLE_STATION) -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(arg), arg, -- (unsigned int) strlen(VAL_STATION), -- VAL_STATION); -- else if (vd->role == VDP_ROLE_BRIDGE) -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(arg), arg, -- (unsigned int) strlen(VAL_BRIDGE), VAL_BRIDGE); -- else -- return cmd_failed; -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int) strlen(arg), arg, -+ (unsigned int) strlen(p), p); - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -436,17 +427,11 @@ static int _set_arg_role(struct cmd *cmd, char *arg, char *argvalue, bool test) - - vd = vdp_data(cmd->ifname); - -- if (!vd) { -- LLDPAD_ERR("%s: could not find vdp_data for %s\n", -- __FILE__, cmd->ifname); -- return cmd_device_not_found; -- } -- - if (!strcasecmp(argvalue, VAL_BRIDGE)) { -- if (!test) -+ if (!test && vd) - vd->role = VDP_ROLE_BRIDGE; - } else if (!strcasecmp(argvalue, VAL_STATION)) { -- if (!test) -+ if (!test && vd) - vd->role = VDP_ROLE_STATION; - } else { - return cmd_invalid; -diff --git a/lldptool_cmds.c b/lldptool_cmds.c -index 17b4d8b..29c34e2 100644 ---- a/lldptool_cmds.c -+++ b/lldptool_cmds.c -@@ -462,12 +462,10 @@ static void print_tlvs(struct cmd *cmd, char *ibuf) - - printed = 0; - LIST_FOREACH(np, &lldp_head, lldp) { -- if (np->ops->print_tlv) -- if (np->ops->print_tlv(tlvid, tlv_len, -- ibuf+offset)) { -+ if (np->ops->print_tlv(tlvid, tlv_len, ibuf+offset)) { - printed = 1; - break; -- } -+ } - } - - if (!printed) { --- -1.9.3 - diff --git a/SOURCES/lldpad-do-not-require-active-TLVs-to-configure-attri.patch b/SOURCES/lldpad-do-not-require-active-TLVs-to-configure-attri.patch deleted file mode 100644 index a12bfbc..0000000 --- a/SOURCES/lldpad-do-not-require-active-TLVs-to-configure-attri.patch +++ /dev/null @@ -1,92 +0,0 @@ -From c92ad04556a0b319acc798a8499aa42b6bd766c2 Mon Sep 17 00:00:00 2001 -From: John Fastabend -Date: Mon, 8 Jul 2013 12:12:08 -0700 -Subject: [PATCH] lldpad: do not require active TLVs to configure attributes - -No longer require TLV data structures to be initialized to read/write -configuration. This allows managing ports before link is established. - -In this patch we update the command handlers to read the config file -on gets which works because sets keep the config file in sync. The set -operations are updated by removing the requirement of existing data -structures. If the data structure is not available yet the config value -is written to the configuration file only. - -Because the sets may occur before ifup() any checks for valid ports -must be done in the set handler path. For 8021qaz this means verifying -the port supports DCB. - -The VDP mode attribute is AFAIK the only attribute that can not -be set or queried before ifup(). This is because the mode values are -not stored in the config file. This is left for future work if the -VDP mode values need to be configured prior to ifup(). At this time -I'm not sure this would be useful. - -One other change is attributes without values in the config file -will be left blank when displayed with the '-c' option. I believe this -is more in spirit with the intent of the option. One example here -given on a tap device that has not been brought online yet and has -no capabilities configuration value. - -# ./lldptool -t -g ncb -i tap0 -V EVBcfg -c -fmode=bridge -capabilities= -vsis=3295 -rte=15 -enableTx=no - -I tested many of the 8021qaz, dcbtool, VDP, and EVB commands along -with some of the other TLV types. - -Signed-off-by: John Fastabend ---- - lldp_8021qaz.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/lldp_8021qaz.c b/lldp_8021qaz.c -index b3da01b..fb7843c 100644 ---- a/lldp_8021qaz.c -+++ b/lldp_8021qaz.c -@@ -492,6 +492,7 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx) - if (!attr) { - LLDPAD_DBG("%s: %s: nlmsg_find_attr failed, no GDCBX support\n", - __func__, ifname); -+ err = -EOPNOTSUPP; - goto out; - } - -@@ -540,8 +541,7 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent) - /* If hardware is not DCBX IEEE compliant or it is managed - * by an LLD agent most likely a firmware agent abort - */ -- if (!(dcbx & DCB_CAP_DCBX_VER_IEEE) || -- (dcbx & DCB_CAP_DCBX_LLD_MANAGED)) -+ if (dcbx & DCB_CAP_DCBX_LLD_MANAGED) - return; - - /* If 802.1Qaz is already configured no need to continue */ -@@ -633,8 +633,10 @@ initialized: - /* Query hardware and set maximum number of TCs with hardware values */ - len = get_ieee_hw(ifname, &ets, &pfc, &data, &cnt); - if (len > 0) { -- tlvs->ets->cfgl->max_tcs = ets->ets_cap; -- tlvs->pfc->local.pfc_cap = pfc->pfc_cap; -+ if (ets) -+ tlvs->ets->cfgl->max_tcs = ets->ets_cap; -+ if (pfc) -+ tlvs->pfc->local.pfc_cap = pfc->pfc_cap; - - free(ets); - free(pfc); -@@ -644,7 +646,7 @@ initialized: - /* if the dcbx field is filled in by the dcbx query then the - * kernel is supports IEEE mode, so make IEEE DCBX active by default. - */ -- if (!dcbx || (dcbx_get_legacy_version(ifname) & ~MASK_DCBX_FORCE)) { -+ if (dcbx_get_legacy_version(ifname) & ~MASK_DCBX_FORCE) { - tlvs->active = false; - } else { - tlvs->active = true; --- -1.9.3 - diff --git a/SPECS/lldpad.spec b/SPECS/lldpad.spec index 14bb0e7..b56e056 100644 --- a/SPECS/lldpad.spec +++ b/SPECS/lldpad.spec @@ -3,23 +3,20 @@ Name: lldpad Version: 0.9.46 -Release: 9%{?dist} +Release: 10%{?dist} Summary: Intel LLDP Agent Group: System Environment/Daemons License: GPLv2 URL: http://open-lldp.org/ Source0: %{name}-%{version}.tar.gz -Patch0: %{name}-0.9.46-multiple-vm-support.patch -Patch1: %{name}-0.9.46-migrate-properly-with-vepa.patch -Patch2: %{name}-0.9.46-Ignore-supplied-PG-configuration-if-PG-is-being-disabled.patch -Patch3: lldpad-do-not-require-active-TLVs-to-configure-attri.patch -Patch4: lldpad-correct-IEEE-DCBX-capabilities-check.patch +Patch0: %{name}-%{version}-123-g48a5f38.patch +Patch1: %{name}-0.9.46-Ignore-supplied-PG-configuration-if-PG-is-being-disabled.patch Requires: kernel >= 2.6.32 BuildRequires: automake autoconf libtool BuildRequires: flex >= 2.5.33 BuildRequires: kernel-headers >= 2.6.32 BuildRequires: libconfig-devel >= 1.3.2 -BuildRequires: libnl-devel +BuildRequires: libnl3-devel BuildRequires: readline-devel BuildRequires: systemd Requires: readline @@ -48,9 +45,6 @@ that use %{name}. %setup -q %patch0 -p1 %patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 %build ./bootstrap.sh @@ -61,23 +55,19 @@ make %{?_smp_mflags} %install make install DESTDIR=%{buildroot} -rm -f %{buildroot}%{_mandir}/man8/dcbd.8 -mkdir -p %{buildroot}%{_unitdir} -install -m644 %{name}.service %{buildroot}%{_unitdir} -rm -rf %{buildroot}/etc/init.d mkdir -p %{buildroot}%{_sharedstatedir}/%{name} rm -f %{buildroot}%{_libdir}/liblldp_clif.la %post /sbin/ldconfig -%systemd_post %{name}.service +%systemd_post %{name}.service %{name}.socket %preun -%systemd_preun %{name}.service +%systemd_preun %{name}.service %{name}.socket %postun /sbin/ldconfig -%systemd_postun_with_restart %{name}.service +%systemd_postun_with_restart %{name}.service %{name}.socket %post devel ## provide legacy support for apps that use the old dcbd interface. @@ -102,6 +92,7 @@ fi %{_libdir}/liblldp_clif.so.* %dir %{_sharedstatedir}/%{name} %{_unitdir}/%{name}.service +%{_unitdir}/%{name}.socket %dir %{_sysconfdir}/bash_completion.d/ %{_sysconfdir}/bash_completion.d/* %{_mandir}/man8/* @@ -112,6 +103,9 @@ fi %{_libdir}/liblldp_clif.so %changelog +* Tue Oct 21 2014 Chris Leech - 0.9.46-10 +- Sync with upstream v0.9.46-123-g48a5f38 (#1087096) + * Fri Jun 27 2014 Chris Leech - 0.9.46-9 - Fix IEEE mode DCBX (#1102886)