2022-09-29 12:16:50

by Daniel Machon

[permalink] [raw]
Subject: [PATCH net-next 0/6] Add new PCP and APPTRUST attributes to dcbnl

This patch series adds new extension attributes to dcbnl, for PCP queue
classification and per-selector trust and trust order. Additionally, the
microchip sparx5 driver has been dcb-enabled to make use of the new
attributes to offload PCP, DSCP and Default prio to the switch, and
implement trust order of selectors.

For pre-RFC discussion see:
https://lore.kernel.org/netdev/Yv9VO1DYAxNduw6A@DEN-LT-70577/

For RFC series see:
https://lore.kernel.org/netdev/[email protected]/

In summary: there currently exist no convenient way to offload per-port
PCP-based queue classification to hardware. Similarly, there is no way
to indicate the notion of trust for APP table selectors. This patch
series addresses both topics.

PCP based queue classification:
- 8021Q standardizes the Priority Code Point table (see 6.9.3 of IEEE
Std 802.1Q-2018). This patch series makes it possible, to offload
the PCP classification to said table. The new PCP selector is not a
standard part of the APP managed object, therefore it is
encapsulated in a new non-std extension attribute.

Selector trust:
- ASIC's often has the notion of trust DSCP and trust PCP. The new
attribute makes it possible to specify a trust order of app
selectors, which drivers can then react on.

DCB-enable sparx5 driver:
- Now supports offloading of DSCP, PCP and default priority. Only one
mapping of protocol:priority is allowed. Consecutive mappings of the
same protocol to some new priority, will overwrite the previous. This
is to keep a consistent view of the app table and the hardware.
- Now supports dscp and pcp trust, by use of the introduced
dcbnl_set/getapptrust ops. Sparx5 supports trust orders: [], [dscp],
[pcp] and [dscp, pcp]. For now, only DSCP and PCP selectors are
supported by the driver, everything else is bounced.

Patch #1 introduces a new PCP selector to the APP object, which makes it
possible to encode PCP and DEI in the app triplet and offload it to the
PCP table of the ASIC.

Patch #2 Introduces the new extension attributes
DCB_ATTR_DCB_APP_TRUST_TABLE and DCB_ATTR_DCB_APP_TRUST. Trusted
selectors are passed in the nested DCB_ATTR_DCB_APP_TRUST_TABLE
attribute, and assembled into an array of selectors:

u8 selectors[256];

where lower indexes has higher precedence. In the array, selectors are
stored consecutively, starting from index zero. With a maximum number of
256 unique selectors, the list has the same maximum size.

Patch #3 Sets up the dcbnl ops hook, and adds support for offloading pcp
app entries, to the PCP table of the switch.

Patch #4 Makes use of the dcbnl_set/getapptrust ops, to set a per-port
trust order.

Patch #5 Adds support for offloading dscp app entries to the DSCP table
of the switch.

Patch #6 Adds support for offloading default prio app entries to the
switch.

================================================================================

RFC v1:
https://lore.kernel.org/netdev/[email protected]/

RFC v1 -> RFC v2:
- Added new nested attribute type DCB_ATTR_DCB_APP_TRUST_TABLE.
- Renamed attributes from DCB_ATTR_IEEE_* to DCB_ATTR_DCB_*.
- Renamed ieee_set/getapptrust to dcbnl_set/getapptrust.
- Added -EOPNOTSUPP if dcbnl_setapptrust is not set.
- Added sanitization of selector array, before passing to driver.

RFC v2 -> (non-RFC) v1
- Added additional check for selector validity.
- Fixed a few style errors.
- using nla_start_nest() instead of nla_start_nest_no_flag().
- Moved DCB_ATTR_DCB_APP_TRUST into new enum.
- Added new DCB_ATTR_DCB_APP extension attribute, for non-std selector
values.
- Added support for offloading dscp, pcp and default prio in the sparx5
driver.
- Added support for per-selector trust and trust order in the sparx5
driver.

