|
Packit |
597cd4 |
/******************************************************************************
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
LLDP Agent Daemon (LLDPAD) Software
|
|
Packit |
597cd4 |
Copyright(c) 2007-2012 Intel Corporation.
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
This program is free software; you can redistribute it and/or modify it
|
|
Packit |
597cd4 |
under the terms and conditions of the GNU General Public License,
|
|
Packit |
597cd4 |
version 2, as published by the Free Software Foundation.
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit |
597cd4 |
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit |
597cd4 |
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
Packit |
597cd4 |
more details.
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
You should have received a copy of the GNU General Public License along with
|
|
Packit |
597cd4 |
this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
597cd4 |
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
The full GNU General Public License is included in this distribution in
|
|
Packit |
597cd4 |
the file called "COPYING".
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
Contact Information:
|
|
Packit |
597cd4 |
open-lldp Mailing List <lldp-devel@open-lldp.org>
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
******************************************************************************/
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
#include <stdlib.h>
|
|
Packit |
597cd4 |
#include <assert.h>
|
|
Packit |
597cd4 |
#include <errno.h>
|
|
Packit |
597cd4 |
#include <netlink/attr.h>
|
|
Packit |
597cd4 |
#include <netlink/msg.h>
|
|
Packit |
597cd4 |
#include "lldp.h"
|
|
Packit |
597cd4 |
#include "lldp_8021qaz.h"
|
|
Packit |
597cd4 |
#include "messages.h"
|
|
Packit |
597cd4 |
#include "lldp_util.h"
|
|
Packit |
597cd4 |
#include "dcb_driver_interface.h"
|
|
Packit |
597cd4 |
#include "config.h"
|
|
Packit |
597cd4 |
#include "lldp_mand_clif.h"
|
|
Packit |
597cd4 |
#include "lldp_dcbx_nl.h"
|
|
Packit |
597cd4 |
#include "lldp/l2_packet.h"
|
|
Packit |
597cd4 |
#include "lldp/ports.h"
|
|
Packit |
597cd4 |
#include "lldpad_status.h"
|
|
Packit |
597cd4 |
#include "lldp_8021qaz_cmds.h"
|
|
Packit |
597cd4 |
#include "lldp_mand_clif.h"
|
|
Packit |
597cd4 |
#include "include/linux/dcbnl.h"
|
|
Packit |
597cd4 |
#include "include/linux/rtnetlink.h"
|
|
Packit |
597cd4 |
#include "include/linux/netlink.h"
|
|
Packit |
597cd4 |
#include "lldp_dcbx.h"
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
struct lldp_head lldp_head;
|
|
Packit |
597cd4 |
struct config_t lldpad_cfg;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static int ieee8021qaz_check_pending(struct port *port, struct lldp_agent *);
|
|
Packit |
597cd4 |
static void run_all_sm(struct port *port, struct lldp_agent *agent);
|
|
Packit |
597cd4 |
static void ieee8021qaz_mibUpdateObjects(struct port *port);
|
|
Packit |
597cd4 |
static void ieee8021qaz_app_reset(struct app_tlv_head *head);
|
|
Packit |
597cd4 |
static int get_ieee_hw(const char *ifname, struct ieee_ets **ets,
|
|
Packit |
597cd4 |
struct ieee_pfc **pfc, struct app_prio **app,
|
|
Packit |
597cd4 |
int *cnt);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static const struct lldp_mod_ops ieee8021qaz_ops = {
|
|
Packit |
597cd4 |
.lldp_mod_register = ieee8021qaz_register,
|
|
Packit |
597cd4 |
.lldp_mod_unregister = ieee8021qaz_unregister,
|
|
Packit |
597cd4 |
.lldp_mod_gettlv = ieee8021qaz_gettlv,
|
|
Packit |
597cd4 |
.lldp_mod_rchange = ieee8021qaz_rchange,
|
|
Packit |
597cd4 |
.lldp_mod_ifup = ieee8021qaz_ifup,
|
|
Packit |
597cd4 |
.lldp_mod_ifdown = ieee8021qaz_ifdown,
|
|
Packit |
597cd4 |
.lldp_mod_mibdelete = ieee8021qaz_mibDeleteObject,
|
|
Packit |
597cd4 |
.get_arg_handler = ieee8021qaz_get_arg_handlers,
|
|
Packit |
597cd4 |
.timer = ieee8021qaz_check_pending,
|
|
Packit |
597cd4 |
};
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static int ieee8021qaz_check_pending(struct port *port,
|
|
Packit |
597cd4 |
struct lldp_agent *agent)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_user_data *iud;
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlv = NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!port->portEnabled)
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
|
|
Packit |
597cd4 |
if (iud) {
|
|
Packit |
597cd4 |
LIST_FOREACH(tlv, &iud->head, entry) {
|
|
Packit |
597cd4 |
if (!strncmp(port->ifname, tlv->ifname, IFNAMSIZ)) {
|
|
Packit |
597cd4 |
if (tlv->active && tlv->pending &&
|
|
Packit |
597cd4 |
port->dormantDelay == 1) {
|
|
Packit |
597cd4 |
tlv->pending = false;
|
|
Packit |
597cd4 |
ieee8021qaz_app_reset(&tlv->app_head);
|
|
Packit |
597cd4 |
run_all_sm(port, agent);
|
|
Packit |
597cd4 |
somethingChangedLocal(port->ifname,
|
|
Packit |
597cd4 |
agent->type);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* LLDP_8021QAZ_MOD_OPS - REGISTER */
|
|
Packit |
597cd4 |
struct lldp_module *ieee8021qaz_register(void)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct lldp_module *mod;
|
|
Packit |
597cd4 |
struct ieee8021qaz_user_data *iud;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
mod = malloc(sizeof(*mod));
|
|
Packit |
597cd4 |
if (!mod) {
|
|
Packit |
597cd4 |
LLDPAD_ERR("Failed to malloc LLDP-8021QAZ module data");
|
|
Packit |
597cd4 |
goto out_err;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
iud = malloc(sizeof(*iud));
|
|
Packit |
597cd4 |
if (!iud) {
|
|
Packit |
597cd4 |
free(mod);
|
|
Packit |
597cd4 |
LLDPAD_ERR("Failed to malloc LLDP-8021QAZ module user data");
|
|
Packit |
597cd4 |
goto out_err;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
memset((void *) iud, 0, sizeof(struct ieee8021qaz_user_data));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
LIST_INIT(&iud->head);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
mod->id = LLDP_MOD_8021QAZ;
|
|
Packit |
597cd4 |
mod->ops = &ieee8021qaz_ops;
|
|
Packit |
597cd4 |
mod->data = iud;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
LLDPAD_DBG("%s: ieee8021qaz_register SUCCESS\n", __func__);
|
|
Packit |
597cd4 |
return mod;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
out_err:
|
|
Packit |
597cd4 |
LLDPAD_DBG("%s: ieee8021qaz_register FAILED\n", __func__);
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *ieee8021qaz_data(const char *ifname)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_user_data *iud;
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlv = NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
|
|
Packit |
597cd4 |
if (iud) {
|
|
Packit |
597cd4 |
LIST_FOREACH(tlv, &iud->head, entry) {
|
|
Packit |
597cd4 |
if (!strncmp(tlv->ifname, ifname, IFNAMSIZ))
|
|
Packit |
597cd4 |
return tlv;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void set_ets_prio_map(const char *arg, u32 *prio_map)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
char *argcpy = strdup(arg);
|
|
Packit |
597cd4 |
char *tokens;
|
|
Packit |
597cd4 |
int tc, prio;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!argcpy)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tokens = strtok(argcpy, ",");
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
while (tokens) {
|
|
Packit |
597cd4 |
prio = 0x7 & atoi(tokens);
|
|
Packit |
597cd4 |
tc = 0x7 & atoi(&tokens[2]);
|
|
Packit |
597cd4 |
*prio_map |= tc << (4 * (7-prio));
|
|
Packit |
597cd4 |
tokens = strtok(NULL, ",");
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
free(argcpy);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void set_ets_tsa_map(const char *arg, u8 *tsa_map)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int i, type, tc;
|
|
Packit |
597cd4 |
char *argcpy = strdup(arg);
|
|
Packit |
597cd4 |
char *tokens;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!argcpy)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tokens = strtok(argcpy, ",");
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; tokens; i++) {
|
|
Packit |
597cd4 |
tc = atoi(tokens);
|
|
Packit |
597cd4 |
if ((strcmp(&tokens[2], "strict")) == 0)
|
|
Packit |
597cd4 |
type = IEEE8021Q_TSA_STRICT;
|
|
Packit |
597cd4 |
else if ((strcmp(&tokens[2], "cb_shaper")) == 0)
|
|
Packit |
597cd4 |
type = IEEE8021Q_TSA_CBSHAPER;
|
|
Packit |
597cd4 |
else if ((strcmp(&tokens[2], "ets")) == 0)
|
|
Packit |
597cd4 |
type = IEEE8021Q_TSA_ETS;
|
|
Packit |
597cd4 |
else if ((strcmp(&tokens[2], "vendor")) == 0)
|
|
Packit |
597cd4 |
type = IEEE8021Q_TSA_VENDOR;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
type = IEEE8021Q_TSA_STRICT;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tsa_map[tc] = type;
|
|
Packit |
597cd4 |
tokens = strtok(NULL, ",");
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
free(argcpy);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static int read_cfg_file(char *ifname, struct lldp_agent *agent,
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
const char *arg = NULL;
|
|
Packit |
597cd4 |
char arg_path[256];
|
|
Packit |
597cd4 |
int res = 0, i;
|
|
Packit |
597cd4 |
int willing, pfc_mask, delay;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read ETS-CFG willing bit -- default willing enabled */
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_ETSCFG), ARG_WILLING);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &willing,
|
|
Packit |
597cd4 |
CONFIG_TYPE_INT);
|
|
Packit |
597cd4 |
if (!res)
|
|
Packit |
597cd4 |
tlvs->ets->cfgl->willing = !!willing;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->ets->cfgl->willing = 1;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read PFC willing bit -- default willing enabled */
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_PFC), ARG_WILLING);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &willing,
|
|
Packit |
597cd4 |
CONFIG_TYPE_INT);
|
|
Packit |
597cd4 |
if (!res)
|
|
Packit |
597cd4 |
tlvs->pfc->local.willing = !!willing;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->pfc->local.willing = 1;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and parse ETS-CFG priority map --
|
|
Packit |
597cd4 |
* default all priorities TC0
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_ETSCFG), ARG_ETS_UP2TC);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &arg,
|
|
Packit |
597cd4 |
CONFIG_TYPE_STRING);
|
|
Packit |
597cd4 |
if (!res)
|
|
Packit |
597cd4 |
set_ets_prio_map(arg, &tlvs->ets->cfgl->prio_map);
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->ets->cfgl->prio_map = 0x00000000;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Default ETS-CFG num_tc to MAX */
|
|
Packit |
597cd4 |
tlvs->ets->cfgl->max_tcs = MAX_TCS;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and parse ETS-REC priority map --
|
|
Packit |
597cd4 |
* default all priorities TC0
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_ETSREC), ARG_ETS_UP2TC);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &arg,
|
|
Packit |
597cd4 |
CONFIG_TYPE_STRING);
|
|
Packit |
597cd4 |
if (!res)
|
|
Packit |
597cd4 |
set_ets_prio_map(arg, &tlvs->ets->recl->prio_map);
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->ets->recl->prio_map = 0x00000000;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and parse ETS-CFG tc bandwidth map --
|
|
Packit |
597cd4 |
* default percentage mapping 0,0,0,0,0,0,0,0 (strict priority)
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_ETSCFG), ARG_ETS_TCBW);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &arg,
|
|
Packit |
597cd4 |
CONFIG_TYPE_STRING);
|
|
Packit |
597cd4 |
if (!res) {
|
|
Packit |
597cd4 |
char *argcpy = strdup(arg);
|
|
Packit |
597cd4 |
char *tokens;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (argcpy) {
|
|
Packit |
597cd4 |
tokens = strtok(argcpy, ",");
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; tokens; i++) {
|
|
Packit |
597cd4 |
tlvs->ets->cfgl->tc_bw[i] = atoi(tokens);
|
|
Packit |
597cd4 |
tokens = strtok(NULL, ",");
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
free(argcpy);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and parse ETS-REC tc bandwidth map --
|
|
Packit |
597cd4 |
* default percentage mapping 0,0,0,0,0,0,0,0 (strict priority)
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_ETSREC), ARG_ETS_TCBW);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &arg,
|
|
Packit |
597cd4 |
CONFIG_TYPE_STRING);
|
|
Packit |
597cd4 |
if (!res) {
|
|
Packit |
597cd4 |
char *argcpy = strdup(arg);
|
|
Packit |
597cd4 |
char *tokens;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (argcpy) {
|
|
Packit |
597cd4 |
tokens = strtok(argcpy, ",");
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; tokens; i++) {
|
|
Packit |
597cd4 |
tlvs->ets->recl->tc_bw[i] = atoi(tokens);
|
|
Packit |
597cd4 |
tokens = strtok(NULL, ",");
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
free(argcpy);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and parse ETS-CFG tc transmission selction algorithm map
|
|
Packit |
597cd4 |
* This defaults to all traffic classes using strict priority
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_ETSCFG), ARG_ETS_TSA);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &arg,
|
|
Packit |
597cd4 |
CONFIG_TYPE_STRING);
|
|
Packit |
597cd4 |
if (!res) {
|
|
Packit |
597cd4 |
set_ets_tsa_map(arg, tlvs->ets->cfgl->tsa_map);
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++)
|
|
Packit |
597cd4 |
tlvs->ets->cfgl->tsa_map[i] = IEEE8021Q_TSA_STRICT;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and parse ETS-REC tc transmission selction algorithm map
|
|
Packit |
597cd4 |
* This defaults to all traffic classes using strict priority
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_ETSREC), ARG_ETS_TSA);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &arg,
|
|
Packit |
597cd4 |
CONFIG_TYPE_STRING);
|
|
Packit |
597cd4 |
if (!res) {
|
|
Packit |
597cd4 |
set_ets_tsa_map(arg, tlvs->ets->recl->tsa_map);
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++)
|
|
Packit |
597cd4 |
tlvs->ets->recl->tsa_map[i] = IEEE8021Q_TSA_STRICT;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and parse PFC enable bitmask -- default 0x00 */
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_PFC), ARG_PFC_ENABLED);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &pfc_mask,
|
|
Packit |
597cd4 |
CONFIG_TYPE_INT);
|
|
Packit |
597cd4 |
if (!res)
|
|
Packit |
597cd4 |
tlvs->pfc->local.pfc_enable = pfc_mask;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and parse PFC delay -- default 0x00 */
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_PFC), ARG_PFC_DELAY);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &delay,
|
|
Packit |
597cd4 |
CONFIG_TYPE_INT);
|
|
Packit |
597cd4 |
if (!res)
|
|
Packit |
597cd4 |
tlvs->pfc->local.delay = delay;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Default PFC capabilities to MAX */
|
|
Packit |
597cd4 |
tlvs->pfc->local.pfc_cap = MAX_TCS;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Read and add APP data to internal lldpad APP ring */
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_APP_ENTRIES; i++) {
|
|
Packit |
597cd4 |
char *parse;
|
|
Packit |
597cd4 |
char *app_tuple;
|
|
Packit |
597cd4 |
u8 prio, sel;
|
|
Packit |
597cd4 |
long pid;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
snprintf(arg_path, sizeof(arg_path), "%s%08x.%s%i", TLVID_PREFIX,
|
|
Packit |
597cd4 |
TLVID_8021(LLDP_8021QAZ_APP), ARG_APP, i);
|
|
Packit |
597cd4 |
res = get_config_setting(ifname, agent->type, arg_path, &arg,
|
|
Packit |
597cd4 |
CONFIG_TYPE_STRING);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (res)
|
|
Packit |
597cd4 |
continue;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Parse cfg file input, bounds checking done on set app cmd */
|
|
Packit |
597cd4 |
parse = strdup(arg);
|
|
Packit |
597cd4 |
if (!parse)
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
app_tuple = strtok(parse, ",");
|
|
Packit |
597cd4 |
if (!app_tuple)
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
prio = atoi(app_tuple);
|
|
Packit |
597cd4 |
app_tuple = strtok(NULL, ",");
|
|
Packit |
597cd4 |
if (!app_tuple)
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
sel = atoi(app_tuple);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
app_tuple = strtok(NULL, ",");
|
|
Packit |
597cd4 |
if (!app_tuple)
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* APP Data can be in hex or integer form */
|
|
Packit |
597cd4 |
errno = 0;
|
|
Packit |
597cd4 |
pid = strtol(app_tuple, NULL, 0);
|
|
Packit |
597cd4 |
if (!errno)
|
|
Packit |
597cd4 |
ieee8021qaz_mod_app(&tlvs->app_head, 0,
|
|
Packit |
597cd4 |
prio, sel, (u16) pid, 0);
|
|
Packit |
597cd4 |
free(parse);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
inline int get_prio_map(u32 prio_map, int prio)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
if (prio > 7)
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return (prio_map >> (4 * (7-prio))) & 0xF;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
inline void set_prio_map(u32 *prio_map, u8 prio, int tc)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
u32 mask = ~(0xffffffff & (0xF << (4 * (7-prio))));
|
|
Packit |
597cd4 |
*prio_map &= mask;
|
|
Packit |
597cd4 |
*prio_map |= tc << (4 * (7-prio));
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* get_dcbx_hw - Get bitmask of hardware DCBX version and firmware status
|
|
Packit |
597cd4 |
*
|
|
Packit |
597cd4 |
* @ifname: interface name to query
|
|
Packit |
597cd4 |
* @dcbx: bitmask to store DCBX capabilities
|
|
Packit |
597cd4 |
*
|
|
Packit |
597cd4 |
* Returns 0 on success, error value otherwise.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
int get_dcbx_hw(const char *ifname, __u8 *dcbx)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int err = 0;
|
|
Packit |
597cd4 |
struct nlattr *attr;
|
|
Packit |
597cd4 |
struct sockaddr_nl dest_addr;
|
|
Packit |
597cd4 |
static struct nl_sock *nlsocket;
|
|
Packit |
597cd4 |
struct nl_msg *nlm = NULL;
|
|
Packit |
597cd4 |
unsigned char *msg = NULL;
|
|
Packit |
597cd4 |
struct nlmsghdr *hdr;
|
|
Packit |
597cd4 |
struct dcbmsg d = {
|
|
Packit |
597cd4 |
.dcb_family = AF_UNSPEC,
|
|
Packit |
597cd4 |
.cmd = DCB_CMD_GDCBX,
|
|
Packit |
597cd4 |
.dcb_pad = 0
|
|
Packit |
597cd4 |
};
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!nlsocket) {
|
|
Packit |
597cd4 |
nlsocket = nl_socket_alloc();
|
|
Packit |
597cd4 |
if (!nlsocket) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: nl_socket_alloc failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
nl_socket_set_local_port(nlsocket, 0);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nl_connect(nlsocket, NETLINK_ROUTE);
|
|
Packit |
597cd4 |
if (err < 0) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s nlconnect failed abort get ieee, %s\n",
|
|
Packit |
597cd4 |
__func__, ifname, nl_geterror(err));
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nlm = nlmsg_alloc_simple(RTM_GETDCB, NLM_F_REQUEST);
|
|
Packit |
597cd4 |
if (!nlm) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s nlmsg_alloc failed abort get ieee\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(&dest_addr, 0, sizeof(dest_addr));
|
|
Packit |
597cd4 |
dest_addr.nl_family = AF_NETLINK;
|
|
Packit |
597cd4 |
nlmsg_set_dst(nlm, &dest_addr);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nlmsg_append(nlm, &d, sizeof(d), NLMSG_ALIGNTO);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nla_put(nlm, DCB_ATTR_IFNAME, strlen(ifname)+1, ifname);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nl_send_auto_complete(nlsocket, nlm);
|
|
Packit |
597cd4 |
if (err <= 0) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s 802.1Qaz get app attributes failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nl_recv(nlsocket, &dest_addr, &msg, NULL);
|
|
Packit |
597cd4 |
if (err <= 0) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: nl_recv returned %d\n", __func__, ifname,
|
|
Packit |
597cd4 |
err);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
hdr = (struct nlmsghdr *) msg;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
attr = nlmsg_find_attr(hdr, sizeof(d), DCB_ATTR_DCBX);
|
|
Packit |
597cd4 |
if (!attr) {
|
|
Packit |
597cd4 |
LLDPAD_DBG("%s: %s: nlmsg_find_attr failed, no GDCBX support\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
err = -EOPNOTSUPP;
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
*dcbx = nla_get_u8(attr);
|
|
Packit |
597cd4 |
out:
|
|
Packit |
597cd4 |
nlmsg_free(nlm);
|
|
Packit |
597cd4 |
free(msg);
|
|
Packit |
597cd4 |
if (nlsocket)
|
|
Packit |
597cd4 |
nl_close(nlsocket);
|
|
Packit |
597cd4 |
return err;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* LLDP_8021QAZ_MOD_OPS - IFUP
|
|
Packit |
597cd4 |
*
|
|
Packit |
597cd4 |
* Load TLV values (either from config file, command prompt or defaults),
|
|
Packit |
597cd4 |
* set up adapter, initialize FSMs and build tlvs
|
|
Packit |
597cd4 |
*
|
|
Packit |
597cd4 |
* Check if a 'config' file exists (to load tlv values). If YES, load save them
|
|
Packit |
597cd4 |
* as new defaults. If NO, load defaults. Also, check for TLV values via cmd
|
|
Packit |
597cd4 |
* prompt. Then initialize FSMs for each tlv and finally build the tlvs
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct port *port = NULL;
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
struct ieee8021qaz_user_data *iud;
|
|
Packit |
597cd4 |
int adminstatus, cnt, len;
|
|
Packit |
597cd4 |
__u8 dcbx = 0;
|
|
Packit |
597cd4 |
struct ieee_ets *ets = NULL;
|
|
Packit |
597cd4 |
struct ieee_pfc *pfc = NULL;
|
|
Packit |
597cd4 |
struct app_prio *data = NULL;
|
|
Packit |
597cd4 |
int err, no_set_status;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* 802.1Qaz does not support bonded or vlan devices */
|
|
Packit |
597cd4 |
if (is_bond(ifname) || is_vlan(ifname))
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = get_dcbx_hw(ifname, &dcbx);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* If admin has explicitly enabled Rx/Tx, don't override it */
|
|
Packit |
597cd4 |
no_set_status = get_config_setting(ifname, agent->type, ARG_ADMINSTATUS,
|
|
Packit |
597cd4 |
&adminstatus, CONFIG_TYPE_INT);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* If hardware is not DCBX IEEE compliant or it is managed
|
|
Packit |
597cd4 |
* by an LLD agent most likely a firmware agent abort
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
if (dcbx & DCB_CAP_DCBX_LLD_MANAGED) {
|
|
Packit |
597cd4 |
if (no_set_status)
|
|
Packit |
597cd4 |
set_lldp_agent_admin(ifname, agent->type,
|
|
Packit |
597cd4 |
(adminstatus & enabledRxOnly));
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* If 802.1Qaz is already configured no need to continue */
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(ifname);
|
|
Packit |
597cd4 |
if (tlvs)
|
|
Packit |
597cd4 |
goto initialized;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* if there is no persistent adminStatus setting then set to enabledRx
|
|
Packit |
597cd4 |
* but do not persist that as a setting.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
if (no_set_status)
|
|
Packit |
597cd4 |
set_lldp_agent_admin(ifname, agent->type, enabledRxOnly);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* lookup port data */
|
|
Packit |
597cd4 |
port = port_find_by_ifindex(get_ifidx(ifname));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* Check if link down and/or tlvs exist for current port.
|
|
Packit |
597cd4 |
* If true, then return without any further work
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
if (!port)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Initializing TLV structs */
|
|
Packit |
597cd4 |
tlvs = malloc(sizeof(*tlvs));
|
|
Packit |
597cd4 |
if (!tlvs) {
|
|
Packit |
597cd4 |
LLDPAD_DBG("%s: ifname %s malloc failed.\n", __func__, ifname);
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
memset(tlvs, 0, sizeof(*tlvs));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->rx = malloc(sizeof(*tlvs->rx));
|
|
Packit |
597cd4 |
if (!tlvs->rx) {
|
|
Packit |
597cd4 |
free(tlvs);
|
|
Packit |
597cd4 |
LLDPAD_DBG("%s: %s malloc failed.\n", __func__, ifname);
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
memset(tlvs->rx, 0, sizeof(*tlvs->rx));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Initializing the ieee8021qaz_tlvs struct */
|
|
Packit |
597cd4 |
strncpy(tlvs->ifname, ifname, IFNAMSIZ);
|
|
Packit |
597cd4 |
tlvs->port = port;
|
|
Packit |
597cd4 |
tlvs->ieee8021qazdu = 0;
|
|
Packit |
597cd4 |
l2_packet_get_own_src_addr(port->l2, tlvs->local_mac);
|
|
Packit |
597cd4 |
memset(tlvs->remote_mac, 0, ETH_ALEN);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Initialize all TLVs */
|
|
Packit |
597cd4 |
tlvs->ets = malloc(sizeof(*tlvs->ets));
|
|
Packit |
597cd4 |
if (!tlvs->ets)
|
|
Packit |
597cd4 |
goto err;
|
|
Packit |
597cd4 |
memset(tlvs->ets, 0, sizeof(*tlvs->ets));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->ets->cfgl = malloc(sizeof(*tlvs->ets->cfgl));
|
|
Packit |
597cd4 |
if (!tlvs->ets->cfgl)
|
|
Packit |
597cd4 |
goto err;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->ets->recl = malloc(sizeof(*tlvs->ets->recl));
|
|
Packit |
597cd4 |
if (!tlvs->ets->recl)
|
|
Packit |
597cd4 |
goto err_recl;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->pfc = malloc(sizeof(*tlvs->pfc));
|
|
Packit |
597cd4 |
if (!tlvs->pfc)
|
|
Packit |
597cd4 |
goto err_pfc;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(tlvs->ets->cfgl, 0, sizeof(*tlvs->ets->cfgl));
|
|
Packit |
597cd4 |
memset(tlvs->ets->recl, 0, sizeof(*tlvs->ets->recl));
|
|
Packit |
597cd4 |
memset(tlvs->pfc, 0, sizeof(*tlvs->pfc));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->ets->pending = 1;
|
|
Packit |
597cd4 |
tlvs->ets->current_state = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->pfc->pending = 1;
|
|
Packit |
597cd4 |
tlvs->pfc->current_state = 0;
|
|
Packit |
597cd4 |
tlvs->pfc->remote_param = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
LIST_INIT(&tlvs->app_head);
|
|
Packit |
597cd4 |
read_cfg_file(port->ifname, agent, tlvs);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
|
|
Packit |
597cd4 |
LIST_INSERT_HEAD(&iud->head, tlvs, entry);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
initialized:
|
|
Packit |
597cd4 |
/* Query hardware and set maximum number of TCs with hardware values */
|
|
Packit |
597cd4 |
len = get_ieee_hw(ifname, &ets, &pfc, &data, &cnt);
|
|
Packit |
597cd4 |
if (len > 0) {
|
|
Packit |
597cd4 |
if (ets)
|
|
Packit |
597cd4 |
tlvs->ets->cfgl->max_tcs = ets->ets_cap;
|
|
Packit |
597cd4 |
if (pfc)
|
|
Packit |
597cd4 |
tlvs->pfc->local.pfc_cap = pfc->pfc_cap;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
free(ets);
|
|
Packit |
597cd4 |
free(pfc);
|
|
Packit |
597cd4 |
free(data);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* if the dcbx field is filled in by the dcbx query then the
|
|
Packit |
597cd4 |
* kernel is supports IEEE mode, so make IEEE DCBX active by default.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
if (dcbx_get_legacy_version(ifname) & ~MASK_DCBX_FORCE) {
|
|
Packit |
597cd4 |
tlvs->active = false;
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
tlvs->active = true;
|
|
Packit |
597cd4 |
tlvs->pending = true;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
err_pfc:
|
|
Packit |
597cd4 |
free(tlvs->ets->recl);
|
|
Packit |
597cd4 |
err_recl:
|
|
Packit |
597cd4 |
free(tlvs->ets->cfgl);
|
|
Packit |
597cd4 |
err:
|
|
Packit |
597cd4 |
free(tlvs->ets);
|
|
Packit |
597cd4 |
free(tlvs->rx);
|
|
Packit |
597cd4 |
free(tlvs);
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s malloc failed.\n", __func__, ifname);
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* ets_sm - Asymmetric State Machine for the ETS tlv
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
static void ets_sm(struct etscfg_obj *localAdminParam,
|
|
Packit |
597cd4 |
struct etsrec_obj *remoteParam,
|
|
Packit |
597cd4 |
bool *state)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int willing = localAdminParam->willing;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (willing && remoteParam)
|
|
Packit |
597cd4 |
*state = RX_RECOMMEND;
|
|
Packit |
597cd4 |
else if (!willing || !remoteParam)
|
|
Packit |
597cd4 |
*state = INIT;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* cmp_mac_addrs - Compares 2 MAC addresses.
|
|
Packit |
597cd4 |
* returns 1, if first_mac > second_mac; else 0
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
static bool cmp_mac_addrs(u8 first_mac[], u8 second_mac[])
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int i;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < ETH_ALEN; i++) {
|
|
Packit |
597cd4 |
if (first_mac[i] == second_mac[i])
|
|
Packit |
597cd4 |
continue;
|
|
Packit |
597cd4 |
if (first_mac[i] < second_mac[i])
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
return 1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* pfc_sm - Symmetric State Machine for the PFC tlv
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
static void pfc_sm(struct ieee8021qaz_tlvs *tlvs)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
bool local_willing, remote_willing;
|
|
Packit |
597cd4 |
bool remote_param, cmp_mac;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
local_willing = tlvs->pfc->local.willing;
|
|
Packit |
597cd4 |
remote_willing = tlvs->pfc->remote.willing;
|
|
Packit |
597cd4 |
remote_param = tlvs->pfc->remote_param;
|
|
Packit |
597cd4 |
cmp_mac = cmp_mac_addrs(tlvs->local_mac, tlvs->remote_mac);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if ((local_willing && !remote_willing && remote_param) ||
|
|
Packit |
597cd4 |
(local_willing && remote_willing && !cmp_mac))
|
|
Packit |
597cd4 |
tlvs->pfc->current_state = RX_RECOMMEND;
|
|
Packit |
597cd4 |
else if (!local_willing || !remote_param ||
|
|
Packit |
597cd4 |
(local_willing && remote_willing && cmp_mac))
|
|
Packit |
597cd4 |
tlvs->pfc->current_state = INIT;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
#ifdef LLDPAD_8021QAZ_DEBUG
|
|
Packit |
597cd4 |
void print_ets(struct ieee_ets *ets)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int i;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
printf("ETS:\n");
|
|
Packit |
597cd4 |
printf("\tcap %2x cbs %2x\n", ets->ets_cap, ets->cbs);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
printf("\tets tc_tx_bw: ");
|
|
Packit |
597cd4 |
for (i = 0; i < 8; i++)
|
|
Packit |
597cd4 |
printf("%i ", ets->tc_tx_bw[i]);
|
|
Packit |
597cd4 |
printf("\n");
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
printf("\tets tc_rx_bw: ");
|
|
Packit |
597cd4 |
for (i = 0; i < 8; i++)
|
|
Packit |
597cd4 |
printf("%i ", ets->tc_rx_bw[i]);
|
|
Packit |
597cd4 |
printf("\n");
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
printf("\tets tc_tsa: ");
|
|
Packit |
597cd4 |
for (i = 0; i < 8; i++)
|
|
Packit |
597cd4 |
printf("%i ", ets->tc_tsa[i]);
|
|
Packit |
597cd4 |
printf("\n");
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
printf("\tets prio_tc: ");
|
|
Packit |
597cd4 |
for (i = 0; i < 8; i++)
|
|
Packit |
597cd4 |
printf("%i ", ets->prio_tc[i]);
|
|
Packit |
597cd4 |
printf("\n");
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
void print_pfc(struct ieee_pfc *pfc)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int i;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
printf("PFC:\n");
|
|
Packit |
597cd4 |
printf("\t cap %2x en %2x\n", pfc->pfc_cap, pfc->pfc_en);
|
|
Packit |
597cd4 |
printf("\t mbc %2x delay %i\n", pfc->mbc, pfc->delay);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
printf("\t requests: ");
|
|
Packit |
597cd4 |
for (i = 0; i < 8; i++)
|
|
Packit |
597cd4 |
printf("%llu ", pfc->requests[i]);
|
|
Packit |
597cd4 |
printf("\n");
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
printf("\t indications: ");
|
|
Packit |
597cd4 |
for (i = 0; i < 8; i++)
|
|
Packit |
597cd4 |
printf("%llu ", pfc->indications[i]);
|
|
Packit |
597cd4 |
printf("\n");
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
#endif
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* get_ieee_hw - Populates IEEE data structures with hardware DCB attributes.
|
|
Packit |
597cd4 |
*
|
|
Packit |
597cd4 |
* @ifname: interface name to query
|
|
Packit |
597cd4 |
* @ets: pointer to copy returned ETS struct
|
|
Packit |
597cd4 |
* @pfc: pointer to copy returned PFC struct
|
|
Packit |
597cd4 |
* @app: pointer to copy concatenated APP entries
|
|
Packit |
597cd4 |
* @cnt: number of app entries returned
|
|
Packit |
597cd4 |
*
|
|
Packit |
597cd4 |
* Returns nlmsg bytes size on success otherwise negative error code.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
static int get_ieee_hw(const char *ifname, struct ieee_ets **ets,
|
|
Packit |
597cd4 |
struct ieee_pfc **pfc, struct app_prio **app,
|
|
Packit |
597cd4 |
int *cnt)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int err = 0;
|
|
Packit |
597cd4 |
int rem;
|
|
Packit |
597cd4 |
int itr = 0;
|
|
Packit |
597cd4 |
struct sockaddr_nl dest_addr;
|
|
Packit |
597cd4 |
struct nl_sock *nlsocket = NULL;
|
|
Packit |
597cd4 |
struct nl_msg *nlm;
|
|
Packit |
597cd4 |
unsigned char *msg = NULL;
|
|
Packit |
597cd4 |
struct nlmsghdr *hdr;
|
|
Packit |
597cd4 |
struct nlattr *app_attr, *attr, *nattr;
|
|
Packit |
597cd4 |
struct dcbmsg d = {
|
|
Packit |
597cd4 |
.dcb_family = AF_UNSPEC,
|
|
Packit |
597cd4 |
.cmd = DCB_CMD_IEEE_GET,
|
|
Packit |
597cd4 |
.dcb_pad = 0
|
|
Packit |
597cd4 |
};
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nlsocket = nl_socket_alloc();
|
|
Packit |
597cd4 |
if (!nlsocket) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
*cnt = 0;
|
|
Packit |
597cd4 |
return -ENOMEM;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
nl_socket_set_local_port(nlsocket, 0);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nl_connect(nlsocket, NETLINK_ROUTE);
|
|
Packit |
597cd4 |
if (err < 0) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s nlconnect failed abort get ieee, %s\n",
|
|
Packit |
597cd4 |
__func__, ifname, nl_geterror(err));
|
|
Packit |
597cd4 |
goto out1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nlm = nlmsg_alloc_simple(RTM_GETDCB, NLM_F_REQUEST);
|
|
Packit |
597cd4 |
if (!nlm) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(&dest_addr, 0, sizeof(dest_addr));
|
|
Packit |
597cd4 |
dest_addr.nl_family = AF_NETLINK;
|
|
Packit |
597cd4 |
nlmsg_set_dst(nlm, &dest_addr);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nlmsg_append(nlm, &d, sizeof(d), NLMSG_ALIGNTO);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nla_put(nlm, DCB_ATTR_IFNAME, strlen(ifname)+1, ifname);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nl_send_auto_complete(nlsocket, nlm);
|
|
Packit |
597cd4 |
if (err <= 0) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s 802.1Qaz get app attributes failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nl_recv(nlsocket, &dest_addr, &msg, NULL);
|
|
Packit |
597cd4 |
if (err <= 0) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: nl_recv returned %d\n", __func__, ifname,
|
|
Packit |
597cd4 |
err);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
hdr = (struct nlmsghdr *) msg;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
attr = nlmsg_find_attr(hdr, sizeof(d), DCB_ATTR_IEEE);
|
|
Packit |
597cd4 |
if (!attr) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: nlmsg_find_attr failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
*app = malloc(sizeof(struct app_prio));
|
|
Packit |
597cd4 |
if (*app == NULL) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
*ets = malloc(sizeof(struct ieee_ets));
|
|
Packit |
597cd4 |
if (*ets == NULL) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
free(*app);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
*pfc = malloc(sizeof(struct ieee_pfc));
|
|
Packit |
597cd4 |
if (*pfc == NULL) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
free(*app);
|
|
Packit |
597cd4 |
free(*ets);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(*pfc, 0, sizeof(struct ieee_pfc));
|
|
Packit |
597cd4 |
memset(*ets, 0, sizeof(struct ieee_ets));
|
|
Packit |
597cd4 |
memset(*app, 0, sizeof(struct app_prio));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nla_for_each_nested(nattr, attr, rem) {
|
|
Packit |
597cd4 |
if (nla_type(nattr) == DCB_ATTR_IEEE_APP_TABLE) {
|
|
Packit |
597cd4 |
struct app_prio *this_app = *app;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nla_for_each_nested(app_attr, nattr, rem) {
|
|
Packit |
597cd4 |
struct dcb_app *data = nla_data(app_attr);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
LLDPAD_DBG("app %i %i %i\n",
|
|
Packit |
597cd4 |
data->selector,
|
|
Packit |
597cd4 |
data->protocol,
|
|
Packit |
597cd4 |
data->priority);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
this_app = realloc(this_app,
|
|
Packit |
597cd4 |
sizeof(struct app_prio) * itr +
|
|
Packit |
597cd4 |
sizeof(struct app_prio));
|
|
Packit |
597cd4 |
if (!this_app) {
|
|
Packit |
597cd4 |
free(this_app);
|
|
Packit |
597cd4 |
free(*ets);
|
|
Packit |
597cd4 |
free(*pfc);
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: realloc failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
this_app[itr].prs =
|
|
Packit |
597cd4 |
(data->priority << 5) | data->selector;
|
|
Packit |
597cd4 |
this_app[itr].pid = htons(data->protocol);
|
|
Packit |
597cd4 |
itr++;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* realloc may have moved app so reset it */
|
|
Packit |
597cd4 |
*app = this_app;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (nla_type(nattr) == DCB_ATTR_IEEE_ETS) {
|
|
Packit |
597cd4 |
struct ieee_ets *nl_ets = nla_data(nattr);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memcpy(*ets, nl_ets, sizeof(struct ieee_ets));
|
|
Packit |
597cd4 |
#ifdef LLDPAD_8021QAZ_DEBUG
|
|
Packit |
597cd4 |
print_ets(nl_ets);
|
|
Packit |
597cd4 |
#endif
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (nla_type(nattr) == DCB_ATTR_IEEE_PFC) {
|
|
Packit |
597cd4 |
struct ieee_pfc *nl_pfc = nla_data(nattr);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memcpy(*pfc, nl_pfc, sizeof(struct ieee_pfc));
|
|
Packit |
597cd4 |
#ifdef LLDPAD_8021QAZ_DEBUG
|
|
Packit |
597cd4 |
print_pfc(nl_pfc);
|
|
Packit |
597cd4 |
#endif
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
out:
|
|
Packit |
597cd4 |
nlmsg_free(nlm);
|
|
Packit |
597cd4 |
free(msg);
|
|
Packit |
597cd4 |
nl_close(nlsocket);
|
|
Packit |
597cd4 |
nl_socket_free(nlsocket);
|
|
Packit |
597cd4 |
out1:
|
|
Packit |
597cd4 |
*cnt = itr;
|
|
Packit |
597cd4 |
return err;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static int del_ieee_hw(const char *ifname, struct dcb_app *app_data)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int err = 0;
|
|
Packit |
597cd4 |
struct nlattr *ieee, *app;
|
|
Packit |
597cd4 |
struct sockaddr_nl dest_addr;
|
|
Packit |
597cd4 |
struct nl_sock *nlsocket;
|
|
Packit |
597cd4 |
struct nl_msg *nlm;
|
|
Packit |
597cd4 |
struct dcbmsg d = {
|
|
Packit |
597cd4 |
.dcb_family = AF_UNSPEC,
|
|
Packit |
597cd4 |
.cmd = DCB_CMD_IEEE_DEL,
|
|
Packit |
597cd4 |
.dcb_pad = 0
|
|
Packit |
597cd4 |
};
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nlsocket = nl_socket_alloc();
|
|
Packit |
597cd4 |
if (!nlsocket) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
return -ENOMEM;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
nl_socket_set_local_port(nlsocket, 0);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nl_connect(nlsocket, NETLINK_ROUTE);
|
|
Packit |
597cd4 |
if (err < 0) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s nlconnect failed abort hardware set, %s\n",
|
|
Packit |
597cd4 |
__func__, ifname, nl_geterror(err));
|
|
Packit |
597cd4 |
err = -EIO;
|
|
Packit |
597cd4 |
goto out1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nlm = nlmsg_alloc_simple(RTM_SETDCB, NLM_F_REQUEST);
|
|
Packit |
597cd4 |
if (!nlm) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out2;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(&dest_addr, 0, sizeof(dest_addr));
|
|
Packit |
597cd4 |
dest_addr.nl_family = AF_NETLINK;
|
|
Packit |
597cd4 |
nlmsg_set_dst(nlm, &dest_addr);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nlmsg_append(nlm, &d, sizeof(d), NLMSG_ALIGNTO);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nla_put(nlm, DCB_ATTR_IFNAME, strlen(ifname)+1, ifname);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ieee = nla_nest_start(nlm, DCB_ATTR_IEEE);
|
|
Packit |
597cd4 |
if (!ieee) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
if (app_data) {
|
|
Packit |
597cd4 |
app = nla_nest_start(nlm, DCB_ATTR_IEEE_APP_TABLE);
|
|
Packit |
597cd4 |
if (!app) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nla_put(nlm, DCB_ATTR_IEEE_APP,
|
|
Packit |
597cd4 |
sizeof(*app_data), app_data);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
nla_nest_end(nlm, app);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
nla_nest_end(nlm, ieee);
|
|
Packit |
597cd4 |
err = nl_send_auto_complete(nlsocket, nlm);
|
|
Packit |
597cd4 |
if (err <= 0)
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s 802.1Qaz set attributes failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
out:
|
|
Packit |
597cd4 |
nlmsg_free(nlm);
|
|
Packit |
597cd4 |
out2:
|
|
Packit |
597cd4 |
nl_close(nlsocket);
|
|
Packit |
597cd4 |
nl_socket_free(nlsocket);
|
|
Packit |
597cd4 |
out1:
|
|
Packit |
597cd4 |
return err;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data,
|
|
Packit |
597cd4 |
struct ieee_pfc *pfc_data, struct dcb_app *app_data)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int err = 0;
|
|
Packit |
597cd4 |
struct nlattr *ieee, *app;
|
|
Packit |
597cd4 |
struct sockaddr_nl dest_addr;
|
|
Packit |
597cd4 |
struct nl_sock *nlsocket;
|
|
Packit |
597cd4 |
struct nl_msg *nlm;
|
|
Packit |
597cd4 |
struct dcbmsg d = {
|
|
Packit |
597cd4 |
.dcb_family = AF_UNSPEC,
|
|
Packit |
597cd4 |
.cmd = DCB_CMD_IEEE_SET,
|
|
Packit |
597cd4 |
.dcb_pad = 0
|
|
Packit |
597cd4 |
};
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nlsocket = nl_socket_alloc();
|
|
Packit |
597cd4 |
if (!nlsocket) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
return -ENOMEM;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
nl_socket_set_local_port(nlsocket, 0);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!ets_data && !pfc_data && !app_data) {
|
|
Packit |
597cd4 |
err = 0;
|
|
Packit |
597cd4 |
goto out1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
#ifdef LLDPAD_8021QAZ_DEBUG
|
|
Packit |
597cd4 |
if (ets_data)
|
|
Packit |
597cd4 |
print_ets(ets_data);
|
|
Packit |
597cd4 |
if (pfc_data)
|
|
Packit |
597cd4 |
print_pfc(pfc_data);
|
|
Packit |
597cd4 |
#endif
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nl_connect(nlsocket, NETLINK_ROUTE);
|
|
Packit |
597cd4 |
if (err < 0) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s nlconnect failed abort hardware set, %s\n",
|
|
Packit |
597cd4 |
__func__, ifname, nl_geterror(err));
|
|
Packit |
597cd4 |
err = -EIO;
|
|
Packit |
597cd4 |
goto out1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
nlm = nlmsg_alloc_simple(RTM_SETDCB, NLM_F_REQUEST);
|
|
Packit |
597cd4 |
if (!nlm) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out2;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(&dest_addr, 0, sizeof(dest_addr));
|
|
Packit |
597cd4 |
dest_addr.nl_family = AF_NETLINK;
|
|
Packit |
597cd4 |
nlmsg_set_dst(nlm, &dest_addr);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nlmsg_append(nlm, &d, sizeof(d), NLMSG_ALIGNTO);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nla_put(nlm, DCB_ATTR_IFNAME, strlen(ifname)+1, ifname);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ieee = nla_nest_start(nlm, DCB_ATTR_IEEE);
|
|
Packit |
597cd4 |
if (!ieee) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (ets_data) {
|
|
Packit |
597cd4 |
err = nla_put(nlm, DCB_ATTR_IEEE_ETS,
|
|
Packit |
597cd4 |
sizeof(*ets_data), ets_data);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (pfc_data) {
|
|
Packit |
597cd4 |
err = nla_put(nlm, DCB_ATTR_IEEE_PFC,
|
|
Packit |
597cd4 |
sizeof(*pfc_data), pfc_data);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
if (app_data) {
|
|
Packit |
597cd4 |
app = nla_nest_start(nlm, DCB_ATTR_IEEE_APP_TABLE);
|
|
Packit |
597cd4 |
if (!app) {
|
|
Packit |
597cd4 |
err = -ENOMEM;
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = nla_put(nlm, DCB_ATTR_IEEE_APP,
|
|
Packit |
597cd4 |
sizeof(*app_data), app_data);
|
|
Packit |
597cd4 |
if (err < 0)
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
nla_nest_end(nlm, app);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
nla_nest_end(nlm, ieee);
|
|
Packit |
597cd4 |
err = nl_send_auto_complete(nlsocket, nlm);
|
|
Packit |
597cd4 |
if (err <= 0)
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s 802.1Qaz set attributes failed\n",
|
|
Packit |
597cd4 |
__func__, ifname);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
out:
|
|
Packit |
597cd4 |
nlmsg_free(nlm);
|
|
Packit |
597cd4 |
out2:
|
|
Packit |
597cd4 |
nl_close(nlsocket);
|
|
Packit |
597cd4 |
nl_socket_free(nlsocket);
|
|
Packit |
597cd4 |
out1:
|
|
Packit |
597cd4 |
return err;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void ets_cfg_to_ieee(struct ieee_ets *ieee, struct etscfg_obj *cfg)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int i;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memcpy(ieee->tc_tx_bw, cfg->tc_bw, MAX_TCS);
|
|
Packit |
597cd4 |
memcpy(ieee->tc_rx_bw, cfg->tc_bw, MAX_TCS);
|
|
Packit |
597cd4 |
memcpy(ieee->tc_tsa, cfg->tsa_map, MAX_TCS);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_USER_PRIORITIES; i++)
|
|
Packit |
597cd4 |
ieee->prio_tc[i] = get_prio_map(cfg->prio_map, i);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memcpy(ieee->tc_reco_bw, cfg->tc_bw, MAX_TCS);
|
|
Packit |
597cd4 |
memcpy(ieee->tc_reco_tsa, cfg->tsa_map, MAX_TCS);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_USER_PRIORITIES; i++)
|
|
Packit |
597cd4 |
ieee->reco_prio_tc[i] = get_prio_map(cfg->prio_map, i);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void ets_rec_to_ieee(struct ieee_ets *ieee, struct etsrec_obj *rec)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
int i;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memcpy(ieee->tc_tx_bw, rec->tc_bw, MAX_TCS);
|
|
Packit |
597cd4 |
memcpy(ieee->tc_rx_bw, rec->tc_bw, MAX_TCS);
|
|
Packit |
597cd4 |
memcpy(ieee->tc_tsa, rec->tsa_map, MAX_TCS);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++)
|
|
Packit |
597cd4 |
ieee->prio_tc[i] = get_prio_map(rec->prio_map, i);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memcpy(ieee->tc_reco_bw, rec->tc_bw, MAX_TCS);
|
|
Packit |
597cd4 |
memcpy(ieee->tc_reco_tsa, rec->tsa_map, MAX_TCS);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++)
|
|
Packit |
597cd4 |
ieee->reco_prio_tc[i] = get_prio_map(rec->prio_map, i);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
void run_all_sm(struct port *port, struct lldp_agent *agent)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
struct ieee_ets *ets;
|
|
Packit |
597cd4 |
struct ieee_pfc *pfc;
|
|
Packit |
597cd4 |
struct pfc_obj *pfc_obj;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
if (!tlvs)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ets_sm(tlvs->ets->cfgl, tlvs->ets->recr, &tlvs->ets->current_state);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ets = malloc(sizeof(*ets));
|
|
Packit |
597cd4 |
if (!ets) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: ets malloc failed\n",
|
|
Packit |
597cd4 |
__func__, port->ifname);
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(ets, 0, sizeof(*ets));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->ets->current_state == RX_RECOMMEND)
|
|
Packit |
597cd4 |
ets_rec_to_ieee(ets, tlvs->ets->recr);
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
ets_cfg_to_ieee(ets, tlvs->ets->cfgl);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
pfc_sm(tlvs);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->pfc->current_state == RX_RECOMMEND)
|
|
Packit |
597cd4 |
pfc_obj = &tlvs->pfc->remote;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
pfc_obj = &tlvs->pfc->local;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
pfc = malloc(sizeof(*pfc));
|
|
Packit |
597cd4 |
if (!pfc) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: pfc malloc failed\n",
|
|
Packit |
597cd4 |
__func__, port->ifname);
|
|
Packit |
597cd4 |
goto out;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(pfc, 0, sizeof(*pfc));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
pfc->pfc_en = pfc_obj->pfc_enable;
|
|
Packit |
597cd4 |
pfc->mbc = pfc_obj->mbc;
|
|
Packit |
597cd4 |
pfc->delay = pfc_obj->delay;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (ieee8021qaz_check_active(port->ifname)) {
|
|
Packit |
597cd4 |
set_dcbx_mode(port->ifname,
|
|
Packit |
597cd4 |
DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_HOST);
|
|
Packit |
597cd4 |
set_ieee_hw(port->ifname, ets, pfc, NULL);
|
|
Packit |
597cd4 |
ieee8021qaz_app_sethw(port->ifname, &tlvs->app_head);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
out:
|
|
Packit |
597cd4 |
free(pfc);
|
|
Packit |
597cd4 |
free(ets);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* bld_ieee8021qaz_etscfg_tlv - builds the ETS Configuration TLV
|
|
Packit |
597cd4 |
* Returns 1 on success, NULL if the TLV fail to build correctly.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
static struct unpacked_tlv *
|
|
Packit |
597cd4 |
bld_ieee8021qaz_etscfg_tlv(struct ieee8021qaz_tlvs *tlvs)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlv_etscfg *etscfg;
|
|
Packit |
597cd4 |
struct unpacked_tlv *tlv = create_tlv();
|
|
Packit |
597cd4 |
int i = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!tlv)
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
etscfg = (struct ieee8021qaz_tlv_etscfg *)malloc(sizeof(*etscfg));
|
|
Packit |
597cd4 |
if (!etscfg) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: Failed to malloc etscfg\n", __func__);
|
|
Packit |
597cd4 |
free(tlv);
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
memset(etscfg, 0, sizeof(*etscfg));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
hton24(etscfg->oui, OUI_IEEE_8021);
|
|
Packit |
597cd4 |
etscfg->subtype = LLDP_8021QAZ_ETSCFG;
|
|
Packit |
597cd4 |
etscfg->wcrt = tlvs->ets->cfgl->willing << 7 |
|
|
Packit |
597cd4 |
tlvs->ets->cfgl->cbs << 6 |
|
|
Packit |
597cd4 |
(tlvs->ets->cfgl->max_tcs & 0x7);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->ets->current_state == INIT) {
|
|
Packit |
597cd4 |
etscfg->prio_map = htonl(tlvs->ets->cfgl->prio_map);
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++) {
|
|
Packit |
597cd4 |
etscfg->tc_bw[i] = tlvs->ets->cfgl->tc_bw[i];
|
|
Packit |
597cd4 |
etscfg->tsa_map[i] = tlvs->ets->cfgl->tsa_map[i];
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
etscfg->prio_map = htonl(tlvs->ets->recr->prio_map);
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++) {
|
|
Packit |
597cd4 |
etscfg->tc_bw[i] = tlvs->ets->recr->tc_bw[i];
|
|
Packit |
597cd4 |
etscfg->tsa_map[i] = tlvs->ets->recr->tsa_map[i];
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlv->type = ORG_SPECIFIC_TLV;
|
|
Packit |
597cd4 |
tlv->length = sizeof(struct ieee8021qaz_tlv_etscfg);
|
|
Packit |
597cd4 |
tlv->info = (u8 *)etscfg;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (OUI_SUB_SIZE > tlv->length)
|
|
Packit |
597cd4 |
goto error;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return tlv;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
error:
|
|
Packit |
597cd4 |
if (tlv) {
|
|
Packit |
597cd4 |
if (tlv->info)
|
|
Packit |
597cd4 |
free(tlv->info);
|
|
Packit |
597cd4 |
free(tlv);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: Failed\n", __func__);
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* bld_ieee8021qaz_etsrec_tlv - builds the ETS Recommendation TLV
|
|
Packit |
597cd4 |
* Returns 1 on success, NULL if the TLV fail to build correctly.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
struct unpacked_tlv *
|
|
Packit |
597cd4 |
bld_ieee8021qaz_etsrec_tlv(struct ieee8021qaz_tlvs *tlvs)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlv_etsrec *etsrec;
|
|
Packit |
597cd4 |
struct unpacked_tlv *tlv = create_tlv();
|
|
Packit |
597cd4 |
int i = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!tlv)
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
etsrec = (struct ieee8021qaz_tlv_etsrec *)malloc(sizeof(*etsrec));
|
|
Packit |
597cd4 |
if (!etsrec) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: Failed to malloc etscfg\n", __func__);
|
|
Packit |
597cd4 |
free(tlv);
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
memset(etsrec, 0, sizeof(*etsrec));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
hton24(etsrec->oui, OUI_IEEE_8021);
|
|
Packit |
597cd4 |
etsrec->subtype = LLDP_8021QAZ_ETSREC;
|
|
Packit |
597cd4 |
etsrec->prio_map = htonl(tlvs->ets->recl->prio_map);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++) {
|
|
Packit |
597cd4 |
etsrec->tc_bw[i] = tlvs->ets->recl->tc_bw[i];
|
|
Packit |
597cd4 |
etsrec->tsa_map[i] = tlvs->ets->recl->tsa_map[i];
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlv->type = ORG_SPECIFIC_TLV;
|
|
Packit |
597cd4 |
tlv->length = sizeof(struct ieee8021qaz_tlv_etsrec);
|
|
Packit |
597cd4 |
tlv->info = (u8 *)etsrec;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (OUI_SUB_SIZE > tlv->length)
|
|
Packit |
597cd4 |
goto error;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return tlv;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
error:
|
|
Packit |
597cd4 |
if (tlv) {
|
|
Packit |
597cd4 |
if (tlv->info)
|
|
Packit |
597cd4 |
free(tlv->info);
|
|
Packit |
597cd4 |
free(tlv);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: Failed\n", __func__);
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* bld_ieee8021qaz_pfc_tlv - builds the PFC Control Configuration TLV
|
|
Packit |
597cd4 |
* Returns unpacket tlv or NULL if the TLV fails to build correctly.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
static struct unpacked_tlv *
|
|
Packit |
597cd4 |
bld_ieee8021qaz_pfc_tlv(struct ieee8021qaz_tlvs *tlvs)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlv_pfc *pfc;
|
|
Packit |
597cd4 |
struct unpacked_tlv *tlv = create_tlv();
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!tlv)
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
pfc = (struct ieee8021qaz_tlv_pfc *)malloc(sizeof(*pfc));
|
|
Packit |
597cd4 |
if (!pfc) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: Failed to malloc pfc\n", __func__);
|
|
Packit |
597cd4 |
free(tlv);
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(pfc, 0, sizeof(*pfc));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
hton24(pfc->oui, OUI_IEEE_8021);
|
|
Packit |
597cd4 |
pfc->subtype = LLDP_8021QAZ_PFC;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
pfc->wmrc = tlvs->pfc->local.willing << 7 |
|
|
Packit |
597cd4 |
tlvs->pfc->local.mbc << 6 |
|
|
Packit |
597cd4 |
tlvs->pfc->local.pfc_cap;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->pfc->current_state == INIT)
|
|
Packit |
597cd4 |
pfc->pfc_enable = tlvs->pfc->local.pfc_enable;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
pfc->pfc_enable = tlvs->pfc->remote.pfc_enable;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlv->type = ORG_SPECIFIC_TLV;
|
|
Packit |
597cd4 |
tlv->length = sizeof(struct ieee8021qaz_tlv_pfc);
|
|
Packit |
597cd4 |
tlv->info = (u8 *)pfc;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (OUI_SUB_SIZE > tlv->length)
|
|
Packit |
597cd4 |
goto error;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return tlv;
|
|
Packit |
597cd4 |
error:
|
|
Packit |
597cd4 |
if (tlv) {
|
|
Packit |
597cd4 |
if (tlv->info)
|
|
Packit |
597cd4 |
free(tlv->info);
|
|
Packit |
597cd4 |
free(tlv);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: Failed\n", __func__);
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* bld_ieee8021qaz_app_tlv - builds the APP TLV
|
|
Packit |
597cd4 |
* Returns unacked tlv or NULL if the TLV fails to build correctly.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
static struct unpacked_tlv *
|
|
Packit |
597cd4 |
bld_ieee8021qaz_app_tlv(char *ifname)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlv_app *app = NULL;
|
|
Packit |
597cd4 |
struct unpacked_tlv *tlv;
|
|
Packit |
597cd4 |
struct ieee_ets *ets = NULL;
|
|
Packit |
597cd4 |
struct ieee_pfc *pfc = NULL;
|
|
Packit |
597cd4 |
struct app_prio *data = NULL;
|
|
Packit |
597cd4 |
__u8 *ptr;
|
|
Packit |
597cd4 |
int cnt, err;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlv = create_tlv();
|
|
Packit |
597cd4 |
if (!tlv)
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
err = get_ieee_hw(ifname, &ets, &pfc, &data, &cnt);
|
|
Packit |
597cd4 |
if (!err) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: get_ieee_hw failed\n", __func__, ifname);
|
|
Packit |
597cd4 |
goto error;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
app = malloc(sizeof(*app) + (sizeof(*data) * cnt));
|
|
Packit |
597cd4 |
if (!app) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: Failed to malloc app\n", __func__);
|
|
Packit |
597cd4 |
goto error;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
memset(app, 0, sizeof(*app));
|
|
Packit |
597cd4 |
hton24(app->oui, OUI_IEEE_8021);
|
|
Packit |
597cd4 |
app->subtype = LLDP_8021QAZ_APP;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ptr = (u8 *) app + sizeof(*app);
|
|
Packit |
597cd4 |
memcpy(ptr, data, sizeof(*data) * cnt);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlv->type = ORG_SPECIFIC_TLV;
|
|
Packit |
597cd4 |
tlv->length = sizeof(struct ieee8021qaz_tlv_app) + (cnt * 3);
|
|
Packit |
597cd4 |
tlv->info = (u8 *)app;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (OUI_SUB_SIZE > tlv->length) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: tlv->length = %d, cnt=%d\n", __func__,
|
|
Packit |
597cd4 |
ifname, tlv->length, cnt);
|
|
Packit |
597cd4 |
goto error;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
free(ets);
|
|
Packit |
597cd4 |
free(pfc);
|
|
Packit |
597cd4 |
free(data);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return tlv;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
error:
|
|
Packit |
597cd4 |
free(tlv);
|
|
Packit |
597cd4 |
free(ets);
|
|
Packit |
597cd4 |
free(pfc);
|
|
Packit |
597cd4 |
free(app);
|
|
Packit |
597cd4 |
free(data);
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: Failed\n", __func__);
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* ieee8021qaz_bld_tlv - builds all IEEE8021QAZ TLVs
|
|
Packit |
597cd4 |
* Returns 1 on success, NULL if any of the TLVs fail to build correctly.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
static struct packed_tlv *ieee8021qaz_bld_tlv(struct port *port,
|
|
Packit |
597cd4 |
struct lldp_agent *agent)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *data;
|
|
Packit |
597cd4 |
struct packed_tlv *ptlv = NULL;
|
|
Packit |
597cd4 |
struct unpacked_tlv *etscfg_tlv, *etsrec_tlv, *pfc_tlv, *app_tlv;
|
|
Packit |
597cd4 |
size_t size;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
data = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
if (!data)
|
|
Packit |
597cd4 |
return ptlv;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
etscfg_tlv = etsrec_tlv = pfc_tlv = app_tlv = NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!data->active)
|
|
Packit |
597cd4 |
return ptlv;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!is_tlv_txdisabled(port->ifname, agent->type, TLVID_8021(LLDP_8021QAZ_ETSCFG)))
|
|
Packit |
597cd4 |
etscfg_tlv = bld_ieee8021qaz_etscfg_tlv(data);
|
|
Packit |
597cd4 |
if (is_tlv_txenabled(port->ifname, agent->type, TLVID_8021(LLDP_8021QAZ_ETSREC)))
|
|
Packit |
597cd4 |
etsrec_tlv = bld_ieee8021qaz_etsrec_tlv(data);
|
|
Packit |
597cd4 |
if (!is_tlv_txdisabled(port->ifname, agent->type, TLVID_8021(LLDP_8021QAZ_PFC)))
|
|
Packit |
597cd4 |
pfc_tlv = bld_ieee8021qaz_pfc_tlv(data);
|
|
Packit |
597cd4 |
if (is_tlv_txenabled(port->ifname, agent->type, TLVID_8021(LLDP_8021QAZ_APP)))
|
|
Packit |
597cd4 |
app_tlv = bld_ieee8021qaz_app_tlv(port->ifname);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
size = TLVSIZE(etscfg_tlv)
|
|
Packit |
597cd4 |
+ TLVSIZE(etsrec_tlv)
|
|
Packit |
597cd4 |
+ TLVSIZE(pfc_tlv)
|
|
Packit |
597cd4 |
+ TLVSIZE(app_tlv);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ptlv = create_ptlv();
|
|
Packit |
597cd4 |
if (!ptlv)
|
|
Packit |
597cd4 |
goto err;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ptlv->tlv = malloc(size);
|
|
Packit |
597cd4 |
if (!ptlv->tlv)
|
|
Packit |
597cd4 |
goto err;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ptlv->size = 0;
|
|
Packit |
597cd4 |
PACK_TLV_AFTER(etscfg_tlv, ptlv, size, err);
|
|
Packit |
597cd4 |
PACK_TLV_AFTER(etsrec_tlv, ptlv, size, err);
|
|
Packit |
597cd4 |
PACK_TLV_AFTER(pfc_tlv, ptlv, size, err);
|
|
Packit |
597cd4 |
PACK_TLV_AFTER(app_tlv, ptlv, size, err);
|
|
Packit |
597cd4 |
err:
|
|
Packit |
597cd4 |
free_unpkd_tlv(etscfg_tlv);
|
|
Packit |
597cd4 |
free_unpkd_tlv(etsrec_tlv);
|
|
Packit |
597cd4 |
free_unpkd_tlv(pfc_tlv);
|
|
Packit |
597cd4 |
free_unpkd_tlv(app_tlv);
|
|
Packit |
597cd4 |
return ptlv;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* LLDP_8021QAZ_MOD_OPS - GETTLV */
|
|
Packit |
597cd4 |
struct packed_tlv *ieee8021qaz_gettlv(struct port *port,
|
|
Packit |
597cd4 |
struct lldp_agent *agent)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct packed_tlv *ptlv = NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Update TLV State Machines */
|
|
Packit |
597cd4 |
run_all_sm(port, agent);
|
|
Packit |
597cd4 |
/* Build TLVs */
|
|
Packit |
597cd4 |
ptlv = ieee8021qaz_bld_tlv(port, agent);
|
|
Packit |
597cd4 |
return ptlv;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static bool unpack_ieee8021qaz_tlvs(struct port *port,
|
|
Packit |
597cd4 |
struct lldp_agent *agent,
|
|
Packit |
597cd4 |
struct unpacked_tlv *tlv)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
/* Unpack tlvs and store in rx */
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE) {
|
|
Packit |
597cd4 |
LLDPAD_INFO("%s: %s: ignoring tlv from remote bridge\n",
|
|
Packit |
597cd4 |
__func__, port->ifname);
|
|
Packit |
597cd4 |
return false;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Process */
|
|
Packit |
597cd4 |
switch (tlv->info[OUI_SIZE]) {
|
|
Packit |
597cd4 |
case IEEE8021QAZ_ETSCFG_TLV:
|
|
Packit |
597cd4 |
if (tlvs->rx->etscfg == NULL) {
|
|
Packit |
597cd4 |
tlvs->ieee8021qazdu |= RCVD_IEEE8021QAZ_TLV_ETSCFG;
|
|
Packit |
597cd4 |
tlvs->rx->etscfg = tlv;
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: 802.1Qaz Duplicate ETSCFG TLV\n",
|
|
Packit |
597cd4 |
__func__, port->ifname);
|
|
Packit |
597cd4 |
agent->rx.dupTlvs |= DUP_IEEE8021QAZ_TLV_ETSCFG;
|
|
Packit |
597cd4 |
return false;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
case IEEE8021QAZ_ETSREC_TLV:
|
|
Packit |
597cd4 |
if (tlvs->rx->etsrec == NULL) {
|
|
Packit |
597cd4 |
tlvs->ieee8021qazdu |= RCVD_IEEE8021QAZ_TLV_ETSREC;
|
|
Packit |
597cd4 |
tlvs->rx->etsrec = tlv;
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: 802.1Qaz Duplicate ETSREC TLV\n",
|
|
Packit |
597cd4 |
__func__, port->ifname);
|
|
Packit |
597cd4 |
agent->rx.dupTlvs |= DUP_IEEE8021QAZ_TLV_ETSREC;
|
|
Packit |
597cd4 |
return false;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
case IEEE8021QAZ_PFC_TLV:
|
|
Packit |
597cd4 |
if (tlvs->rx->pfc == NULL) {
|
|
Packit |
597cd4 |
tlvs->ieee8021qazdu |= RCVD_IEEE8021QAZ_TLV_PFC;
|
|
Packit |
597cd4 |
tlvs->rx->pfc = tlv;
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: 802.1Qaz Duplicate PFC TLV\n",
|
|
Packit |
597cd4 |
__func__, port->ifname);
|
|
Packit |
597cd4 |
agent->rx.dupTlvs |= DUP_IEEE8021QAZ_TLV_PFC;
|
|
Packit |
597cd4 |
return false;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
case IEEE8021QAZ_APP_TLV:
|
|
Packit |
597cd4 |
if (tlvs->rx->app == NULL) {
|
|
Packit |
597cd4 |
tlvs->ieee8021qazdu |= RCVD_IEEE8021QAZ_TLV_APP;
|
|
Packit |
597cd4 |
tlvs->rx->app = tlv;
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: 802.1Qaz Duplicate APP TLV\n",
|
|
Packit |
597cd4 |
__func__, port->ifname);
|
|
Packit |
597cd4 |
agent->rx.dupTlvs |= DUP_IEEE8021QAZ_TLV_APP;
|
|
Packit |
597cd4 |
return false;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
default:
|
|
Packit |
597cd4 |
LLDPAD_INFO("%s: %s: Unknown TLV 0x%04x\n", __func__,
|
|
Packit |
597cd4 |
port->ifname, tlv->info[OUI_SIZE]);
|
|
Packit |
597cd4 |
return false;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
return true;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void clear_ieee8021qaz_rx(struct ieee8021qaz_tlvs *tlvs)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
if (!tlvs)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!tlvs->rx)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->rx->ieee8021qaz)
|
|
Packit |
597cd4 |
tlvs->rx->ieee8021qaz = free_unpkd_tlv(tlvs->rx->ieee8021qaz);
|
|
Packit |
597cd4 |
if (tlvs->rx->etscfg)
|
|
Packit |
597cd4 |
tlvs->rx->etscfg = free_unpkd_tlv(tlvs->rx->etscfg);
|
|
Packit |
597cd4 |
if (tlvs->rx->etsrec)
|
|
Packit |
597cd4 |
tlvs->rx->etsrec = free_unpkd_tlv(tlvs->rx->etsrec);
|
|
Packit |
597cd4 |
if (tlvs->rx->pfc)
|
|
Packit |
597cd4 |
tlvs->rx->pfc = free_unpkd_tlv(tlvs->rx->pfc);
|
|
Packit |
597cd4 |
if (tlvs->rx->app)
|
|
Packit |
597cd4 |
tlvs->rx->app = free_unpkd_tlv(tlvs->rx->app);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
free(tlvs->rx);
|
|
Packit |
597cd4 |
tlvs->rx = NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void process_ieee8021qaz_etscfg_tlv(struct port *port)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
u8 offset = 0;
|
|
Packit |
597cd4 |
int i = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
offset = OUI_SUB_SIZE;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->ets->cfgr)
|
|
Packit |
597cd4 |
free(tlvs->ets->cfgr);
|
|
Packit |
597cd4 |
tlvs->ets->cfgr = malloc(sizeof(*tlvs->ets->cfgr));
|
|
Packit |
597cd4 |
if (!tlvs->ets->cfgr) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: %s: cfgr malloc failed\n",
|
|
Packit |
597cd4 |
__func__, port->ifname);
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->rx->etscfg->info[offset] & BIT7)
|
|
Packit |
597cd4 |
tlvs->ets->cfgr->willing = true;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->ets->cfgr->willing = false;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->rx->etscfg->info[offset] & BIT6)
|
|
Packit |
597cd4 |
tlvs->ets->cfgr->cbs = true;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->ets->cfgr->cbs = false;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->ets->cfgr->max_tcs = tlvs->rx->etscfg->info[offset] & 0x07;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*Moving offset to PRIO_MAP */
|
|
Packit |
597cd4 |
offset += 1;
|
|
Packit |
597cd4 |
tlvs->ets->cfgr->prio_map = 0;
|
|
Packit |
597cd4 |
for (i = 0; i < 4; i++) {
|
|
Packit |
597cd4 |
u8 temp1 = 0, temp2 = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
temp1 = (tlvs->rx->etscfg->info[offset] >> 4) & 0x0F;
|
|
Packit |
597cd4 |
temp2 = tlvs->rx->etscfg->info[offset] & 0x0F;
|
|
Packit |
597cd4 |
set_prio_map(&tlvs->ets->cfgr->prio_map, (2*i), temp1);
|
|
Packit |
597cd4 |
set_prio_map(&tlvs->ets->cfgr->prio_map, ((2*i)+1), temp2);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
offset += 1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++) {
|
|
Packit |
597cd4 |
tlvs->ets->cfgr->tc_bw[i] = tlvs->rx->etscfg->info[offset];
|
|
Packit |
597cd4 |
offset += 1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++) {
|
|
Packit |
597cd4 |
tlvs->ets->cfgr->tsa_map[i] = tlvs->rx->etscfg->info[offset];
|
|
Packit |
597cd4 |
offset += 1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void process_ieee8021qaz_etsrec_tlv(struct port *port)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
u8 offset = 0;
|
|
Packit |
597cd4 |
int i = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Bypassing OUI, SUBTYPE fields */
|
|
Packit |
597cd4 |
offset = OUI_SUB_SIZE + 1;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->ets->recr)
|
|
Packit |
597cd4 |
memset(tlvs->ets->recr, 0, sizeof(*tlvs->ets->recr));
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->ets->recr = malloc(sizeof(*tlvs->ets->recr));
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!tlvs->ets->recr)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->ets->recr->prio_map = 0;
|
|
Packit |
597cd4 |
for (i = 0; i < 4; i++) {
|
|
Packit |
597cd4 |
u8 temp1 = 0, temp2 = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
temp1 = (tlvs->rx->etsrec->info[offset] >> 4) & 0x0F;
|
|
Packit |
597cd4 |
temp2 = tlvs->rx->etsrec->info[offset] & 0x0F;
|
|
Packit |
597cd4 |
set_prio_map(&tlvs->ets->recr->prio_map, (2*i), temp1);
|
|
Packit |
597cd4 |
set_prio_map(&tlvs->ets->recr->prio_map, ((2*i)+1), temp2);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
offset += 1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++) {
|
|
Packit |
597cd4 |
tlvs->ets->recr->tc_bw[i] = tlvs->rx->etsrec->info[offset];
|
|
Packit |
597cd4 |
offset += 1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
for (i = 0; i < MAX_TCS; i++) {
|
|
Packit |
597cd4 |
tlvs->ets->recr->tsa_map[i] = tlvs->rx->etsrec->info[offset];
|
|
Packit |
597cd4 |
offset += 1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void process_ieee8021qaz_pfc_tlv(struct port *port)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
u8 offset = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Bypassing OUI, SUBTYPE fields */
|
|
Packit |
597cd4 |
offset = OUI_SUB_SIZE;
|
|
Packit |
597cd4 |
if (tlvs->rx->pfc->info[offset] & BIT7)
|
|
Packit |
597cd4 |
tlvs->pfc->remote.willing = true;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->pfc->remote.willing = false;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->rx->pfc->info[offset] & BIT6)
|
|
Packit |
597cd4 |
tlvs->pfc->remote.mbc = true;
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
tlvs->pfc->remote.mbc = false;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->pfc->remote.pfc_cap = tlvs->rx->pfc->info[offset] & 0x0F;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
offset += 1;
|
|
Packit |
597cd4 |
tlvs->pfc->remote.pfc_enable = tlvs->rx->pfc->info[offset];
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs->pfc->remote_param = true;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
int ieee8021qaz_mod_app(struct app_tlv_head *head, int peer,
|
|
Packit |
597cd4 |
u8 prio, u8 sel, u16 proto, u32 ops)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct app_obj *np;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Search list for existing match and abort
|
|
Packit |
597cd4 |
* Mark entry for deletion if delete option supplied
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
LIST_FOREACH(np, head, entry) {
|
|
Packit |
597cd4 |
if (np->app.selector == sel &&
|
|
Packit |
597cd4 |
np->app.protocol == proto &&
|
|
Packit |
597cd4 |
np->app.priority == prio) {
|
|
Packit |
597cd4 |
if (ops & op_delete)
|
|
Packit |
597cd4 |
np->hw = IEEE_APP_DEL;
|
|
Packit |
597cd4 |
return 1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (ops & op_delete)
|
|
Packit |
597cd4 |
return 1;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Add new entry for APP data */
|
|
Packit |
597cd4 |
np = calloc(1, sizeof(*np));
|
|
Packit |
597cd4 |
if (!np) {
|
|
Packit |
597cd4 |
LLDPAD_WARN("%s: memory alloc failure.\n", __func__);
|
|
Packit |
597cd4 |
return -1;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
np->peer = peer;
|
|
Packit |
597cd4 |
np->hw = IEEE_APP_SET;
|
|
Packit |
597cd4 |
np->app.priority = prio;
|
|
Packit |
597cd4 |
np->app.selector = sel;
|
|
Packit |
597cd4 |
np->app.protocol = proto;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
LIST_INSERT_HEAD(head, np, entry);
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void ieee8021qaz_app_reset(struct app_tlv_head *head)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct app_obj *np;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
LIST_FOREACH(np, head, entry) {
|
|
Packit |
597cd4 |
if (np->peer)
|
|
Packit |
597cd4 |
np->hw = IEEE_APP_DEL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static int __ieee8021qaz_app_sethw(char *ifname, struct app_tlv_head *head)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct app_obj *np, *np_tmp;
|
|
Packit |
597cd4 |
int set = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
LIST_FOREACH(np, head, entry) {
|
|
Packit |
597cd4 |
if (np->hw != IEEE_APP_SET)
|
|
Packit |
597cd4 |
continue;
|
|
Packit |
597cd4 |
set = set_ieee_hw(ifname, NULL, NULL, &np->app);
|
|
Packit |
597cd4 |
np->hw = IEEE_APP_DONE;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
np = LIST_FIRST(head);
|
|
Packit |
597cd4 |
while (np) {
|
|
Packit |
597cd4 |
if (np->hw == IEEE_APP_DEL) {
|
|
Packit |
597cd4 |
np_tmp = np;
|
|
Packit |
597cd4 |
np = LIST_NEXT(np, entry);
|
|
Packit |
597cd4 |
LIST_REMOVE(np_tmp, entry);
|
|
Packit |
597cd4 |
set = del_ieee_hw(ifname, &np_tmp->app);
|
|
Packit |
597cd4 |
free(np_tmp);
|
|
Packit |
597cd4 |
} else {
|
|
Packit |
597cd4 |
np = LIST_NEXT(np, entry);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
return set;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
int ieee8021qaz_app_sethw(char *ifname, struct app_tlv_head *head)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
if (ieee8021qaz_check_active(ifname)) {
|
|
Packit |
597cd4 |
set_dcbx_mode(ifname,
|
|
Packit |
597cd4 |
DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_HOST);
|
|
Packit |
597cd4 |
return __ieee8021qaz_app_sethw(ifname, head);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void process_ieee8021qaz_app_tlv(struct port *port)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
int offset = OUI_SUB_SIZE + 1;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* clear app priorities so old data is flushed */
|
|
Packit |
597cd4 |
ieee8021qaz_app_reset(&tlvs->app_head);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
while (offset < tlvs->rx->app->length) {
|
|
Packit |
597cd4 |
struct app_obj *np;
|
|
Packit |
597cd4 |
int set = 0;
|
|
Packit |
597cd4 |
u8 prio = (tlvs->rx->app->info[offset] & 0xE0) >> 5;
|
|
Packit |
597cd4 |
u8 sel = (tlvs->rx->app->info[offset] & 0x07);
|
|
Packit |
597cd4 |
u16 proto = (tlvs->rx->app->info[offset + 1] << 8) |
|
|
Packit |
597cd4 |
tlvs->rx->app->info[offset + 2];
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Search list for existing match and mark set */
|
|
Packit |
597cd4 |
LIST_FOREACH(np, &tlvs->app_head, entry) {
|
|
Packit |
597cd4 |
if (np->app.selector == sel &&
|
|
Packit |
597cd4 |
np->app.protocol == proto &&
|
|
Packit |
597cd4 |
np->app.priority == prio) {
|
|
Packit |
597cd4 |
np->hw = IEEE_APP_SET;
|
|
Packit |
597cd4 |
set = 1;
|
|
Packit |
597cd4 |
break;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* If APP data not found in LIST add APP entry */
|
|
Packit |
597cd4 |
if (!set)
|
|
Packit |
597cd4 |
ieee8021qaz_mod_app(&tlvs->app_head, 1,
|
|
Packit |
597cd4 |
prio, sel, proto, 0);
|
|
Packit |
597cd4 |
offset += 3;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void ieee8021qaz_mibUpdateObjects(struct port *port)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->rx->etscfg) {
|
|
Packit |
597cd4 |
process_ieee8021qaz_etscfg_tlv(port);
|
|
Packit |
597cd4 |
} else if (tlvs->ets->cfgr) {
|
|
Packit |
597cd4 |
free(tlvs->ets->cfgr);
|
|
Packit |
597cd4 |
tlvs->ets->cfgr = NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->rx->etsrec) {
|
|
Packit |
597cd4 |
process_ieee8021qaz_etsrec_tlv(port);
|
|
Packit |
597cd4 |
} else if (tlvs->ets->recr) {
|
|
Packit |
597cd4 |
free(tlvs->ets->recr);
|
|
Packit |
597cd4 |
tlvs->ets->recr = NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->rx->pfc)
|
|
Packit |
597cd4 |
process_ieee8021qaz_pfc_tlv(port);
|
|
Packit |
597cd4 |
else if (tlvs->pfc)
|
|
Packit |
597cd4 |
tlvs->pfc->remote_param = false;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->rx->app)
|
|
Packit |
597cd4 |
process_ieee8021qaz_app_tlv(port);
|
|
Packit |
597cd4 |
else
|
|
Packit |
597cd4 |
ieee8021qaz_app_reset(&tlvs->app_head);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* LLDP_8021_QAZ_MOD_OPS - RCHANGE
|
|
Packit |
597cd4 |
*
|
|
Packit |
597cd4 |
* TLVs not consumed on error otherwise it is either free'd or stored
|
|
Packit |
597cd4 |
* internally in the module.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
int ieee8021qaz_rchange(struct port *port, struct lldp_agent *agent,
|
|
Packit |
597cd4 |
struct unpacked_tlv *tlv)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
u8 oui[OUI_SIZE] = INIT_IEEE8021QAZ_OUI;
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *qaz_tlvs;
|
|
Packit |
597cd4 |
struct ieee8021qaz_unpkd_tlvs *rx;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
qaz_tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
if (!qaz_tlvs)
|
|
Packit |
597cd4 |
return SUBTYPE_INVALID;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* TYPE_1 mandatory and always before IEEE8021QAZ tlvs so
|
|
Packit |
597cd4 |
* we can use it to make the beginning of a IEEE8021QAZ PDU.
|
|
Packit |
597cd4 |
* Verifies that only a single IEEE8021QAZ tlv is present.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
if (tlv->type == TYPE_1) {
|
|
Packit |
597cd4 |
clear_ieee8021qaz_rx(qaz_tlvs);
|
|
Packit |
597cd4 |
rx = malloc(sizeof(*rx));
|
|
Packit |
597cd4 |
memset(rx, 0, sizeof(*rx));
|
|
Packit |
597cd4 |
qaz_tlvs->rx = rx;
|
|
Packit |
597cd4 |
qaz_tlvs->ieee8021qazdu = 0;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* TYPE_127 is for the Organizationally Specific TLVS
|
|
Packit |
597cd4 |
* More than 1 of this type is allowed.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
if (tlv->type == TYPE_127) {
|
|
Packit |
597cd4 |
if (tlv->length < (OUI_SUB_SIZE))
|
|
Packit |
597cd4 |
return TLV_ERR;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if ((memcmp(tlv->info, &oui, OUI_SIZE) != 0))
|
|
Packit |
597cd4 |
return SUBTYPE_INVALID;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
l2_packet_get_remote_addr(port->l2, qaz_tlvs->remote_mac);
|
|
Packit |
597cd4 |
if (unpack_ieee8021qaz_tlvs(port, agent, tlv))
|
|
Packit |
597cd4 |
return TLV_OK;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlv->type == TYPE_0) {
|
|
Packit |
597cd4 |
if (qaz_tlvs->active &&
|
|
Packit |
597cd4 |
dcbx_tlvs_rxed(qaz_tlvs->ifname, agent) &&
|
|
Packit |
597cd4 |
!qaz_tlvs->ieee8021qazdu) {
|
|
Packit |
597cd4 |
qaz_tlvs->active = false;
|
|
Packit |
597cd4 |
LLDPAD_INFO("IEEE DCBX on %s going INACTIVE\n",
|
|
Packit |
597cd4 |
qaz_tlvs->ifname);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (qaz_tlvs->active) {
|
|
Packit |
597cd4 |
/* If peer is DCBX, then go into RXTX mode
|
|
Packit |
597cd4 |
* if current configuration is RXOnly and
|
|
Packit |
597cd4 |
* not persistant (i.e. default)
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
int adminstatus;
|
|
Packit |
597cd4 |
if (qaz_tlvs->ieee8021qazdu &&
|
|
Packit |
597cd4 |
get_config_setting(qaz_tlvs->ifname,
|
|
Packit |
597cd4 |
agent->type,
|
|
Packit |
597cd4 |
ARG_ADMINSTATUS,
|
|
Packit |
597cd4 |
&adminstatus,
|
|
Packit |
597cd4 |
CONFIG_TYPE_INT) &&
|
|
Packit |
597cd4 |
get_lldp_agent_admin(qaz_tlvs->ifname,
|
|
Packit |
597cd4 |
agent->type) ==
|
|
Packit |
597cd4 |
enabledRxOnly) {
|
|
Packit |
597cd4 |
adminstatus = enabledRxTx;
|
|
Packit |
597cd4 |
if (set_config_setting(qaz_tlvs->ifname,
|
|
Packit |
597cd4 |
agent->type,
|
|
Packit |
597cd4 |
ARG_ADMINSTATUS,
|
|
Packit |
597cd4 |
&adminstatus,
|
|
Packit |
597cd4 |
CONFIG_TYPE_INT) ==
|
|
Packit |
597cd4 |
cmd_success)
|
|
Packit |
597cd4 |
set_lldp_agent_admin(qaz_tlvs->ifname,
|
|
Packit |
597cd4 |
agent->type,
|
|
Packit |
597cd4 |
adminstatus);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
if (qaz_tlvs->ieee8021qazdu)
|
|
Packit |
597cd4 |
qaz_tlvs->pending = false;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Update TLV State Machines */
|
|
Packit |
597cd4 |
ieee8021qaz_mibUpdateObjects(port);
|
|
Packit |
597cd4 |
run_all_sm(port, agent);
|
|
Packit |
597cd4 |
clear_ieee8021qaz_rx(qaz_tlvs);
|
|
Packit |
597cd4 |
somethingChangedLocal(port->ifname, agent->type);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return TLV_OK;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void ieee8021qaz_free_rx(struct ieee8021qaz_unpkd_tlvs *rx)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
if (!rx)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (rx->etscfg)
|
|
Packit |
597cd4 |
rx->etscfg = free_unpkd_tlv(rx->etscfg);
|
|
Packit |
597cd4 |
if (rx->etsrec)
|
|
Packit |
597cd4 |
rx->etsrec = free_unpkd_tlv(rx->etsrec);
|
|
Packit |
597cd4 |
if (rx->pfc)
|
|
Packit |
597cd4 |
rx->pfc = free_unpkd_tlv(rx->pfc);
|
|
Packit |
597cd4 |
if (rx->app)
|
|
Packit |
597cd4 |
rx->app = free_unpkd_tlv(rx->app);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* LLDP_8021QAZ_MOD_OPS - MIBDELETEOBJECT
|
|
Packit |
597cd4 |
*
|
|
Packit |
597cd4 |
* ieee8021qaz_mibDeleteObject - deletes MIBs
|
|
Packit |
597cd4 |
* Check if peer has ETS enabled
|
|
Packit |
597cd4 |
* - If yes, check if ETS TLV is present
|
|
Packit |
597cd4 |
* - If yes, set it as absent (delete it?)
|
|
Packit |
597cd4 |
* Same for PFC and APP.
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
u8 ieee8021qaz_mibDeleteObject(struct port *port, struct lldp_agent *agent)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(port->ifname);
|
|
Packit |
597cd4 |
if (!tlvs)
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
ieee8021qaz_free_rx(tlvs->rx);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Reseting ETS Remote params */
|
|
Packit |
597cd4 |
if (tlvs->ets) {
|
|
Packit |
597cd4 |
if (tlvs->ets->recr) {
|
|
Packit |
597cd4 |
free(tlvs->ets->recr);
|
|
Packit |
597cd4 |
tlvs->ets->recr = NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->ets->cfgr) {
|
|
Packit |
597cd4 |
free(tlvs->ets->cfgr);
|
|
Packit |
597cd4 |
tlvs->ets->cfgr = NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Reseting PFC Remote params */
|
|
Packit |
597cd4 |
tlvs->pfc->remote_param = 0;
|
|
Packit |
597cd4 |
tlvs->pfc->remote.willing = NULL;
|
|
Packit |
597cd4 |
tlvs->pfc->remote.mbc = NULL;
|
|
Packit |
597cd4 |
tlvs->pfc->remote.pfc_cap = 0;
|
|
Packit |
597cd4 |
tlvs->pfc->remote.pfc_enable = 0;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Clear peer Application data */
|
|
Packit |
597cd4 |
ieee8021qaz_app_reset(&tlvs->app_head);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Kick Tx State Machine */
|
|
Packit |
597cd4 |
somethingChangedLocal(port->ifname, agent->type);
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static struct ets_attrib *free_ets_tlv(struct ets_attrib *ets)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
if (ets) {
|
|
Packit |
597cd4 |
free(ets->cfgl);
|
|
Packit |
597cd4 |
free(ets->recl);
|
|
Packit |
597cd4 |
free(ets->cfgr);
|
|
Packit |
597cd4 |
free(ets->recr);
|
|
Packit |
597cd4 |
free(ets);
|
|
Packit |
597cd4 |
ets = NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static struct pfc_attrib *free_pfc_tlv(struct pfc_attrib *pfc)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
if (pfc) {
|
|
Packit |
597cd4 |
free(pfc);
|
|
Packit |
597cd4 |
pfc = NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void ieee8021qaz_free_tlv(struct ieee8021qaz_tlvs *tlvs)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct app_obj *np;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (!tlvs)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (tlvs->ets)
|
|
Packit |
597cd4 |
tlvs->ets = free_ets_tlv(tlvs->ets);
|
|
Packit |
597cd4 |
if (tlvs->pfc)
|
|
Packit |
597cd4 |
tlvs->pfc = free_pfc_tlv(tlvs->pfc);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* Remove _all_ existing application data */
|
|
Packit |
597cd4 |
LIST_FOREACH(np, &tlvs->app_head, entry)
|
|
Packit |
597cd4 |
np->hw = IEEE_APP_DEL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
__ieee8021qaz_app_sethw(tlvs->ifname, &tlvs->app_head);
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
static void ieee8021qaz_free_data(struct ieee8021qaz_user_data *iud)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *id;
|
|
Packit |
597cd4 |
if (iud) {
|
|
Packit |
597cd4 |
while (!LIST_EMPTY(&iud->head)) {
|
|
Packit |
597cd4 |
id = LIST_FIRST(&iud->head);
|
|
Packit |
597cd4 |
LIST_REMOVE(id, entry);
|
|
Packit |
597cd4 |
ieee8021qaz_free_tlv(id);
|
|
Packit |
597cd4 |
ieee8021qaz_free_rx(id->rx);
|
|
Packit |
597cd4 |
free(id->rx);
|
|
Packit |
597cd4 |
free(id);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/* LLDP_8021QAZ_MOD_OPS - UNREGISTER */
|
|
Packit |
597cd4 |
void ieee8021qaz_unregister(struct lldp_module *mod)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
if (mod->data) {
|
|
Packit |
597cd4 |
ieee8021qaz_free_data(mod->data);
|
|
Packit |
597cd4 |
free(mod->data);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
free(mod);
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* LLDP_8021QAZ_MOD_OPS - IFDOWN
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
void ieee8021qaz_ifdown(char *device_name, struct lldp_agent *agent)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlvs;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
if (agent->type != NEAREST_BRIDGE)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
tlvs = ieee8021qaz_data(device_name);
|
|
Packit |
597cd4 |
if (!tlvs)
|
|
Packit |
597cd4 |
return;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
ieee8021qaz_free_rx(tlvs->rx);
|
|
Packit |
597cd4 |
free(tlvs->rx);
|
|
Packit |
597cd4 |
tlvs->rx = NULL;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* LLDP_8021QAZ_MOD_OPS - TLVS_RXED
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
int ieee8021qaz_tlvs_rxed(const char *ifname)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_user_data *iud;
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlv = NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
|
|
Packit |
597cd4 |
if (iud) {
|
|
Packit |
597cd4 |
LIST_FOREACH(tlv, &iud->head, entry) {
|
|
Packit |
597cd4 |
if (!strncmp(tlv->ifname, ifname, IFNAMSIZ))
|
|
Packit |
597cd4 |
return !!tlv->ieee8021qazdu;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
/*
|
|
Packit |
597cd4 |
* LLDP_8021QAZ_MOD_OPS - CHECK_ACTIVE
|
|
Packit |
597cd4 |
*/
|
|
Packit |
597cd4 |
int ieee8021qaz_check_active(const char *ifname)
|
|
Packit |
597cd4 |
{
|
|
Packit |
597cd4 |
struct ieee8021qaz_user_data *iud;
|
|
Packit |
597cd4 |
struct ieee8021qaz_tlvs *tlv = NULL;
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ);
|
|
Packit |
597cd4 |
if (iud) {
|
|
Packit |
597cd4 |
LIST_FOREACH(tlv, &iud->head, entry) {
|
|
Packit |
597cd4 |
if (!strncmp(tlv->ifname, ifname, IFNAMSIZ))
|
|
Packit |
597cd4 |
return tlv->active && !tlv->pending;
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
}
|
|
Packit |
597cd4 |
|
|
Packit |
597cd4 |
return 0;
|
|
Packit |
597cd4 |
}
|