diff --git a/SOURCES/lldpad-correct-IEEE-DCBX-capabilities-check.patch b/SOURCES/lldpad-correct-IEEE-DCBX-capabilities-check.patch new file mode 100644 index 0000000..e84c17c --- /dev/null +++ b/SOURCES/lldpad-correct-IEEE-DCBX-capabilities-check.patch @@ -0,0 +1,1607 @@ +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 new file mode 100644 index 0000000..a12bfbc --- /dev/null +++ b/SOURCES/lldpad-do-not-require-active-TLVs-to-configure-attri.patch @@ -0,0 +1,92 @@ +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 9ea93fe..14bb0e7 100644 --- a/SPECS/lldpad.spec +++ b/SPECS/lldpad.spec @@ -3,7 +3,7 @@ Name: lldpad Version: 0.9.46 -Release: 8%{?dist} +Release: 9%{?dist} Summary: Intel LLDP Agent Group: System Environment/Daemons License: GPLv2 @@ -12,6 +12,8 @@ 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 Requires: kernel >= 2.6.32 BuildRequires: automake autoconf libtool BuildRequires: flex >= 2.5.33 @@ -47,6 +49,8 @@ that use %{name}. %patch0 -p1 %patch1 -p1 %patch2 -p1 +%patch3 -p1 +%patch4 -p1 %build ./bootstrap.sh @@ -108,6 +112,9 @@ fi %{_libdir}/liblldp_clif.so %changelog +* Fri Jun 27 2014 Chris Leech - 0.9.46-9 +- Fix IEEE mode DCBX (#1102886) + * Wed Mar 19 2014 Petr Ĺ abata - 0.9.46-8 - Ignore supplied PG configuration if PG is being disabled (#1067261)