Daniel Machon (6):
net: dcb: add new pcp selector to app object
net: dcb: add new apptrust attribute
net: microchip: sparx5: add support for offloading pcp table
net: microchip: sparx5: add support for apptrust
net: microchip: sparx5: add support for offloading dscp table
net: microchip: sparx5: add support for offloading default prio

.../net/ethernet/microchip/sparx5/Makefile | 2 +-
.../ethernet/microchip/sparx5/sparx5_dcb.c | 287 ++++++++++++++++++
.../ethernet/microchip/sparx5/sparx5_main.h | 1 +
.../microchip/sparx5/sparx5_main_regs.h | 127 +++++++-
.../ethernet/microchip/sparx5/sparx5_netdev.c | 1 +
.../ethernet/microchip/sparx5/sparx5_port.c | 99 ++++++
.../ethernet/microchip/sparx5/sparx5_port.h | 33 ++
.../ethernet/microchip/sparx5/sparx5_qos.c | 4 +
.../ethernet/microchip/sparx5/sparx5_qos.h | 3 +
include/net/dcbnl.h | 4 +
include/uapi/linux/dcbnl.h | 14 +
net/dcb/dcbnl.c | 126 +++++++-
12 files changed, 690 insertions(+), 11 deletions(-)
create mode 100644 drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c

--
2.34.1


2022-09-29 12:18:56

by Daniel Machon

[permalink] [raw]
Subject: [PATCH net-next 5/6] net: microchip: sparx5: add support for offloading dscp table

Add support for offloading dscp app entries. Dscp values are global for
all ports on the sparx5 switch. Therefore, we replicate each dscp app
entry per-port.

