summaryrefslogtreecommitdiffstats
path: root/net/dcb/dcbnl.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dcb/dcbnl.c')
-rw-r--r--net/dcb/dcbnl.c159
1 files changed, 152 insertions, 7 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index fc56e8546261..d5b45a201c1b 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -1642,6 +1642,60 @@ err:
return ret;
}
+static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
+ int dir)
+{
+ u8 pgid, up_map, prio, tc_pct;
+ const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
+ int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG;
+ struct nlattr *pg = nla_nest_start(skb, i);
+
+ if (!pg)
+ goto nla_put_failure;
+
+ for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
+ struct nlattr *tc_nest = nla_nest_start(skb, i);
+
+ if (!tc_nest)
+ goto nla_put_failure;
+
+ pgid = DCB_ATTR_VALUE_UNDEFINED;
+ prio = DCB_ATTR_VALUE_UNDEFINED;
+ tc_pct = DCB_ATTR_VALUE_UNDEFINED;
+ up_map = DCB_ATTR_VALUE_UNDEFINED;
+
+ if (!dir)
+ ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0,
+ &prio, &pgid, &tc_pct, &up_map);
+ else
+ ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0,
+ &prio, &pgid, &tc_pct, &up_map);
+
+ NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_PGID, pgid);
+ NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
+ NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
+ NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct);
+ nla_nest_end(skb, tc_nest);
+ }
+
+ for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
+ tc_pct = DCB_ATTR_VALUE_UNDEFINED;
+
+ if (!dir)
+ ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0,
+ &tc_pct);
+ else
+ ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
+ &tc_pct);
+ NLA_PUT_U8(skb, i, tc_pct);
+ }
+ nla_nest_end(skb, pg);
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
/* Handle CEE DCBX GET commands. */
static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
u32 pid, u32 seq, u16 flags)
@@ -1649,9 +1703,11 @@ static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct dcbmsg *dcb;
- struct nlattr *cee;
+ struct nlattr *cee, *app;
+ struct dcb_app_type *itr;
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
- int err;
+ int dcbx, i, err = -EMSGSIZE;
+ u8 value;
if (!ops)
return -EOPNOTSUPP;
@@ -1672,7 +1728,88 @@ static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
if (!cee)
goto nla_put_failure;
- /* get peer info if available */
+ /* local pg */
+ if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) {
+ err = dcbnl_cee_pg_fill(skb, netdev, 1);
+ if (err)
+ goto nla_put_failure;
+ }
+
+ if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) {
+ err = dcbnl_cee_pg_fill(skb, netdev, 0);
+ if (err)
+ goto nla_put_failure;
+ }
+
+ /* local pfc */
+ if (ops->getpfccfg) {
+ struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC);
+
+ if (!pfc_nest)
+ goto nla_put_failure;
+
+ for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
+ ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
+ NLA_PUT_U8(skb, i, value);
+ }
+ nla_nest_end(skb, pfc_nest);
+ }
+
+ /* local app */
+ spin_lock(&dcb_lock);
+ app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE);
+ if (!app)
+ goto nla_put_failure;
+
+ list_for_each_entry(itr, &dcb_app_list, list) {
+ if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) {
+ struct nlattr *app_nest = nla_nest_start(skb,
+ DCB_ATTR_APP);
+ if (!app_nest)
+ goto dcb_unlock;
+
+ err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE,
+ itr->app.selector);
+ if (err)
+ goto dcb_unlock;
+
+ err = nla_put_u16(skb, DCB_APP_ATTR_ID,
+ itr->app.protocol);
+ if (err)
+ goto dcb_unlock;
+
+ err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY,
+ itr->app.priority);
+ if (err)
+ goto dcb_unlock;
+
+ nla_nest_end(skb, app_nest);
+ }
+ }
+ nla_nest_end(skb, app);
+
+ if (netdev->dcbnl_ops->getdcbx)
+ dcbx = netdev->dcbnl_ops->getdcbx(netdev);
+ else
+ dcbx = -EOPNOTSUPP;
+
+ spin_unlock(&dcb_lock);
+
+ /* features flags */
+ if (ops->getfeatcfg) {
+ struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT);
+ if (!feat)
+ goto nla_put_failure;
+
+ for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX;
+ i++)
+ if (!ops->getfeatcfg(netdev, i, &value))
+ NLA_PUT_U8(skb, i, value);
+
+ nla_nest_end(skb, feat);
+ }
+
+ /* peer info if available */
if (ops->cee_peer_getpg) {
struct cee_pg pg;
err = ops->cee_peer_getpg(netdev, &pg);
@@ -1695,16 +1832,24 @@ static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
if (err)
goto nla_put_failure;
}
-
nla_nest_end(skb, cee);
- nlmsg_end(skb, nlh);
+ /* DCBX state */
+ if (dcbx >= 0) {
+ err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
+ if (err)
+ goto nla_put_failure;
+ }
+ nlmsg_end(skb, nlh);
return rtnl_unicast(skb, &init_net, pid);
+
+dcb_unlock:
+ spin_unlock(&dcb_lock);
nla_put_failure:
nlmsg_cancel(skb, nlh);
nlmsg_failure:
- kfree_skb(skb);
- return -1;
+ nlmsg_free(skb);
+ return err;
}
static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)