diff options
-rw-r--r-- | drivers/net/ixgbe/ixgbe_dcb_nl.c | 33 | ||||
-rw-r--r-- | include/linux/dcbnl.h | 27 | ||||
-rw-r--r-- | include/net/dcbnl.h | 2 | ||||
-rw-r--r-- | net/dcb/dcbnl.c | 132 |
4 files changed, 193 insertions, 1 deletions
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index eb3a6cea1aaa..5921795f8403 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -376,6 +376,35 @@ static u8 ixgbe_dcbnl_getcap(struct net_device *netdev, int capid, u8 *cap) return rval; } +static u8 ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u8 rval = 0; + + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + switch (tcid) { + case DCB_NUMTCS_ATTR_PG: + *num = MAX_TRAFFIC_CLASS; + break; + case DCB_NUMTCS_ATTR_PFC: + *num = MAX_TRAFFIC_CLASS; + break; + default: + rval = -EINVAL; + break; + } + } else { + rval = -EINVAL; + } + + return rval; +} + +static u8 ixgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num) +{ + return -EINVAL; +} + struct dcbnl_rtnl_ops dcbnl_ops = { .getstate = ixgbe_dcbnl_get_state, .setstate = ixgbe_dcbnl_set_state, @@ -391,6 +420,8 @@ struct dcbnl_rtnl_ops dcbnl_ops = { .setpfccfg = ixgbe_dcbnl_set_pfc_cfg, .getpfccfg = ixgbe_dcbnl_get_pfc_cfg, .setall = ixgbe_dcbnl_set_all, - .getcap = ixgbe_dcbnl_getcap + .getcap = ixgbe_dcbnl_getcap, + .getnumtcs = ixgbe_dcbnl_getnumtcs, + .setnumtcs = ixgbe_dcbnl_setnumtcs }; diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h index 13f0c638a695..1077fba1dadc 100644 --- a/include/linux/dcbnl.h +++ b/include/linux/dcbnl.h @@ -44,6 +44,8 @@ struct dcbmsg { * @DCB_CMD_GPERM_HWADDR: get the permanent MAC address of the underlying * device. Only useful when using bonding. * @DCB_CMD_GCAP: request the DCB capabilities of the device + * @DCB_CMD_GNUMTCS: get the number of traffic classes currently supported + * @DCB_CMD_SNUMTCS: set the number of traffic classes */ enum dcbnl_commands { DCB_CMD_UNDEFINED, @@ -62,6 +64,8 @@ enum dcbnl_commands { DCB_CMD_SET_ALL, DCB_CMD_GPERM_HWADDR, DCB_CMD_GCAP, + DCB_CMD_GNUMTCS, + DCB_CMD_SNUMTCS, __DCB_CMD_ENUM_MAX, DCB_CMD_MAX = __DCB_CMD_ENUM_MAX - 1, @@ -81,6 +85,7 @@ enum dcbnl_commands { * @DCB_ATTR_SET_ALL: bool to commit changes to hardware or not (NLA_U8) * @DCB_ATTR_PERM_HWADDR: MAC address of the physical device (NLA_NESTED) * @DCB_ATTR_CAP: DCB capabilities of the device (NLA_NESTED) + * @DCB_ATTR_NUMTCS: number of traffic classes supported (NLA_NESTED) */ enum dcbnl_attrs { DCB_ATTR_UNDEFINED, @@ -94,6 +99,7 @@ enum dcbnl_attrs { DCB_ATTR_SET_ALL, DCB_ATTR_PERM_HWADDR, DCB_ATTR_CAP, + DCB_ATTR_NUMTCS, __DCB_ATTR_ENUM_MAX, DCB_ATTR_MAX = __DCB_ATTR_ENUM_MAX - 1, @@ -253,6 +259,27 @@ enum dcbnl_cap_attrs { __DCB_CAP_ATTR_ENUM_MAX, DCB_CAP_ATTR_MAX = __DCB_CAP_ATTR_ENUM_MAX - 1, }; + +/** + * enum dcbnl_numtcs_attrs - number of traffic classes + * + * @DCB_NUMTCS_ATTR_UNDEFINED: unspecified attribute to catch errors + * @DCB_NUMTCS_ATTR_ALL: (NLA_FLAG) all traffic class attributes + * @DCB_NUMTCS_ATTR_PG: (NLA_U8) number of traffic classes used for + * priority groups + * @DCB_NUMTCS_ATTR_PFC: (NLA_U8) number of traffic classes which can + * support priority flow control + */ +enum dcbnl_numtcs_attrs { + DCB_NUMTCS_ATTR_UNDEFINED, + DCB_NUMTCS_ATTR_ALL, + DCB_NUMTCS_ATTR_PG, + DCB_NUMTCS_ATTR_PFC, + + __DCB_NUMTCS_ATTR_ENUM_MAX, + DCB_NUMTCS_ATTR_MAX = __DCB_NUMTCS_ATTR_ENUM_MAX - 1, +}; + /** * enum dcb_general_attr_values - general DCB attribute values * diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h index 183ed040cf4c..f0a65281ea73 100644 --- a/include/net/dcbnl.h +++ b/include/net/dcbnl.h @@ -40,6 +40,8 @@ struct dcbnl_rtnl_ops { void (*getpfccfg)(struct net_device *, int, u8 *); u8 (*setall)(struct net_device *); u8 (*getcap)(struct net_device *, int, u8 *); + u8 (*getnumtcs)(struct net_device *, int, u8 *); + u8 (*setnumtcs)(struct net_device *, int, u8); }; #endif /* __NET_DCBNL_H__ */ diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index de61d64d102d..5ff7e3c0c172 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -120,6 +120,13 @@ static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, }; +/* DCB capabilities nested attributes. */ +static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { + [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, + [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, + [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, +}; + /* standard netlink reply call */ static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, u32 seq, u16 flags) @@ -347,6 +354,123 @@ err_out: return -EINVAL; } +static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct sk_buff *dcbnl_skb; + struct nlmsghdr *nlh; + struct dcbmsg *dcb; + struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; + u8 value; + int ret = -EINVAL; + int i; + int getall = 0; + + if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) + return ret; + + ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], + dcbnl_numtcs_nest); + if (ret) { + ret = -EINVAL; + goto err_out; + } + + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) { + ret = -EINVAL; + goto err_out; + } + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); + + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = DCB_CMD_GNUMTCS; + + nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); + if (!nest) { + ret = -EINVAL; + goto err; + } + + if (data[DCB_NUMTCS_ATTR_ALL]) + getall = 1; + + for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { + if (!getall && !data[i]) + continue; + + ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); + if (!ret) { + ret = nla_put_u8(dcbnl_skb, i, value); + + if (ret) { + nla_nest_cancel(dcbnl_skb, nest); + ret = -EINVAL; + goto err; + } + } else { + goto err; + } + } + nla_nest_end(dcbnl_skb, nest); + + nlmsg_end(dcbnl_skb, nlh); + + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) { + ret = -EINVAL; + goto err; + } + + return 0; +nlmsg_failure: +err: + kfree(dcbnl_skb); +err_out: + return ret; +} + +static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; + int ret = -EINVAL; + u8 value; + int i; + + if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setstate) + return ret; + + ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], + dcbnl_numtcs_nest); + + if (ret) { + ret = -EINVAL; + goto err; + } + + for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { + if (data[i] == NULL) + continue; + + value = nla_get_u8(data[i]); + + ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); + + if (ret) + goto operr; + } + +operr: + ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS, + DCB_ATTR_NUMTCS, pid, seq, flags); + +err: + return ret; +} + static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, u32 pid, u32 seq, u16 flags, int dir) { @@ -757,6 +881,14 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, nlh->nlmsg_flags); goto out; + case DCB_CMD_GNUMTCS: + ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_SNUMTCS: + ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; default: goto errout; } |