Signed-off-by: Daniel Machon <[email protected]>
---
.../ethernet/microchip/sparx5/sparx5_dcb.c | 62 ++++++++++++++++++-
.../ethernet/microchip/sparx5/sparx5_port.c | 39 ++++++++++++
.../ethernet/microchip/sparx5/sparx5_port.h | 9 +++
3 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c b/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
index 10aeb422b1ae..0cc46672b59c 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
@@ -34,6 +34,13 @@ static int sparx5_dcb_app_validate(struct net_device *dev,
int err = 0;

switch (app->selector) {
+ /* Dscp checks */
+ case IEEE_8021QAZ_APP_SEL_DSCP:
+ if (app->protocol > 63)
+ err = -EINVAL;
+ else if (app->priority >= SPX5_PRIOS)
+ err = -ERANGE;
+ break;
/* Pcp checks */
case DCB_APP_SEL_PCP:
if (app->protocol > 15)
@@ -104,12 +111,20 @@ static int sparx5_dcb_app_update(struct net_device *dev)
struct dcb_app app_itr = { .selector = DCB_APP_SEL_PCP };
struct sparx5_port *port = netdev_priv(dev);
struct sparx5_port_qos_pcp_map *pcp_map;
+ struct dcb_ieee_app_dscp_map *dscp_map;
struct sparx5_port_qos qos = {0};
int portno = port->portno;
int i;

+ dscp_map = &qos.dscp.map;
pcp_map = &qos.pcp.map;

+ /* Get dscp ingress mapping */
+ dcb_ieee_getapp_dscp_prio_mask_map(dev, dscp_map);
+ for (i = 0; i < ARRAY_SIZE(dscp_map->map); i++)
+ if (dscp_map->map[i])
+ dscp_map->map[i] = fls(dscp_map->map[i]) - 1;
+
/* Get pcp ingress mapping */
for (i = 0; i < ARRAY_SIZE(pcp_map->map); i++) {
app_itr.protocol = i;
@@ -122,9 +137,44 @@ static int sparx5_dcb_app_update(struct net_device *dev)
qos.pcp.dp_enable = qos.pcp.qos_enable;
}

+ /* Enable use of dscp for queue classification ? */
+ if (sparx5_dcb_apptrust_contains(portno, IEEE_8021QAZ_APP_SEL_DSCP)) {
+ qos.dscp.qos_enable = true;
+ qos.dscp.dp_enable = qos.dscp.qos_enable;
+ }
+
return sparx5_port_qos_set(port, &qos);
}

+/* Set or delete dscp app entry.
+ *
+ * Dscp mapping is global for all ports, so set and delete app entries are
+ * replicated for each port.
+ */
+static int sparx5_dcb_ieee_dscp_setdel_app(struct net_device *dev,
+ struct dcb_app *app, bool del)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ struct dcb_app apps[SPX5_PORTS];
+ struct sparx5_port *port_itr;
+ int err, i;
+
+ for (i = 0; i < SPX5_PORTS; i++) {
+ port_itr = port->sparx5->ports[i];
+ if (!port_itr)
+ continue;
+ memcpy(&apps[i], app, sizeof(struct dcb_app));
+ if (del)
+ err = dcb_ieee_delapp(port_itr->ndev, &apps[i]);
+ else
+ err = dcb_ieee_setapp(port_itr->ndev, &apps[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int sparx5_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app)
{
struct dcb_app app_itr;
@@ -143,7 +193,11 @@ static int sparx5_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app)
dcb_ieee_delapp(dev, &app_itr);
}

- err = dcb_ieee_setapp(dev, app);
+ if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
+ err = sparx5_dcb_ieee_dscp_setdel_app(dev, app, false);
+ else
+ err = dcb_ieee_setapp(dev, app);
+
if (err)
goto out;

@@ -157,7 +211,11 @@ static int sparx5_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app)
{
int err;

- err = dcb_ieee_delapp(dev, app);
+ if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
+ err = sparx5_dcb_ieee_dscp_setdel_app(dev, app, true);
+ else
+ err = dcb_ieee_delapp(dev, app);
+
if (err < 0)
return err;

diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
index 99e86e87aa16..fb5e321c4896 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
@@ -1149,6 +1149,7 @@ void sparx5_port_enable(struct sparx5_port *port, bool enable)
int sparx5_port_qos_set(struct sparx5_port *port,
struct sparx5_port_qos *qos)
{
+ sparx5_port_qos_dscp_set(port, &qos->dscp);
sparx5_port_qos_pcp_set(port, &qos->pcp);

return 0;
@@ -1181,3 +1182,41 @@ int sparx5_port_qos_pcp_set(const struct sparx5_port *port,

return 0;
}
+
+int sparx5_port_qos_dscp_set(const struct sparx5_port *port,
+ struct sparx5_port_qos_dscp *qos)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+ u8 *dscp = qos->map.map;
+ int i;
+
+ /* Enable/disable dscp and dp for qos classification.
+ * Disable rewrite of dscp values for now.
+ */
+ spx5_rmw(ANA_CL_QOS_CFG_DSCP_QOS_ENA_SET(qos->qos_enable) |
+ ANA_CL_QOS_CFG_DSCP_DP_ENA_SET(qos->dp_enable) |
+ ANA_CL_QOS_CFG_DSCP_KEEP_ENA_SET(1),
+ ANA_CL_QOS_CFG_DSCP_QOS_ENA | ANA_CL_QOS_CFG_DSCP_DP_ENA |
+ ANA_CL_QOS_CFG_DSCP_KEEP_ENA, sparx5,
+ ANA_CL_QOS_CFG(port->portno));
+
+ /* Map each dscp value to priority and dp */
+ for (i = 0; i < ARRAY_SIZE(qos->map.map); i++) {
+ spx5_rmw(ANA_CL_DSCP_CFG_DSCP_QOS_VAL_SET(*(dscp + i)) |
+ ANA_CL_DSCP_CFG_DSCP_DP_VAL_SET(0),
+ ANA_CL_DSCP_CFG_DSCP_QOS_VAL |
+ ANA_CL_DSCP_CFG_DSCP_DP_VAL, sparx5,
+ ANA_CL_DSCP_CFG(i));
+ }
+
+ /* Set per-dscp trust */
+ for (i = 0; i < ARRAY_SIZE(qos->map.map); i++) {
+ if (qos->qos_enable) {
+ spx5_rmw(ANA_CL_DSCP_CFG_DSCP_TRUST_ENA_SET(1),
+ ANA_CL_DSCP_CFG_DSCP_TRUST_ENA, sparx5,
+ ANA_CL_DSCP_CFG(i));
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.h b/drivers/net/ethernet/microchip/sparx5/sparx5_port.h
index fae9f5464548..00def02455a7 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.h
@@ -101,8 +101,15 @@ struct sparx5_port_qos_pcp {
bool dp_enable;
};

+struct sparx5_port_qos_dscp {
+ struct dcb_ieee_app_dscp_map map;
+ bool qos_enable;
+ bool dp_enable;
+};
+
struct sparx5_port_qos {
struct sparx5_port_qos_pcp pcp;
+ struct sparx5_port_qos_dscp dscp;
};

int sparx5_port_qos_set(struct sparx5_port *port, struct sparx5_port_qos *qos);
@@ -110,4 +117,6 @@ int sparx5_port_qos_set(struct sparx5_port *port, struct sparx5_port_qos *qos);
int sparx5_port_qos_pcp_set(const struct sparx5_port *port,
struct sparx5_port_qos_pcp *qos);

+int sparx5_port_qos_dscp_set(const struct sparx5_port *port,
+ struct sparx5_port_qos_dscp *qos);
#endif /* __SPARX5_PORT_H__ */
--
2.34.1

2022-09-29 12:20:22

by Daniel Machon

[permalink] [raw]
Subject: [PATCH net-next 6/6] net: microchip: sparx5: add support for offloading default prio

Add support for offloading default prio {ETHERTYPE, 0, prio}.

Signed-off-by: Daniel Machon <[email protected]>
---
.../ethernet/microchip/sparx5/sparx5_dcb.c | 12 ++++++++++
.../ethernet/microchip/sparx5/sparx5_port.c | 23 +++++++++++++++++++
.../ethernet/microchip/sparx5/sparx5_port.h | 5 ++++
3 files changed, 40 insertions(+)

diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c b/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
index 0cc46672b59c..50df24972643 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
@@ -34,6 +34,13 @@ static int sparx5_dcb_app_validate(struct net_device *dev,
int err = 0;

switch (app->selector) {
+ /* Default priority checks */
+ case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
+ if (app->protocol != 0)
+ err = -EINVAL;
+ else if (app->priority >= SPX5_PRIOS)
+ err = -ERANGE;
+ break;
/* Dscp checks */
case IEEE_8021QAZ_APP_SEL_DSCP:
if (app->protocol > 63)
@@ -119,6 +126,11 @@ static int sparx5_dcb_app_update(struct net_device *dev)
dscp_map = &qos.dscp.map;
pcp_map = &qos.pcp.map;

+ /* Get default prio. */
+ qos.default_prio = dcb_ieee_getapp_default_prio_mask(dev);
+ if (qos.default_prio)
+ qos.default_prio = fls(qos.default_prio) - 1;
+
/* Get dscp ingress mapping */
dcb_ieee_getapp_dscp_prio_mask_map(dev, dscp_map);
for (i = 0; i < ARRAY_SIZE(dscp_map->map); i++)
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
index fb5e321c4896..73ebe76d7e50 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
@@ -1151,6 +1151,7 @@ int sparx5_port_qos_set(struct sparx5_port *port,
{
sparx5_port_qos_dscp_set(port, &qos->dscp);
sparx5_port_qos_pcp_set(port, &qos->pcp);
+ sparx5_port_qos_default_set(port, qos);

return 0;
}
@@ -1220,3 +1221,25 @@ int sparx5_port_qos_dscp_set(const struct sparx5_port *port,

return 0;
}
+
+int sparx5_port_qos_default_set(const struct sparx5_port *port,
+ const struct sparx5_port_qos *qos)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+
+ /* Set default prio and dp level */
+ spx5_rmw(ANA_CL_QOS_CFG_DEFAULT_QOS_VAL_SET(qos->default_prio) |
+ ANA_CL_QOS_CFG_DEFAULT_DP_VAL_SET(0),
+ ANA_CL_QOS_CFG_DEFAULT_QOS_VAL |
+ ANA_CL_QOS_CFG_DEFAULT_DP_VAL,
+ sparx5, ANA_CL_QOS_CFG(port->portno));
+
+ /* Set default pcp and dei for untagged frames */
+ spx5_rmw(ANA_CL_VLAN_CTRL_PORT_PCP_SET(0) |
+ ANA_CL_VLAN_CTRL_PORT_DEI_SET(0),
+ ANA_CL_VLAN_CTRL_PORT_PCP |
+ ANA_CL_VLAN_CTRL_PORT_DEI,
+ sparx5, ANA_CL_VLAN_CTRL(port->portno));
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.h b/drivers/net/ethernet/microchip/sparx5/sparx5_port.h
index 00def02455a7..698d7d5a5c4e 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.h
@@ -110,6 +110,7 @@ struct sparx5_port_qos_dscp {
struct sparx5_port_qos {
struct sparx5_port_qos_pcp pcp;
struct sparx5_port_qos_dscp dscp;
+ u8 default_prio;
};

int sparx5_port_qos_set(struct sparx5_port *port, struct sparx5_port_qos *qos);
@@ -119,4 +120,8 @@ int sparx5_port_qos_pcp_set(const struct sparx5_port *port,

int sparx5_port_qos_dscp_set(const struct sparx5_port *port,
struct sparx5_port_qos_dscp *qos);
+
+int sparx5_port_qos_default_set(const struct sparx5_port *port,
+ const struct sparx5_port_qos *qos);
+
#endif /* __SPARX5_PORT_H__ */
--
2.34.1

2022-09-29 12:21:05

by Daniel Machon

[permalink] [raw]
Subject: [PATCH net-next 2/6] net: dcb: add new apptrust attribute

Add new apptrust extension attributes to the 8021Qaz APP managed object.

Two new attributes, DCB_ATTR_DCB_APP_TRUST_TABLE and
DCB_ATTR_DCB_APP_TRUST, has been added. Trusted selectors are passed in
the nested attribute DCB_ATTR_DCB_APP_TRUST, in order of precedence.

The new attributes are meant to allow drivers, whose hw supports the
notion of trust, to be able to set whether a particular app selector is
trusted - and in which order.

Signed-off-by: Daniel Machon <[email protected]>
---
include/net/dcbnl.h | 4 ++
include/uapi/linux/dcbnl.h | 8 ++++
net/dcb/dcbnl.c | 77 ++++++++++++++++++++++++++++++++++++--
3 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h
index 2b2d86fb3131..8841ab6c2de7 100644
--- a/include/net/dcbnl.h
+++ b/include/net/dcbnl.h
@@ -109,6 +109,10 @@ struct dcbnl_rtnl_ops {
/* buffer settings */
int (*dcbnl_getbuffer)(struct net_device *, struct dcbnl_buffer *);
int (*dcbnl_setbuffer)(struct net_device *, struct dcbnl_buffer *);
+
+ /* apptrust */
+ int (*dcbnl_setapptrust)(struct net_device *, u8 *, int);
+ int (*dcbnl_getapptrust)(struct net_device *, u8 *, int *);
};

#endif /* __NET_DCBNL_H__ */
diff --git a/include/uapi/linux/dcbnl.h b/include/uapi/linux/dcbnl.h
index 9f68dc501cc1..fcca9016b298 100644
--- a/include/uapi/linux/dcbnl.h
+++ b/include/uapi/linux/dcbnl.h
@@ -423,6 +423,7 @@ enum ieee_attrs {
DCB_ATTR_IEEE_QCN,
DCB_ATTR_IEEE_QCN_STATS,
DCB_ATTR_DCB_BUFFER,
+ DCB_ATTR_DCB_APP_TRUST_TABLE,
__DCB_ATTR_IEEE_MAX
};
#define DCB_ATTR_IEEE_MAX (__DCB_ATTR_IEEE_MAX - 1)
@@ -435,6 +436,13 @@ enum ieee_attrs_app {
};
#define DCB_ATTR_IEEE_APP_MAX (__DCB_ATTR_IEEE_APP_MAX - 1)

+enum dcbnl_attrs_apptrust {
+ DCB_ATTR_DCB_APP_TRUST_UNSPEC,
+ DCB_ATTR_DCB_APP_TRUST,
+ __DCB_ATTR_DCB_APP_TRUST_MAX
+};
+#define DCB_ATTR_DCB_APP_TRUST_MAX (__DCB_ATTR_DCB_APP_TRUST_MAX - 1)
+
/**
* enum cee_attrs - CEE DCBX get attributes.
*
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index 580d26acfc84..ad84f70e3eb3 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -166,6 +166,7 @@ static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
[DCB_ATTR_IEEE_QCN] = {.len = sizeof(struct ieee_qcn)},
[DCB_ATTR_IEEE_QCN_STATS] = {.len = sizeof(struct ieee_qcn_stats)},
[DCB_ATTR_DCB_BUFFER] = {.len = sizeof(struct dcbnl_buffer)},
+ [DCB_ATTR_DCB_APP_TRUST_TABLE] = {.type = NLA_NESTED},
};

/* DCB number of traffic classes nested attributes. */
@@ -1070,11 +1071,11 @@ static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
/* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb GET commands. */
static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
{
- struct nlattr *ieee, *app;
- struct dcb_app_type *itr;
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
+ struct nlattr *ieee, *app, *apptrust;
+ struct dcb_app_type *itr;
+ int err, i;
int dcbx;
- int err;

if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name))
return -EMSGSIZE;
@@ -1174,6 +1175,24 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
spin_unlock_bh(&dcb_lock);
nla_nest_end(skb, app);

+ if (ops->dcbnl_getapptrust) {
+ u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1] = {0};
+ int nselectors;
+
+ apptrust = nla_nest_start(skb, DCB_ATTR_DCB_APP_TRUST_TABLE);
+ if (!app)
+ return -EMSGSIZE;
+
+ err = ops->dcbnl_getapptrust(netdev, selectors, &nselectors);
+ if (err)
+ return -EMSGSIZE;
+
+ for (i = 0; i < nselectors; i++)
+ nla_put_u8(skb, DCB_ATTR_DCB_APP_TRUST, selectors[i]);
+
+ nla_nest_end(skb, apptrust);
+ }
+
/* get peer info if available */
if (ops->ieee_peer_getets) {
struct ieee_ets ets;
@@ -1467,8 +1486,8 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
{
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
+ int err, i;
int prio;
- int err;

if (!ops)
return -EOPNOTSUPP;
@@ -1554,6 +1573,56 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
}
}

+ if (ieee[DCB_ATTR_DCB_APP_TRUST_TABLE]) {
+ u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1] = {0};
+ struct nlattr *attr;
+ int nselectors = 0;
+ u8 selector;
+ int rem;
+
+ if (!ops->dcbnl_setapptrust) {
+ err = -EOPNOTSUPP;
+ goto err;
+ }
+
+ nla_for_each_nested(attr, ieee[DCB_ATTR_DCB_APP_TRUST_TABLE],
+ rem) {
+ if (nla_type(attr) != DCB_ATTR_DCB_APP_TRUST ||
+ nla_len(attr) != 1 ||
+ nselectors >= sizeof(selectors)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ selector = nla_get_u8(attr);
+ switch (selector) {
+ case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
+ case IEEE_8021QAZ_APP_SEL_STREAM:
+ case IEEE_8021QAZ_APP_SEL_DGRAM:
+ case IEEE_8021QAZ_APP_SEL_ANY:
+ case IEEE_8021QAZ_APP_SEL_DSCP:
+ case DCB_APP_SEL_PCP:
+ break;
+ default:
+ err = -EINVAL;
+ goto err;
+ }
+ /* Duplicate selector ? */
+ for (i = 0; i < nselectors; i++) {
+ if (selectors[i] == selector) {
+ err = -EINVAL;
+ goto err;
+ }
+ }
+
+ selectors[nselectors++] = selector;
+ }
+
+ err = ops->dcbnl_setapptrust(netdev, selectors, nselectors);
+ if (err)
+ goto err;
+ }
+
err:
err = nla_put_u8(skb, DCB_ATTR_IEEE, err);
dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
--
2.34.1