19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 22f90b865SAlexander Duyck /* 3698e1d23SMark Rustad * Copyright (c) 2008-2011, Intel Corporation. 42f90b865SAlexander Duyck * 536b9ad80SPaul Gortmaker * Description: Data Center Bridging netlink interface 62f90b865SAlexander Duyck * Author: Lucy Liu <lucy.liu@intel.com> 72f90b865SAlexander Duyck */ 82f90b865SAlexander Duyck 92f90b865SAlexander Duyck #include <linux/netdevice.h> 102f90b865SAlexander Duyck #include <linux/netlink.h> 115a0e3ad6STejun Heo #include <linux/slab.h> 122f90b865SAlexander Duyck #include <net/netlink.h> 132f90b865SAlexander Duyck #include <net/rtnetlink.h> 142f90b865SAlexander Duyck #include <linux/dcbnl.h> 1596b99684SJohn Fastabend #include <net/dcbevent.h> 162f90b865SAlexander Duyck #include <linux/rtnetlink.h> 1736b9ad80SPaul Gortmaker #include <linux/init.h> 182f90b865SAlexander Duyck #include <net/sock.h> 192f90b865SAlexander Duyck 20ae86b9e3SBen Hutchings /* Data Center Bridging (DCB) is a collection of Ethernet enhancements 212f90b865SAlexander Duyck * intended to allow network traffic with differing requirements 222f90b865SAlexander Duyck * (highly reliable, no drops vs. best effort vs. low latency) to operate 232f90b865SAlexander Duyck * and co-exist on Ethernet. Current DCB features are: 242f90b865SAlexander Duyck * 252f90b865SAlexander Duyck * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a 262f90b865SAlexander Duyck * framework for assigning bandwidth guarantees to traffic classes. 272f90b865SAlexander Duyck * 282f90b865SAlexander Duyck * Priority-based Flow Control (PFC) - provides a flow control mechanism which 292f90b865SAlexander Duyck * can work independently for each 802.1p priority. 302f90b865SAlexander Duyck * 312f90b865SAlexander Duyck * Congestion Notification - provides a mechanism for end-to-end congestion 322f90b865SAlexander Duyck * control for protocols which do not have built-in congestion management. 332f90b865SAlexander Duyck * 342f90b865SAlexander Duyck * More information about the emerging standards for these Ethernet features 352f90b865SAlexander Duyck * can be found at: http://www.ieee802.org/1/pages/dcbridges.html 362f90b865SAlexander Duyck * 372f90b865SAlexander Duyck * This file implements an rtnetlink interface to allow configuration of DCB 382f90b865SAlexander Duyck * features for capable devices. 392f90b865SAlexander Duyck */ 402f90b865SAlexander Duyck 412f90b865SAlexander Duyck /**************** DCB attribute policies *************************************/ 422f90b865SAlexander Duyck 432f90b865SAlexander Duyck /* DCB netlink attributes policy */ 44b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { 45859ee3c4SAlexander Duyck [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, 462f90b865SAlexander Duyck [DCB_ATTR_STATE] = {.type = NLA_U8}, 472f90b865SAlexander Duyck [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, 482f90b865SAlexander Duyck [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 492f90b865SAlexander Duyck [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 502f90b865SAlexander Duyck [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 5146132188SAlexander Duyck [DCB_ATTR_CAP] = {.type = NLA_NESTED}, 520eb3aa9bSAlexander Duyck [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, 53859ee3c4SAlexander Duyck [DCB_ATTR_BCN] = {.type = NLA_NESTED}, 546fa382afSYi Zou [DCB_ATTR_APP] = {.type = NLA_NESTED}, 553e29027aSJohn Fastabend [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, 566241b625SShmulik Ravid [DCB_ATTR_DCBX] = {.type = NLA_U8}, 57ea45fe4eSShmulik Ravid [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, 582f90b865SAlexander Duyck }; 592f90b865SAlexander Duyck 602f90b865SAlexander Duyck /* DCB priority flow control to User Priority nested attributes */ 61b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { 622f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, 632f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, 642f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, 652f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, 662f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, 672f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, 682f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, 692f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, 702f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, 712f90b865SAlexander Duyck }; 722f90b865SAlexander Duyck 732f90b865SAlexander Duyck /* DCB priority grouping nested attributes */ 74b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { 752f90b865SAlexander Duyck [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, 762f90b865SAlexander Duyck [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, 772f90b865SAlexander Duyck [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, 782f90b865SAlexander Duyck [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, 792f90b865SAlexander Duyck [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, 802f90b865SAlexander Duyck [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, 812f90b865SAlexander Duyck [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, 822f90b865SAlexander Duyck [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, 832f90b865SAlexander Duyck [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, 842f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, 852f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, 862f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, 872f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, 882f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, 892f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, 902f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, 912f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, 922f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, 932f90b865SAlexander Duyck }; 942f90b865SAlexander Duyck 952f90b865SAlexander Duyck /* DCB traffic class nested attributes. */ 96b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { 972f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, 982f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, 992f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, 1002f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, 1012f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 1022f90b865SAlexander Duyck }; 1032f90b865SAlexander Duyck 10446132188SAlexander Duyck /* DCB capabilities nested attributes. */ 105b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { 10646132188SAlexander Duyck [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, 10746132188SAlexander Duyck [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, 10846132188SAlexander Duyck [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, 10946132188SAlexander Duyck [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, 11046132188SAlexander Duyck [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, 11146132188SAlexander Duyck [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, 11246132188SAlexander Duyck [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, 11346132188SAlexander Duyck [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, 1146241b625SShmulik Ravid [DCB_CAP_ATTR_DCBX] = {.type = NLA_U8}, 11546132188SAlexander Duyck }; 1162f90b865SAlexander Duyck 11733dbabc4SAlexander Duyck /* DCB capabilities nested attributes. */ 118b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { 11933dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, 12033dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, 12133dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, 12233dbabc4SAlexander Duyck }; 12333dbabc4SAlexander Duyck 124859ee3c4SAlexander Duyck /* DCB BCN nested attributes. */ 125b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { 126859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, 127859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, 128859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, 129859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, 130859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, 131859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, 132859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, 133859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, 134859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, 135f4314e81SDon Skidmore [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, 136f4314e81SDon Skidmore [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, 137859ee3c4SAlexander Duyck [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, 138859ee3c4SAlexander Duyck [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, 139859ee3c4SAlexander Duyck [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, 140859ee3c4SAlexander Duyck [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, 141859ee3c4SAlexander Duyck [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, 142859ee3c4SAlexander Duyck [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, 143859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, 144859ee3c4SAlexander Duyck [DCB_BCN_ATTR_W] = {.type = NLA_U32}, 145859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, 146859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, 147859ee3c4SAlexander Duyck [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, 148859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, 149859ee3c4SAlexander Duyck [DCB_BCN_ATTR_C] = {.type = NLA_U32}, 150859ee3c4SAlexander Duyck [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, 151859ee3c4SAlexander Duyck }; 152859ee3c4SAlexander Duyck 1536fa382afSYi Zou /* DCB APP nested attributes. */ 154b54452b0SAlexey Dobriyan static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { 1556fa382afSYi Zou [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8}, 1566fa382afSYi Zou [DCB_APP_ATTR_ID] = {.type = NLA_U16}, 1576fa382afSYi Zou [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, 1586fa382afSYi Zou }; 1596fa382afSYi Zou 1603e29027aSJohn Fastabend /* IEEE 802.1Qaz nested attributes. */ 1613e29027aSJohn Fastabend static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { 1623e29027aSJohn Fastabend [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, 1633e29027aSJohn Fastabend [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, 1643e29027aSJohn Fastabend [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, 16508f10affSAmir Vadai [DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)}, 166c9368247SShani Michaeli [DCB_ATTR_IEEE_QCN] = {.len = sizeof(struct ieee_qcn)}, 167c9368247SShani Michaeli [DCB_ATTR_IEEE_QCN_STATS] = {.len = sizeof(struct ieee_qcn_stats)}, 168e549f6f9SHuy Nguyen [DCB_ATTR_DCB_BUFFER] = {.len = sizeof(struct dcbnl_buffer)}, 1693e29027aSJohn Fastabend }; 1703e29027aSJohn Fastabend 171ea45fe4eSShmulik Ravid /* DCB number of traffic classes nested attributes. */ 172ea45fe4eSShmulik Ravid static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { 173ea45fe4eSShmulik Ravid [DCB_FEATCFG_ATTR_ALL] = {.type = NLA_FLAG}, 174ea45fe4eSShmulik Ravid [DCB_FEATCFG_ATTR_PG] = {.type = NLA_U8}, 175ea45fe4eSShmulik Ravid [DCB_FEATCFG_ATTR_PFC] = {.type = NLA_U8}, 176ea45fe4eSShmulik Ravid [DCB_FEATCFG_ATTR_APP] = {.type = NLA_U8}, 177ea45fe4eSShmulik Ravid }; 178ea45fe4eSShmulik Ravid 1799ab933abSJohn Fastabend static LIST_HEAD(dcb_app_list); 1809ab933abSJohn Fastabend static DEFINE_SPINLOCK(dcb_lock); 1819ab933abSJohn Fastabend 18233a03aadSThomas Graf static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq, 18333a03aadSThomas Graf u32 flags, struct nlmsghdr **nlhp) 18433a03aadSThomas Graf { 18533a03aadSThomas Graf struct sk_buff *skb; 18633a03aadSThomas Graf struct dcbmsg *dcb; 18733a03aadSThomas Graf struct nlmsghdr *nlh; 18833a03aadSThomas Graf 18933a03aadSThomas Graf skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 19033a03aadSThomas Graf if (!skb) 19133a03aadSThomas Graf return NULL; 19233a03aadSThomas Graf 19333a03aadSThomas Graf nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags); 194b3908e22SThomas Graf BUG_ON(!nlh); 19533a03aadSThomas Graf 19633a03aadSThomas Graf dcb = nlmsg_data(nlh); 19733a03aadSThomas Graf dcb->dcb_family = AF_UNSPEC; 19833a03aadSThomas Graf dcb->cmd = cmd; 19933a03aadSThomas Graf dcb->dcb_pad = 0; 20033a03aadSThomas Graf 20133a03aadSThomas Graf if (nlhp) 20233a03aadSThomas Graf *nlhp = nlh; 20333a03aadSThomas Graf 20433a03aadSThomas Graf return skb; 20533a03aadSThomas Graf } 20633a03aadSThomas Graf 2077be99413SThomas Graf static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh, 2087be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 2092f90b865SAlexander Duyck { 2102f90b865SAlexander Duyck /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ 2112f90b865SAlexander Duyck if (!netdev->dcbnl_ops->getstate) 2123d1f4869SThomas Graf return -EOPNOTSUPP; 2132f90b865SAlexander Duyck 2147be99413SThomas Graf return nla_put_u8(skb, DCB_ATTR_STATE, 2157be99413SThomas Graf netdev->dcbnl_ops->getstate(netdev)); 2162f90b865SAlexander Duyck } 2172f90b865SAlexander Duyck 2187be99413SThomas Graf static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, 2197be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 2202f90b865SAlexander Duyck { 2212f90b865SAlexander Duyck struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; 2222f90b865SAlexander Duyck u8 value; 2233d1f4869SThomas Graf int ret; 2242f90b865SAlexander Duyck int i; 2252f90b865SAlexander Duyck int getall = 0; 2262f90b865SAlexander Duyck 2273d1f4869SThomas Graf if (!tb[DCB_ATTR_PFC_CFG]) 2283d1f4869SThomas Graf return -EINVAL; 2293d1f4869SThomas Graf 2303d1f4869SThomas Graf if (!netdev->dcbnl_ops->getpfccfg) 2313d1f4869SThomas Graf return -EOPNOTSUPP; 2322f90b865SAlexander Duyck 2338cb08174SJohannes Berg ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX, 2348cb08174SJohannes Berg tb[DCB_ATTR_PFC_CFG], 2358cb08174SJohannes Berg dcbnl_pfc_up_nest, NULL); 2362f90b865SAlexander Duyck if (ret) 2373d1f4869SThomas Graf return ret; 2382f90b865SAlexander Duyck 239ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, DCB_ATTR_PFC_CFG); 2402f90b865SAlexander Duyck if (!nest) 2413d1f4869SThomas Graf return -EMSGSIZE; 2422f90b865SAlexander Duyck 2432f90b865SAlexander Duyck if (data[DCB_PFC_UP_ATTR_ALL]) 2442f90b865SAlexander Duyck getall = 1; 2452f90b865SAlexander Duyck 2462f90b865SAlexander Duyck for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 2472f90b865SAlexander Duyck if (!getall && !data[i]) 2482f90b865SAlexander Duyck continue; 2492f90b865SAlexander Duyck 2502f90b865SAlexander Duyck netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, 2512f90b865SAlexander Duyck &value); 2527be99413SThomas Graf ret = nla_put_u8(skb, i, value); 2532f90b865SAlexander Duyck if (ret) { 2547be99413SThomas Graf nla_nest_cancel(skb, nest); 2553d1f4869SThomas Graf return ret; 2562f90b865SAlexander Duyck } 2572f90b865SAlexander Duyck } 2587be99413SThomas Graf nla_nest_end(skb, nest); 2592f90b865SAlexander Duyck 2602f90b865SAlexander Duyck return 0; 2612f90b865SAlexander Duyck } 2622f90b865SAlexander Duyck 2637be99413SThomas Graf static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh, 2647be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 2652f90b865SAlexander Duyck { 2662f90b865SAlexander Duyck u8 perm_addr[MAX_ADDR_LEN]; 2672f90b865SAlexander Duyck 2682f90b865SAlexander Duyck if (!netdev->dcbnl_ops->getpermhwaddr) 2693d1f4869SThomas Graf return -EOPNOTSUPP; 2702f90b865SAlexander Duyck 27129cd8ae0SMathias Krause memset(perm_addr, 0, sizeof(perm_addr)); 2722f90b865SAlexander Duyck netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); 2732f90b865SAlexander Duyck 2747be99413SThomas Graf return nla_put(skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr); 2752f90b865SAlexander Duyck } 2762f90b865SAlexander Duyck 2777be99413SThomas Graf static int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh, 2787be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 27946132188SAlexander Duyck { 28046132188SAlexander Duyck struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; 28146132188SAlexander Duyck u8 value; 2823d1f4869SThomas Graf int ret; 28346132188SAlexander Duyck int i; 28446132188SAlexander Duyck int getall = 0; 28546132188SAlexander Duyck 2863d1f4869SThomas Graf if (!tb[DCB_ATTR_CAP]) 2873d1f4869SThomas Graf return -EINVAL; 2883d1f4869SThomas Graf 2893d1f4869SThomas Graf if (!netdev->dcbnl_ops->getcap) 2903d1f4869SThomas Graf return -EOPNOTSUPP; 29146132188SAlexander Duyck 2928cb08174SJohannes Berg ret = nla_parse_nested_deprecated(data, DCB_CAP_ATTR_MAX, 2938cb08174SJohannes Berg tb[DCB_ATTR_CAP], dcbnl_cap_nest, 2948cb08174SJohannes Berg NULL); 29546132188SAlexander Duyck if (ret) 2963d1f4869SThomas Graf return ret; 29746132188SAlexander Duyck 298ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, DCB_ATTR_CAP); 29946132188SAlexander Duyck if (!nest) 3003d1f4869SThomas Graf return -EMSGSIZE; 30146132188SAlexander Duyck 30246132188SAlexander Duyck if (data[DCB_CAP_ATTR_ALL]) 30346132188SAlexander Duyck getall = 1; 30446132188SAlexander Duyck 30546132188SAlexander Duyck for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { 30646132188SAlexander Duyck if (!getall && !data[i]) 30746132188SAlexander Duyck continue; 30846132188SAlexander Duyck 30946132188SAlexander Duyck if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { 3107be99413SThomas Graf ret = nla_put_u8(skb, i, value); 31146132188SAlexander Duyck if (ret) { 3127be99413SThomas Graf nla_nest_cancel(skb, nest); 3133d1f4869SThomas Graf return ret; 3147be99413SThomas Graf } 3157be99413SThomas Graf } 3167be99413SThomas Graf } 3177be99413SThomas Graf nla_nest_end(skb, nest); 31846132188SAlexander Duyck 31946132188SAlexander Duyck return 0; 32046132188SAlexander Duyck } 32146132188SAlexander Duyck 3227be99413SThomas Graf static int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, 3237be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 32433dbabc4SAlexander Duyck { 32533dbabc4SAlexander Duyck struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; 32633dbabc4SAlexander Duyck u8 value; 3273d1f4869SThomas Graf int ret; 32833dbabc4SAlexander Duyck int i; 32933dbabc4SAlexander Duyck int getall = 0; 33033dbabc4SAlexander Duyck 3313d1f4869SThomas Graf if (!tb[DCB_ATTR_NUMTCS]) 3323d1f4869SThomas Graf return -EINVAL; 3333d1f4869SThomas Graf 3343d1f4869SThomas Graf if (!netdev->dcbnl_ops->getnumtcs) 3353d1f4869SThomas Graf return -EOPNOTSUPP; 33633dbabc4SAlexander Duyck 3378cb08174SJohannes Berg ret = nla_parse_nested_deprecated(data, DCB_NUMTCS_ATTR_MAX, 3388cb08174SJohannes Berg tb[DCB_ATTR_NUMTCS], 339fceb6435SJohannes Berg dcbnl_numtcs_nest, NULL); 3403d1f4869SThomas Graf if (ret) 3413d1f4869SThomas Graf return ret; 34233dbabc4SAlexander Duyck 343ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, DCB_ATTR_NUMTCS); 3443d1f4869SThomas Graf if (!nest) 3453d1f4869SThomas Graf return -EMSGSIZE; 34633dbabc4SAlexander Duyck 34733dbabc4SAlexander Duyck if (data[DCB_NUMTCS_ATTR_ALL]) 34833dbabc4SAlexander Duyck getall = 1; 34933dbabc4SAlexander Duyck 35033dbabc4SAlexander Duyck for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 35133dbabc4SAlexander Duyck if (!getall && !data[i]) 35233dbabc4SAlexander Duyck continue; 35333dbabc4SAlexander Duyck 35433dbabc4SAlexander Duyck ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); 35533dbabc4SAlexander Duyck if (!ret) { 3567be99413SThomas Graf ret = nla_put_u8(skb, i, value); 35733dbabc4SAlexander Duyck if (ret) { 3587be99413SThomas Graf nla_nest_cancel(skb, nest); 3593d1f4869SThomas Graf return ret; 36033dbabc4SAlexander Duyck } 3613d1f4869SThomas Graf } else 3623d1f4869SThomas Graf return -EINVAL; 3637be99413SThomas Graf } 3647be99413SThomas Graf nla_nest_end(skb, nest); 36533dbabc4SAlexander Duyck 36633dbabc4SAlexander Duyck return 0; 36733dbabc4SAlexander Duyck } 36833dbabc4SAlexander Duyck 3697be99413SThomas Graf static int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, 3707be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 37133dbabc4SAlexander Duyck { 37233dbabc4SAlexander Duyck struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; 3733d1f4869SThomas Graf int ret; 37433dbabc4SAlexander Duyck u8 value; 37533dbabc4SAlexander Duyck int i; 37633dbabc4SAlexander Duyck 3773d1f4869SThomas Graf if (!tb[DCB_ATTR_NUMTCS]) 3783d1f4869SThomas Graf return -EINVAL; 3793d1f4869SThomas Graf 3803d1f4869SThomas Graf if (!netdev->dcbnl_ops->setnumtcs) 3813d1f4869SThomas Graf return -EOPNOTSUPP; 38233dbabc4SAlexander Duyck 3838cb08174SJohannes Berg ret = nla_parse_nested_deprecated(data, DCB_NUMTCS_ATTR_MAX, 3848cb08174SJohannes Berg tb[DCB_ATTR_NUMTCS], 385fceb6435SJohannes Berg dcbnl_numtcs_nest, NULL); 3867be99413SThomas Graf if (ret) 3873d1f4869SThomas Graf return ret; 38833dbabc4SAlexander Duyck 38933dbabc4SAlexander Duyck for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 39033dbabc4SAlexander Duyck if (data[i] == NULL) 39133dbabc4SAlexander Duyck continue; 39233dbabc4SAlexander Duyck 39333dbabc4SAlexander Duyck value = nla_get_u8(data[i]); 39433dbabc4SAlexander Duyck 39533dbabc4SAlexander Duyck ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); 39633dbabc4SAlexander Duyck if (ret) 3977be99413SThomas Graf break; 39833dbabc4SAlexander Duyck } 39933dbabc4SAlexander Duyck 4007be99413SThomas Graf return nla_put_u8(skb, DCB_ATTR_NUMTCS, !!ret); 40133dbabc4SAlexander Duyck } 40233dbabc4SAlexander Duyck 4037be99413SThomas Graf static int dcbnl_getpfcstate(struct net_device *netdev, struct nlmsghdr *nlh, 4047be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 4050eb3aa9bSAlexander Duyck { 4060eb3aa9bSAlexander Duyck if (!netdev->dcbnl_ops->getpfcstate) 4073d1f4869SThomas Graf return -EOPNOTSUPP; 4080eb3aa9bSAlexander Duyck 4097be99413SThomas Graf return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 4107be99413SThomas Graf netdev->dcbnl_ops->getpfcstate(netdev)); 4110eb3aa9bSAlexander Duyck } 4120eb3aa9bSAlexander Duyck 4137be99413SThomas Graf static int dcbnl_setpfcstate(struct net_device *netdev, struct nlmsghdr *nlh, 4147be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 4150eb3aa9bSAlexander Duyck { 4160eb3aa9bSAlexander Duyck u8 value; 4170eb3aa9bSAlexander Duyck 4183d1f4869SThomas Graf if (!tb[DCB_ATTR_PFC_STATE]) 4197be99413SThomas Graf return -EINVAL; 4200eb3aa9bSAlexander Duyck 4213d1f4869SThomas Graf if (!netdev->dcbnl_ops->setpfcstate) 4223d1f4869SThomas Graf return -EOPNOTSUPP; 4233d1f4869SThomas Graf 4240eb3aa9bSAlexander Duyck value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); 4250eb3aa9bSAlexander Duyck 4260eb3aa9bSAlexander Duyck netdev->dcbnl_ops->setpfcstate(netdev, value); 4270eb3aa9bSAlexander Duyck 4287be99413SThomas Graf return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 0); 4290eb3aa9bSAlexander Duyck } 4300eb3aa9bSAlexander Duyck 4317be99413SThomas Graf static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh, 4327be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 43357949686SYi Zou { 43457949686SYi Zou struct nlattr *app_nest; 43557949686SYi Zou struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 43657949686SYi Zou u16 id; 43757949686SYi Zou u8 up, idtype; 4383d1f4869SThomas Graf int ret; 43957949686SYi Zou 4403dce38a0SJohn Fastabend if (!tb[DCB_ATTR_APP]) 4413d1f4869SThomas Graf return -EINVAL; 44257949686SYi Zou 4438cb08174SJohannes Berg ret = nla_parse_nested_deprecated(app_tb, DCB_APP_ATTR_MAX, 4448cb08174SJohannes Berg tb[DCB_ATTR_APP], dcbnl_app_nest, 4458cb08174SJohannes Berg NULL); 44657949686SYi Zou if (ret) 4473d1f4869SThomas Graf return ret; 44857949686SYi Zou 44957949686SYi Zou /* all must be non-null */ 45057949686SYi Zou if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 45157949686SYi Zou (!app_tb[DCB_APP_ATTR_ID])) 4523d1f4869SThomas Graf return -EINVAL; 45357949686SYi Zou 45457949686SYi Zou /* either by eth type or by socket number */ 45557949686SYi Zou idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 45657949686SYi Zou if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 45757949686SYi Zou (idtype != DCB_APP_IDTYPE_PORTNUM)) 4583d1f4869SThomas Graf return -EINVAL; 45957949686SYi Zou 46057949686SYi Zou id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 4613dce38a0SJohn Fastabend 4623dce38a0SJohn Fastabend if (netdev->dcbnl_ops->getapp) { 463c2659479SAnish Bhatt ret = netdev->dcbnl_ops->getapp(netdev, idtype, id); 464c2659479SAnish Bhatt if (ret < 0) 465c2659479SAnish Bhatt return ret; 466c2659479SAnish Bhatt else 467c2659479SAnish Bhatt up = ret; 4683dce38a0SJohn Fastabend } else { 4693dce38a0SJohn Fastabend struct dcb_app app = { 4703dce38a0SJohn Fastabend .selector = idtype, 4713dce38a0SJohn Fastabend .protocol = id, 4723dce38a0SJohn Fastabend }; 4733dce38a0SJohn Fastabend up = dcb_getapp(netdev, &app); 4743dce38a0SJohn Fastabend } 47557949686SYi Zou 476ae0be8deSMichal Kubecek app_nest = nla_nest_start_noflag(skb, DCB_ATTR_APP); 4777be99413SThomas Graf if (!app_nest) 4783d1f4869SThomas Graf return -EMSGSIZE; 47957949686SYi Zou 4807be99413SThomas Graf ret = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, idtype); 48157949686SYi Zou if (ret) 48257949686SYi Zou goto out_cancel; 48357949686SYi Zou 4847be99413SThomas Graf ret = nla_put_u16(skb, DCB_APP_ATTR_ID, id); 48557949686SYi Zou if (ret) 48657949686SYi Zou goto out_cancel; 48757949686SYi Zou 4887be99413SThomas Graf ret = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, up); 48957949686SYi Zou if (ret) 49057949686SYi Zou goto out_cancel; 49157949686SYi Zou 4927be99413SThomas Graf nla_nest_end(skb, app_nest); 49357949686SYi Zou 4943d1f4869SThomas Graf return 0; 49557949686SYi Zou 49657949686SYi Zou out_cancel: 4977be99413SThomas Graf nla_nest_cancel(skb, app_nest); 49857949686SYi Zou return ret; 49957949686SYi Zou } 50057949686SYi Zou 5017be99413SThomas Graf static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh, 5027be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 50357949686SYi Zou { 5043d1f4869SThomas Graf int ret; 50557949686SYi Zou u16 id; 50657949686SYi Zou u8 up, idtype; 50757949686SYi Zou struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 50857949686SYi Zou 5099ab933abSJohn Fastabend if (!tb[DCB_ATTR_APP]) 5103d1f4869SThomas Graf return -EINVAL; 51157949686SYi Zou 5128cb08174SJohannes Berg ret = nla_parse_nested_deprecated(app_tb, DCB_APP_ATTR_MAX, 5138cb08174SJohannes Berg tb[DCB_ATTR_APP], dcbnl_app_nest, 5148cb08174SJohannes Berg NULL); 51557949686SYi Zou if (ret) 5163d1f4869SThomas Graf return ret; 51757949686SYi Zou 51857949686SYi Zou /* all must be non-null */ 51957949686SYi Zou if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 52057949686SYi Zou (!app_tb[DCB_APP_ATTR_ID]) || 52157949686SYi Zou (!app_tb[DCB_APP_ATTR_PRIORITY])) 5223d1f4869SThomas Graf return -EINVAL; 52357949686SYi Zou 52457949686SYi Zou /* either by eth type or by socket number */ 52557949686SYi Zou idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 52657949686SYi Zou if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 52757949686SYi Zou (idtype != DCB_APP_IDTYPE_PORTNUM)) 5283d1f4869SThomas Graf return -EINVAL; 52957949686SYi Zou 53057949686SYi Zou id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 53157949686SYi Zou up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); 53257949686SYi Zou 5339ab933abSJohn Fastabend if (netdev->dcbnl_ops->setapp) { 5343d1f4869SThomas Graf ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); 535c2659479SAnish Bhatt if (ret < 0) 536c2659479SAnish Bhatt return ret; 5379ab933abSJohn Fastabend } else { 5389ab933abSJohn Fastabend struct dcb_app app; 5399ab933abSJohn Fastabend app.selector = idtype; 5409ab933abSJohn Fastabend app.protocol = id; 5419ab933abSJohn Fastabend app.priority = up; 5423d1f4869SThomas Graf ret = dcb_setapp(netdev, &app); 5439ab933abSJohn Fastabend } 5449ab933abSJohn Fastabend 5457be99413SThomas Graf ret = nla_put_u8(skb, DCB_ATTR_APP, ret); 54608157984SJohn Fastabend dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0); 5473d1f4869SThomas Graf 54857949686SYi Zou return ret; 54957949686SYi Zou } 55057949686SYi Zou 5517be99413SThomas Graf static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 5527be99413SThomas Graf struct nlattr **tb, struct sk_buff *skb, int dir) 5532f90b865SAlexander Duyck { 5542f90b865SAlexander Duyck struct nlattr *pg_nest, *param_nest, *data; 5552f90b865SAlexander Duyck struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 5562f90b865SAlexander Duyck struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 5572f90b865SAlexander Duyck u8 prio, pgid, tc_pct, up_map; 5583d1f4869SThomas Graf int ret; 5592f90b865SAlexander Duyck int getall = 0; 5602f90b865SAlexander Duyck int i; 5612f90b865SAlexander Duyck 5623d1f4869SThomas Graf if (!tb[DCB_ATTR_PG_CFG]) 5633d1f4869SThomas Graf return -EINVAL; 5643d1f4869SThomas Graf 5653d1f4869SThomas Graf if (!netdev->dcbnl_ops->getpgtccfgtx || 5662f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgtccfgrx || 5672f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgbwgcfgtx || 5682f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgbwgcfgrx) 5693d1f4869SThomas Graf return -EOPNOTSUPP; 5702f90b865SAlexander Duyck 5718cb08174SJohannes Berg ret = nla_parse_nested_deprecated(pg_tb, DCB_PG_ATTR_MAX, 5728cb08174SJohannes Berg tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest, 5738cb08174SJohannes Berg NULL); 5742f90b865SAlexander Duyck if (ret) 5753d1f4869SThomas Graf return ret; 5762f90b865SAlexander Duyck 577ae0be8deSMichal Kubecek pg_nest = nla_nest_start_noflag(skb, DCB_ATTR_PG_CFG); 5782f90b865SAlexander Duyck if (!pg_nest) 5793d1f4869SThomas Graf return -EMSGSIZE; 5802f90b865SAlexander Duyck 5812f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_TC_ALL]) 5822f90b865SAlexander Duyck getall = 1; 5832f90b865SAlexander Duyck 5842f90b865SAlexander Duyck for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 5852f90b865SAlexander Duyck if (!getall && !pg_tb[i]) 5862f90b865SAlexander Duyck continue; 5872f90b865SAlexander Duyck 5882f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_TC_ALL]) 5892f90b865SAlexander Duyck data = pg_tb[DCB_PG_ATTR_TC_ALL]; 5902f90b865SAlexander Duyck else 5912f90b865SAlexander Duyck data = pg_tb[i]; 5928cb08174SJohannes Berg ret = nla_parse_nested_deprecated(param_tb, 5938cb08174SJohannes Berg DCB_TC_ATTR_PARAM_MAX, data, 594fceb6435SJohannes Berg dcbnl_tc_param_nest, NULL); 5952f90b865SAlexander Duyck if (ret) 5962f90b865SAlexander Duyck goto err_pg; 5972f90b865SAlexander Duyck 598ae0be8deSMichal Kubecek param_nest = nla_nest_start_noflag(skb, i); 5992f90b865SAlexander Duyck if (!param_nest) 6002f90b865SAlexander Duyck goto err_pg; 6012f90b865SAlexander Duyck 6022f90b865SAlexander Duyck pgid = DCB_ATTR_VALUE_UNDEFINED; 6032f90b865SAlexander Duyck prio = DCB_ATTR_VALUE_UNDEFINED; 6042f90b865SAlexander Duyck tc_pct = DCB_ATTR_VALUE_UNDEFINED; 6052f90b865SAlexander Duyck up_map = DCB_ATTR_VALUE_UNDEFINED; 6062f90b865SAlexander Duyck 6072f90b865SAlexander Duyck if (dir) { 6082f90b865SAlexander Duyck /* Rx */ 6092f90b865SAlexander Duyck netdev->dcbnl_ops->getpgtccfgrx(netdev, 6102f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, &prio, 6112f90b865SAlexander Duyck &pgid, &tc_pct, &up_map); 6122f90b865SAlexander Duyck } else { 6132f90b865SAlexander Duyck /* Tx */ 6142f90b865SAlexander Duyck netdev->dcbnl_ops->getpgtccfgtx(netdev, 6152f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, &prio, 6162f90b865SAlexander Duyck &pgid, &tc_pct, &up_map); 6172f90b865SAlexander Duyck } 6182f90b865SAlexander Duyck 6192f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_PGID] || 6202f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 6217be99413SThomas Graf ret = nla_put_u8(skb, 6222f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_PGID, pgid); 6232f90b865SAlexander Duyck if (ret) 6242f90b865SAlexander Duyck goto err_param; 6252f90b865SAlexander Duyck } 6262f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || 6272f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 6287be99413SThomas Graf ret = nla_put_u8(skb, 6292f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); 6302f90b865SAlexander Duyck if (ret) 6312f90b865SAlexander Duyck goto err_param; 6322f90b865SAlexander Duyck } 6332f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || 6342f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 6357be99413SThomas Graf ret = nla_put_u8(skb, 6362f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); 6372f90b865SAlexander Duyck if (ret) 6382f90b865SAlexander Duyck goto err_param; 6392f90b865SAlexander Duyck } 6402f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || 6412f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 6427be99413SThomas Graf ret = nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, 6432f90b865SAlexander Duyck tc_pct); 6442f90b865SAlexander Duyck if (ret) 6452f90b865SAlexander Duyck goto err_param; 6462f90b865SAlexander Duyck } 6477be99413SThomas Graf nla_nest_end(skb, param_nest); 6482f90b865SAlexander Duyck } 6492f90b865SAlexander Duyck 6502f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) 6512f90b865SAlexander Duyck getall = 1; 6522f90b865SAlexander Duyck else 6532f90b865SAlexander Duyck getall = 0; 6542f90b865SAlexander Duyck 6552f90b865SAlexander Duyck for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 6562f90b865SAlexander Duyck if (!getall && !pg_tb[i]) 6572f90b865SAlexander Duyck continue; 6582f90b865SAlexander Duyck 6592f90b865SAlexander Duyck tc_pct = DCB_ATTR_VALUE_UNDEFINED; 6602f90b865SAlexander Duyck 6612f90b865SAlexander Duyck if (dir) { 6622f90b865SAlexander Duyck /* Rx */ 6632f90b865SAlexander Duyck netdev->dcbnl_ops->getpgbwgcfgrx(netdev, 6642f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 6652f90b865SAlexander Duyck } else { 6662f90b865SAlexander Duyck /* Tx */ 6672f90b865SAlexander Duyck netdev->dcbnl_ops->getpgbwgcfgtx(netdev, 6682f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 6692f90b865SAlexander Duyck } 6707be99413SThomas Graf ret = nla_put_u8(skb, i, tc_pct); 6712f90b865SAlexander Duyck if (ret) 6722f90b865SAlexander Duyck goto err_pg; 6732f90b865SAlexander Duyck } 6742f90b865SAlexander Duyck 6757be99413SThomas Graf nla_nest_end(skb, pg_nest); 6762f90b865SAlexander Duyck 6772f90b865SAlexander Duyck return 0; 6782f90b865SAlexander Duyck 6792f90b865SAlexander Duyck err_param: 6807be99413SThomas Graf nla_nest_cancel(skb, param_nest); 6812f90b865SAlexander Duyck err_pg: 6827be99413SThomas Graf nla_nest_cancel(skb, pg_nest); 6833d1f4869SThomas Graf 6843d1f4869SThomas Graf return -EMSGSIZE; 6852f90b865SAlexander Duyck } 6862f90b865SAlexander Duyck 6877be99413SThomas Graf static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 6887be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 6892f90b865SAlexander Duyck { 6907be99413SThomas Graf return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 0); 6912f90b865SAlexander Duyck } 6922f90b865SAlexander Duyck 6937be99413SThomas Graf static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 6947be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 6952f90b865SAlexander Duyck { 6967be99413SThomas Graf return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 1); 6972f90b865SAlexander Duyck } 6982f90b865SAlexander Duyck 6997be99413SThomas Graf static int dcbnl_setstate(struct net_device *netdev, struct nlmsghdr *nlh, 7007be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 7012f90b865SAlexander Duyck { 7022f90b865SAlexander Duyck u8 value; 7032f90b865SAlexander Duyck 7043d1f4869SThomas Graf if (!tb[DCB_ATTR_STATE]) 7057be99413SThomas Graf return -EINVAL; 7062f90b865SAlexander Duyck 7073d1f4869SThomas Graf if (!netdev->dcbnl_ops->setstate) 7083d1f4869SThomas Graf return -EOPNOTSUPP; 7093d1f4869SThomas Graf 7102f90b865SAlexander Duyck value = nla_get_u8(tb[DCB_ATTR_STATE]); 7112f90b865SAlexander Duyck 7127be99413SThomas Graf return nla_put_u8(skb, DCB_ATTR_STATE, 7137be99413SThomas Graf netdev->dcbnl_ops->setstate(netdev, value)); 7142f90b865SAlexander Duyck } 7152f90b865SAlexander Duyck 7167be99413SThomas Graf static int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, 7177be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 7182f90b865SAlexander Duyck { 7192f90b865SAlexander Duyck struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; 7202f90b865SAlexander Duyck int i; 7213d1f4869SThomas Graf int ret; 7222f90b865SAlexander Duyck u8 value; 7232f90b865SAlexander Duyck 7243d1f4869SThomas Graf if (!tb[DCB_ATTR_PFC_CFG]) 7253d1f4869SThomas Graf return -EINVAL; 7263d1f4869SThomas Graf 7273d1f4869SThomas Graf if (!netdev->dcbnl_ops->setpfccfg) 7283d1f4869SThomas Graf return -EOPNOTSUPP; 7292f90b865SAlexander Duyck 7308cb08174SJohannes Berg ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX, 7318cb08174SJohannes Berg tb[DCB_ATTR_PFC_CFG], 7328cb08174SJohannes Berg dcbnl_pfc_up_nest, NULL); 7332f90b865SAlexander Duyck if (ret) 7343d1f4869SThomas Graf return ret; 7352f90b865SAlexander Duyck 7362f90b865SAlexander Duyck for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 7372f90b865SAlexander Duyck if (data[i] == NULL) 7382f90b865SAlexander Duyck continue; 7392f90b865SAlexander Duyck value = nla_get_u8(data[i]); 7402f90b865SAlexander Duyck netdev->dcbnl_ops->setpfccfg(netdev, 7412f90b865SAlexander Duyck data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); 7422f90b865SAlexander Duyck } 7432f90b865SAlexander Duyck 7447be99413SThomas Graf return nla_put_u8(skb, DCB_ATTR_PFC_CFG, 0); 7452f90b865SAlexander Duyck } 7462f90b865SAlexander Duyck 7477be99413SThomas Graf static int dcbnl_setall(struct net_device *netdev, struct nlmsghdr *nlh, 7487be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 7492f90b865SAlexander Duyck { 7503d1f4869SThomas Graf int ret; 7512f90b865SAlexander Duyck 7523d1f4869SThomas Graf if (!tb[DCB_ATTR_SET_ALL]) 7533d1f4869SThomas Graf return -EINVAL; 7543d1f4869SThomas Graf 7553d1f4869SThomas Graf if (!netdev->dcbnl_ops->setall) 7563d1f4869SThomas Graf return -EOPNOTSUPP; 7572f90b865SAlexander Duyck 7587be99413SThomas Graf ret = nla_put_u8(skb, DCB_ATTR_SET_ALL, 7597be99413SThomas Graf netdev->dcbnl_ops->setall(netdev)); 76008157984SJohn Fastabend dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0); 7612f90b865SAlexander Duyck 7622f90b865SAlexander Duyck return ret; 7632f90b865SAlexander Duyck } 7642f90b865SAlexander Duyck 7657be99413SThomas Graf static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 7667be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb, 7677be99413SThomas Graf int dir) 7682f90b865SAlexander Duyck { 7692f90b865SAlexander Duyck struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 7702f90b865SAlexander Duyck struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 7713d1f4869SThomas Graf int ret; 7722f90b865SAlexander Duyck int i; 7732f90b865SAlexander Duyck u8 pgid; 7742f90b865SAlexander Duyck u8 up_map; 7752f90b865SAlexander Duyck u8 prio; 7762f90b865SAlexander Duyck u8 tc_pct; 7772f90b865SAlexander Duyck 7783d1f4869SThomas Graf if (!tb[DCB_ATTR_PG_CFG]) 7793d1f4869SThomas Graf return -EINVAL; 7803d1f4869SThomas Graf 7813d1f4869SThomas Graf if (!netdev->dcbnl_ops->setpgtccfgtx || 7822f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgtccfgrx || 7832f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgbwgcfgtx || 7842f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgbwgcfgrx) 7853d1f4869SThomas Graf return -EOPNOTSUPP; 7862f90b865SAlexander Duyck 7878cb08174SJohannes Berg ret = nla_parse_nested_deprecated(pg_tb, DCB_PG_ATTR_MAX, 7888cb08174SJohannes Berg tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest, 7898cb08174SJohannes Berg NULL); 7902f90b865SAlexander Duyck if (ret) 7913d1f4869SThomas Graf return ret; 7922f90b865SAlexander Duyck 7932f90b865SAlexander Duyck for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 7942f90b865SAlexander Duyck if (!pg_tb[i]) 7952f90b865SAlexander Duyck continue; 7962f90b865SAlexander Duyck 7978cb08174SJohannes Berg ret = nla_parse_nested_deprecated(param_tb, 7988cb08174SJohannes Berg DCB_TC_ATTR_PARAM_MAX, 7998cb08174SJohannes Berg pg_tb[i], 8008cb08174SJohannes Berg dcbnl_tc_param_nest, NULL); 8012f90b865SAlexander Duyck if (ret) 8023d1f4869SThomas Graf return ret; 8032f90b865SAlexander Duyck 8042f90b865SAlexander Duyck pgid = DCB_ATTR_VALUE_UNDEFINED; 8052f90b865SAlexander Duyck prio = DCB_ATTR_VALUE_UNDEFINED; 8062f90b865SAlexander Duyck tc_pct = DCB_ATTR_VALUE_UNDEFINED; 8072f90b865SAlexander Duyck up_map = DCB_ATTR_VALUE_UNDEFINED; 8082f90b865SAlexander Duyck 8092f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]) 8102f90b865SAlexander Duyck prio = 8112f90b865SAlexander Duyck nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]); 8122f90b865SAlexander Duyck 8132f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_PGID]) 8142f90b865SAlexander Duyck pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]); 8152f90b865SAlexander Duyck 8162f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT]) 8172f90b865SAlexander Duyck tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]); 8182f90b865SAlexander Duyck 8192f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]) 8202f90b865SAlexander Duyck up_map = 8212f90b865SAlexander Duyck nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]); 8222f90b865SAlexander Duyck 8232f90b865SAlexander Duyck /* dir: Tx = 0, Rx = 1 */ 8242f90b865SAlexander Duyck if (dir) { 8252f90b865SAlexander Duyck /* Rx */ 8262f90b865SAlexander Duyck netdev->dcbnl_ops->setpgtccfgrx(netdev, 8272f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, 8282f90b865SAlexander Duyck prio, pgid, tc_pct, up_map); 8292f90b865SAlexander Duyck } else { 8302f90b865SAlexander Duyck /* Tx */ 8312f90b865SAlexander Duyck netdev->dcbnl_ops->setpgtccfgtx(netdev, 8322f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, 8332f90b865SAlexander Duyck prio, pgid, tc_pct, up_map); 8342f90b865SAlexander Duyck } 8352f90b865SAlexander Duyck } 8362f90b865SAlexander Duyck 8372f90b865SAlexander Duyck for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 8382f90b865SAlexander Duyck if (!pg_tb[i]) 8392f90b865SAlexander Duyck continue; 8402f90b865SAlexander Duyck 8412f90b865SAlexander Duyck tc_pct = nla_get_u8(pg_tb[i]); 8422f90b865SAlexander Duyck 8432f90b865SAlexander Duyck /* dir: Tx = 0, Rx = 1 */ 8442f90b865SAlexander Duyck if (dir) { 8452f90b865SAlexander Duyck /* Rx */ 8462f90b865SAlexander Duyck netdev->dcbnl_ops->setpgbwgcfgrx(netdev, 8472f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, tc_pct); 8482f90b865SAlexander Duyck } else { 8492f90b865SAlexander Duyck /* Tx */ 8502f90b865SAlexander Duyck netdev->dcbnl_ops->setpgbwgcfgtx(netdev, 8512f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, tc_pct); 8522f90b865SAlexander Duyck } 8532f90b865SAlexander Duyck } 8542f90b865SAlexander Duyck 855bb1dfefdSJohn Fastabend return nla_put_u8(skb, DCB_ATTR_PG_CFG, 0); 8562f90b865SAlexander Duyck } 8572f90b865SAlexander Duyck 8587be99413SThomas Graf static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 8597be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 8602f90b865SAlexander Duyck { 8617be99413SThomas Graf return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 0); 8622f90b865SAlexander Duyck } 8632f90b865SAlexander Duyck 8647be99413SThomas Graf static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 8657be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 8662f90b865SAlexander Duyck { 8677be99413SThomas Graf return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 1); 8682f90b865SAlexander Duyck } 8692f90b865SAlexander Duyck 8707be99413SThomas Graf static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 8717be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 872859ee3c4SAlexander Duyck { 873859ee3c4SAlexander Duyck struct nlattr *bcn_nest; 874859ee3c4SAlexander Duyck struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; 875859ee3c4SAlexander Duyck u8 value_byte; 876859ee3c4SAlexander Duyck u32 value_integer; 8773d1f4869SThomas Graf int ret; 878859ee3c4SAlexander Duyck bool getall = false; 879859ee3c4SAlexander Duyck int i; 880859ee3c4SAlexander Duyck 8813d1f4869SThomas Graf if (!tb[DCB_ATTR_BCN]) 8823d1f4869SThomas Graf return -EINVAL; 8833d1f4869SThomas Graf 8843d1f4869SThomas Graf if (!netdev->dcbnl_ops->getbcnrp || 885859ee3c4SAlexander Duyck !netdev->dcbnl_ops->getbcncfg) 8863d1f4869SThomas Graf return -EOPNOTSUPP; 887859ee3c4SAlexander Duyck 8888cb08174SJohannes Berg ret = nla_parse_nested_deprecated(bcn_tb, DCB_BCN_ATTR_MAX, 8898cb08174SJohannes Berg tb[DCB_ATTR_BCN], dcbnl_bcn_nest, 8908cb08174SJohannes Berg NULL); 891859ee3c4SAlexander Duyck if (ret) 8923d1f4869SThomas Graf return ret; 893859ee3c4SAlexander Duyck 894ae0be8deSMichal Kubecek bcn_nest = nla_nest_start_noflag(skb, DCB_ATTR_BCN); 895859ee3c4SAlexander Duyck if (!bcn_nest) 8963d1f4869SThomas Graf return -EMSGSIZE; 897859ee3c4SAlexander Duyck 898859ee3c4SAlexander Duyck if (bcn_tb[DCB_BCN_ATTR_ALL]) 899859ee3c4SAlexander Duyck getall = true; 900859ee3c4SAlexander Duyck 901859ee3c4SAlexander Duyck for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 902859ee3c4SAlexander Duyck if (!getall && !bcn_tb[i]) 903859ee3c4SAlexander Duyck continue; 904859ee3c4SAlexander Duyck 905859ee3c4SAlexander Duyck netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, 906859ee3c4SAlexander Duyck &value_byte); 9077be99413SThomas Graf ret = nla_put_u8(skb, i, value_byte); 908859ee3c4SAlexander Duyck if (ret) 909859ee3c4SAlexander Duyck goto err_bcn; 910859ee3c4SAlexander Duyck } 911859ee3c4SAlexander Duyck 912f4314e81SDon Skidmore for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 913859ee3c4SAlexander Duyck if (!getall && !bcn_tb[i]) 914859ee3c4SAlexander Duyck continue; 915859ee3c4SAlexander Duyck 916859ee3c4SAlexander Duyck netdev->dcbnl_ops->getbcncfg(netdev, i, 917859ee3c4SAlexander Duyck &value_integer); 9187be99413SThomas Graf ret = nla_put_u32(skb, i, value_integer); 919859ee3c4SAlexander Duyck if (ret) 920859ee3c4SAlexander Duyck goto err_bcn; 921859ee3c4SAlexander Duyck } 922859ee3c4SAlexander Duyck 9237be99413SThomas Graf nla_nest_end(skb, bcn_nest); 924859ee3c4SAlexander Duyck 925859ee3c4SAlexander Duyck return 0; 926859ee3c4SAlexander Duyck 927859ee3c4SAlexander Duyck err_bcn: 9287be99413SThomas Graf nla_nest_cancel(skb, bcn_nest); 929859ee3c4SAlexander Duyck return ret; 930859ee3c4SAlexander Duyck } 931859ee3c4SAlexander Duyck 9327be99413SThomas Graf static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 9337be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 934859ee3c4SAlexander Duyck { 935859ee3c4SAlexander Duyck struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; 936859ee3c4SAlexander Duyck int i; 9373d1f4869SThomas Graf int ret; 938859ee3c4SAlexander Duyck u8 value_byte; 939859ee3c4SAlexander Duyck u32 value_int; 940859ee3c4SAlexander Duyck 9413d1f4869SThomas Graf if (!tb[DCB_ATTR_BCN]) 9423d1f4869SThomas Graf return -EINVAL; 9433d1f4869SThomas Graf 9443d1f4869SThomas Graf if (!netdev->dcbnl_ops->setbcncfg || 945f64f9e71SJoe Perches !netdev->dcbnl_ops->setbcnrp) 9463d1f4869SThomas Graf return -EOPNOTSUPP; 947859ee3c4SAlexander Duyck 9488cb08174SJohannes Berg ret = nla_parse_nested_deprecated(data, DCB_BCN_ATTR_MAX, 9498cb08174SJohannes Berg tb[DCB_ATTR_BCN], dcbnl_pfc_up_nest, 9508cb08174SJohannes Berg NULL); 951859ee3c4SAlexander Duyck if (ret) 9523d1f4869SThomas Graf return ret; 953859ee3c4SAlexander Duyck 954859ee3c4SAlexander Duyck for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 955859ee3c4SAlexander Duyck if (data[i] == NULL) 956859ee3c4SAlexander Duyck continue; 957859ee3c4SAlexander Duyck value_byte = nla_get_u8(data[i]); 958859ee3c4SAlexander Duyck netdev->dcbnl_ops->setbcnrp(netdev, 959859ee3c4SAlexander Duyck data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); 960859ee3c4SAlexander Duyck } 961859ee3c4SAlexander Duyck 962f4314e81SDon Skidmore for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 963859ee3c4SAlexander Duyck if (data[i] == NULL) 964859ee3c4SAlexander Duyck continue; 965859ee3c4SAlexander Duyck value_int = nla_get_u32(data[i]); 966859ee3c4SAlexander Duyck netdev->dcbnl_ops->setbcncfg(netdev, 967859ee3c4SAlexander Duyck i, value_int); 968859ee3c4SAlexander Duyck } 969859ee3c4SAlexander Duyck 9703d1f4869SThomas Graf return nla_put_u8(skb, DCB_ATTR_BCN, 0); 971859ee3c4SAlexander Duyck } 972859ee3c4SAlexander Duyck 973dc6ed1dfSShmulik Ravid static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, 974dc6ed1dfSShmulik Ravid int app_nested_type, int app_info_type, 975dc6ed1dfSShmulik Ravid int app_entry_type) 976eed84713SShmulik Ravid { 977eed84713SShmulik Ravid struct dcb_peer_app_info info; 978eed84713SShmulik Ravid struct dcb_app *table = NULL; 979eed84713SShmulik Ravid const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 980eed84713SShmulik Ravid u16 app_count; 981eed84713SShmulik Ravid int err; 982eed84713SShmulik Ravid 983eed84713SShmulik Ravid 984eed84713SShmulik Ravid /** 985eed84713SShmulik Ravid * retrieve the peer app configuration form the driver. If the driver 986eed84713SShmulik Ravid * handlers fail exit without doing anything 987eed84713SShmulik Ravid */ 988eed84713SShmulik Ravid err = ops->peer_getappinfo(netdev, &info, &app_count); 989eed84713SShmulik Ravid if (!err && app_count) { 9906da2ec56SKees Cook table = kmalloc_array(app_count, sizeof(struct dcb_app), 9916da2ec56SKees Cook GFP_KERNEL); 992eed84713SShmulik Ravid if (!table) 993eed84713SShmulik Ravid return -ENOMEM; 994eed84713SShmulik Ravid 995eed84713SShmulik Ravid err = ops->peer_getapptable(netdev, table); 996eed84713SShmulik Ravid } 997eed84713SShmulik Ravid 998eed84713SShmulik Ravid if (!err) { 999eed84713SShmulik Ravid u16 i; 1000eed84713SShmulik Ravid struct nlattr *app; 1001eed84713SShmulik Ravid 1002eed84713SShmulik Ravid /** 1003eed84713SShmulik Ravid * build the message, from here on the only possible failure 1004eed84713SShmulik Ravid * is due to the skb size 1005eed84713SShmulik Ravid */ 1006eed84713SShmulik Ravid err = -EMSGSIZE; 1007eed84713SShmulik Ravid 1008ae0be8deSMichal Kubecek app = nla_nest_start_noflag(skb, app_nested_type); 1009eed84713SShmulik Ravid if (!app) 1010eed84713SShmulik Ravid goto nla_put_failure; 1011eed84713SShmulik Ravid 10121eb4c977SDavid S. Miller if (app_info_type && 10131eb4c977SDavid S. Miller nla_put(skb, app_info_type, sizeof(info), &info)) 10141eb4c977SDavid S. Miller goto nla_put_failure; 1015dc6ed1dfSShmulik Ravid 10161eb4c977SDavid S. Miller for (i = 0; i < app_count; i++) { 10171eb4c977SDavid S. Miller if (nla_put(skb, app_entry_type, sizeof(struct dcb_app), 10181eb4c977SDavid S. Miller &table[i])) 10191eb4c977SDavid S. Miller goto nla_put_failure; 10201eb4c977SDavid S. Miller } 1021eed84713SShmulik Ravid nla_nest_end(skb, app); 1022eed84713SShmulik Ravid } 1023eed84713SShmulik Ravid err = 0; 1024eed84713SShmulik Ravid 1025eed84713SShmulik Ravid nla_put_failure: 1026eed84713SShmulik Ravid kfree(table); 1027eed84713SShmulik Ravid return err; 1028eed84713SShmulik Ravid } 10293e29027aSJohn Fastabend 1030c9368247SShani Michaeli /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb GET commands. */ 1031314b4778SJohn Fastabend static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) 10323e29027aSJohn Fastabend { 10339ab933abSJohn Fastabend struct nlattr *ieee, *app; 10349ab933abSJohn Fastabend struct dcb_app_type *itr; 10353e29027aSJohn Fastabend const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1036c7797bafSJohn Fastabend int dcbx; 10373d1f4869SThomas Graf int err; 10383e29027aSJohn Fastabend 10391eb4c977SDavid S. Miller if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 10403d1f4869SThomas Graf return -EMSGSIZE; 10413d1f4869SThomas Graf 1042ae0be8deSMichal Kubecek ieee = nla_nest_start_noflag(skb, DCB_ATTR_IEEE); 10433e29027aSJohn Fastabend if (!ieee) 10443d1f4869SThomas Graf return -EMSGSIZE; 10453e29027aSJohn Fastabend 10463e29027aSJohn Fastabend if (ops->ieee_getets) { 10473e29027aSJohn Fastabend struct ieee_ets ets; 104829cd8ae0SMathias Krause memset(&ets, 0, sizeof(ets)); 10493e29027aSJohn Fastabend err = ops->ieee_getets(netdev, &ets); 10501eb4c977SDavid S. Miller if (!err && 10511eb4c977SDavid S. Miller nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets)) 10523d1f4869SThomas Graf return -EMSGSIZE; 10533e29027aSJohn Fastabend } 10543e29027aSJohn Fastabend 105508f10affSAmir Vadai if (ops->ieee_getmaxrate) { 105608f10affSAmir Vadai struct ieee_maxrate maxrate; 105729cd8ae0SMathias Krause memset(&maxrate, 0, sizeof(maxrate)); 105808f10affSAmir Vadai err = ops->ieee_getmaxrate(netdev, &maxrate); 105908f10affSAmir Vadai if (!err) { 106008f10affSAmir Vadai err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE, 106108f10affSAmir Vadai sizeof(maxrate), &maxrate); 106208f10affSAmir Vadai if (err) 10633d1f4869SThomas Graf return -EMSGSIZE; 106408f10affSAmir Vadai } 106508f10affSAmir Vadai } 106608f10affSAmir Vadai 1067c9368247SShani Michaeli if (ops->ieee_getqcn) { 1068c9368247SShani Michaeli struct ieee_qcn qcn; 1069c9368247SShani Michaeli 1070c9368247SShani Michaeli memset(&qcn, 0, sizeof(qcn)); 1071c9368247SShani Michaeli err = ops->ieee_getqcn(netdev, &qcn); 1072c9368247SShani Michaeli if (!err) { 1073c9368247SShani Michaeli err = nla_put(skb, DCB_ATTR_IEEE_QCN, 1074c9368247SShani Michaeli sizeof(qcn), &qcn); 1075c9368247SShani Michaeli if (err) 1076c9368247SShani Michaeli return -EMSGSIZE; 1077c9368247SShani Michaeli } 1078c9368247SShani Michaeli } 1079c9368247SShani Michaeli 1080c9368247SShani Michaeli if (ops->ieee_getqcnstats) { 1081c9368247SShani Michaeli struct ieee_qcn_stats qcn_stats; 1082c9368247SShani Michaeli 1083c9368247SShani Michaeli memset(&qcn_stats, 0, sizeof(qcn_stats)); 1084c9368247SShani Michaeli err = ops->ieee_getqcnstats(netdev, &qcn_stats); 1085c9368247SShani Michaeli if (!err) { 1086c9368247SShani Michaeli err = nla_put(skb, DCB_ATTR_IEEE_QCN_STATS, 1087c9368247SShani Michaeli sizeof(qcn_stats), &qcn_stats); 1088c9368247SShani Michaeli if (err) 1089c9368247SShani Michaeli return -EMSGSIZE; 1090c9368247SShani Michaeli } 1091c9368247SShani Michaeli } 1092c9368247SShani Michaeli 10933e29027aSJohn Fastabend if (ops->ieee_getpfc) { 10943e29027aSJohn Fastabend struct ieee_pfc pfc; 109529cd8ae0SMathias Krause memset(&pfc, 0, sizeof(pfc)); 10963e29027aSJohn Fastabend err = ops->ieee_getpfc(netdev, &pfc); 10971eb4c977SDavid S. Miller if (!err && 10981eb4c977SDavid S. Miller nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc)) 10993d1f4869SThomas Graf return -EMSGSIZE; 11003e29027aSJohn Fastabend } 11013e29027aSJohn Fastabend 1102e549f6f9SHuy Nguyen if (ops->dcbnl_getbuffer) { 1103e549f6f9SHuy Nguyen struct dcbnl_buffer buffer; 1104e549f6f9SHuy Nguyen 1105e549f6f9SHuy Nguyen memset(&buffer, 0, sizeof(buffer)); 1106e549f6f9SHuy Nguyen err = ops->dcbnl_getbuffer(netdev, &buffer); 1107e549f6f9SHuy Nguyen if (!err && 1108e549f6f9SHuy Nguyen nla_put(skb, DCB_ATTR_DCB_BUFFER, sizeof(buffer), &buffer)) 1109e549f6f9SHuy Nguyen return -EMSGSIZE; 1110e549f6f9SHuy Nguyen } 1111e549f6f9SHuy Nguyen 1112ae0be8deSMichal Kubecek app = nla_nest_start_noflag(skb, DCB_ATTR_IEEE_APP_TABLE); 11139ab933abSJohn Fastabend if (!app) 11143d1f4869SThomas Graf return -EMSGSIZE; 11159ab933abSJohn Fastabend 111652cff74eSAnish Bhatt spin_lock_bh(&dcb_lock); 11179ab933abSJohn Fastabend list_for_each_entry(itr, &dcb_app_list, list) { 1118e290ed81SMark Rustad if (itr->ifindex == netdev->ifindex) { 111970bfa2d2SDan Carpenter err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), 112070bfa2d2SDan Carpenter &itr->app); 112170bfa2d2SDan Carpenter if (err) { 112252cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 11233d1f4869SThomas Graf return -EMSGSIZE; 112470bfa2d2SDan Carpenter } 112570bfa2d2SDan Carpenter } 11269ab933abSJohn Fastabend } 1127c7797bafSJohn Fastabend 1128c7797bafSJohn Fastabend if (netdev->dcbnl_ops->getdcbx) 1129c7797bafSJohn Fastabend dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1130c7797bafSJohn Fastabend else 1131c7797bafSJohn Fastabend dcbx = -EOPNOTSUPP; 1132c7797bafSJohn Fastabend 113352cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 11349ab933abSJohn Fastabend nla_nest_end(skb, app); 11359ab933abSJohn Fastabend 1136eed84713SShmulik Ravid /* get peer info if available */ 1137eed84713SShmulik Ravid if (ops->ieee_peer_getets) { 1138eed84713SShmulik Ravid struct ieee_ets ets; 113929cd8ae0SMathias Krause memset(&ets, 0, sizeof(ets)); 1140eed84713SShmulik Ravid err = ops->ieee_peer_getets(netdev, &ets); 11411eb4c977SDavid S. Miller if (!err && 11421eb4c977SDavid S. Miller nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets)) 11433d1f4869SThomas Graf return -EMSGSIZE; 1144eed84713SShmulik Ravid } 1145eed84713SShmulik Ravid 1146eed84713SShmulik Ravid if (ops->ieee_peer_getpfc) { 1147eed84713SShmulik Ravid struct ieee_pfc pfc; 114829cd8ae0SMathias Krause memset(&pfc, 0, sizeof(pfc)); 1149eed84713SShmulik Ravid err = ops->ieee_peer_getpfc(netdev, &pfc); 11501eb4c977SDavid S. Miller if (!err && 11511eb4c977SDavid S. Miller nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc)) 11523d1f4869SThomas Graf return -EMSGSIZE; 1153eed84713SShmulik Ravid } 1154eed84713SShmulik Ravid 1155eed84713SShmulik Ravid if (ops->peer_getappinfo && ops->peer_getapptable) { 1156dc6ed1dfSShmulik Ravid err = dcbnl_build_peer_app(netdev, skb, 1157dc6ed1dfSShmulik Ravid DCB_ATTR_IEEE_PEER_APP, 1158dc6ed1dfSShmulik Ravid DCB_ATTR_IEEE_APP_UNSPEC, 1159dc6ed1dfSShmulik Ravid DCB_ATTR_IEEE_APP); 1160eed84713SShmulik Ravid if (err) 11613d1f4869SThomas Graf return -EMSGSIZE; 1162eed84713SShmulik Ravid } 1163eed84713SShmulik Ravid 11643e29027aSJohn Fastabend nla_nest_end(skb, ieee); 1165c7797bafSJohn Fastabend if (dcbx >= 0) { 1166c7797bafSJohn Fastabend err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1167c7797bafSJohn Fastabend if (err) 11683d1f4869SThomas Graf return -EMSGSIZE; 1169c7797bafSJohn Fastabend } 11703e29027aSJohn Fastabend 1171314b4778SJohn Fastabend return 0; 11723e29027aSJohn Fastabend } 11733e29027aSJohn Fastabend 11745b7f7626SShmulik Ravid static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, 11755b7f7626SShmulik Ravid int dir) 11765b7f7626SShmulik Ravid { 11775b7f7626SShmulik Ravid u8 pgid, up_map, prio, tc_pct; 11785b7f7626SShmulik Ravid const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 11795b7f7626SShmulik Ravid int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG; 1180ae0be8deSMichal Kubecek struct nlattr *pg = nla_nest_start_noflag(skb, i); 11815b7f7626SShmulik Ravid 11825b7f7626SShmulik Ravid if (!pg) 11833d1f4869SThomas Graf return -EMSGSIZE; 11845b7f7626SShmulik Ravid 11855b7f7626SShmulik Ravid for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 1186ae0be8deSMichal Kubecek struct nlattr *tc_nest = nla_nest_start_noflag(skb, i); 11875b7f7626SShmulik Ravid 11885b7f7626SShmulik Ravid if (!tc_nest) 11893d1f4869SThomas Graf return -EMSGSIZE; 11905b7f7626SShmulik Ravid 11915b7f7626SShmulik Ravid pgid = DCB_ATTR_VALUE_UNDEFINED; 11925b7f7626SShmulik Ravid prio = DCB_ATTR_VALUE_UNDEFINED; 11935b7f7626SShmulik Ravid tc_pct = DCB_ATTR_VALUE_UNDEFINED; 11945b7f7626SShmulik Ravid up_map = DCB_ATTR_VALUE_UNDEFINED; 11955b7f7626SShmulik Ravid 11965b7f7626SShmulik Ravid if (!dir) 11975b7f7626SShmulik Ravid ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0, 11985b7f7626SShmulik Ravid &prio, &pgid, &tc_pct, &up_map); 11995b7f7626SShmulik Ravid else 12005b7f7626SShmulik Ravid ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, 12015b7f7626SShmulik Ravid &prio, &pgid, &tc_pct, &up_map); 12025b7f7626SShmulik Ravid 12031eb4c977SDavid S. Miller if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) || 12041eb4c977SDavid S. Miller nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) || 12051eb4c977SDavid S. Miller nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) || 12061eb4c977SDavid S. Miller nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct)) 12073d1f4869SThomas Graf return -EMSGSIZE; 12085b7f7626SShmulik Ravid nla_nest_end(skb, tc_nest); 12095b7f7626SShmulik Ravid } 12105b7f7626SShmulik Ravid 12115b7f7626SShmulik Ravid for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 12125b7f7626SShmulik Ravid tc_pct = DCB_ATTR_VALUE_UNDEFINED; 12135b7f7626SShmulik Ravid 12145b7f7626SShmulik Ravid if (!dir) 12155b7f7626SShmulik Ravid ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0, 12165b7f7626SShmulik Ravid &tc_pct); 12175b7f7626SShmulik Ravid else 12185b7f7626SShmulik Ravid ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, 12195b7f7626SShmulik Ravid &tc_pct); 12201eb4c977SDavid S. Miller if (nla_put_u8(skb, i, tc_pct)) 12213d1f4869SThomas Graf return -EMSGSIZE; 12225b7f7626SShmulik Ravid } 12235b7f7626SShmulik Ravid nla_nest_end(skb, pg); 12245b7f7626SShmulik Ravid return 0; 12255b7f7626SShmulik Ravid } 12265b7f7626SShmulik Ravid 12275b7f7626SShmulik Ravid static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) 12285b7f7626SShmulik Ravid { 12295b7f7626SShmulik Ravid struct nlattr *cee, *app; 12305b7f7626SShmulik Ravid struct dcb_app_type *itr; 12315b7f7626SShmulik Ravid const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 12325b7f7626SShmulik Ravid int dcbx, i, err = -EMSGSIZE; 12335b7f7626SShmulik Ravid u8 value; 12345b7f7626SShmulik Ravid 12351eb4c977SDavid S. Miller if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 12361eb4c977SDavid S. Miller goto nla_put_failure; 1237ae0be8deSMichal Kubecek cee = nla_nest_start_noflag(skb, DCB_ATTR_CEE); 12385b7f7626SShmulik Ravid if (!cee) 12395b7f7626SShmulik Ravid goto nla_put_failure; 12405b7f7626SShmulik Ravid 12415b7f7626SShmulik Ravid /* local pg */ 12425b7f7626SShmulik Ravid if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) { 12435b7f7626SShmulik Ravid err = dcbnl_cee_pg_fill(skb, netdev, 1); 12445b7f7626SShmulik Ravid if (err) 12455b7f7626SShmulik Ravid goto nla_put_failure; 12465b7f7626SShmulik Ravid } 12475b7f7626SShmulik Ravid 12485b7f7626SShmulik Ravid if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) { 12495b7f7626SShmulik Ravid err = dcbnl_cee_pg_fill(skb, netdev, 0); 12505b7f7626SShmulik Ravid if (err) 12515b7f7626SShmulik Ravid goto nla_put_failure; 12525b7f7626SShmulik Ravid } 12535b7f7626SShmulik Ravid 12545b7f7626SShmulik Ravid /* local pfc */ 12555b7f7626SShmulik Ravid if (ops->getpfccfg) { 1256ae0be8deSMichal Kubecek struct nlattr *pfc_nest = nla_nest_start_noflag(skb, 1257ae0be8deSMichal Kubecek DCB_ATTR_CEE_PFC); 12585b7f7626SShmulik Ravid 12595b7f7626SShmulik Ravid if (!pfc_nest) 12605b7f7626SShmulik Ravid goto nla_put_failure; 12615b7f7626SShmulik Ravid 12625b7f7626SShmulik Ravid for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 12635b7f7626SShmulik Ravid ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); 12641eb4c977SDavid S. Miller if (nla_put_u8(skb, i, value)) 12651eb4c977SDavid S. Miller goto nla_put_failure; 12665b7f7626SShmulik Ravid } 12675b7f7626SShmulik Ravid nla_nest_end(skb, pfc_nest); 12685b7f7626SShmulik Ravid } 12695b7f7626SShmulik Ravid 12705b7f7626SShmulik Ravid /* local app */ 127152cff74eSAnish Bhatt spin_lock_bh(&dcb_lock); 1272ae0be8deSMichal Kubecek app = nla_nest_start_noflag(skb, DCB_ATTR_CEE_APP_TABLE); 12735b7f7626SShmulik Ravid if (!app) 127440f5d72aSDan Carpenter goto dcb_unlock; 12755b7f7626SShmulik Ravid 12765b7f7626SShmulik Ravid list_for_each_entry(itr, &dcb_app_list, list) { 1277e290ed81SMark Rustad if (itr->ifindex == netdev->ifindex) { 1278ae0be8deSMichal Kubecek struct nlattr *app_nest = nla_nest_start_noflag(skb, 12795b7f7626SShmulik Ravid DCB_ATTR_APP); 12805b7f7626SShmulik Ravid if (!app_nest) 12815b7f7626SShmulik Ravid goto dcb_unlock; 12825b7f7626SShmulik Ravid 12835b7f7626SShmulik Ravid err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, 12845b7f7626SShmulik Ravid itr->app.selector); 12855b7f7626SShmulik Ravid if (err) 12865b7f7626SShmulik Ravid goto dcb_unlock; 12875b7f7626SShmulik Ravid 12885b7f7626SShmulik Ravid err = nla_put_u16(skb, DCB_APP_ATTR_ID, 12895b7f7626SShmulik Ravid itr->app.protocol); 12905b7f7626SShmulik Ravid if (err) 12915b7f7626SShmulik Ravid goto dcb_unlock; 12925b7f7626SShmulik Ravid 12935b7f7626SShmulik Ravid err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, 12945b7f7626SShmulik Ravid itr->app.priority); 12955b7f7626SShmulik Ravid if (err) 12965b7f7626SShmulik Ravid goto dcb_unlock; 12975b7f7626SShmulik Ravid 12985b7f7626SShmulik Ravid nla_nest_end(skb, app_nest); 12995b7f7626SShmulik Ravid } 13005b7f7626SShmulik Ravid } 13015b7f7626SShmulik Ravid nla_nest_end(skb, app); 13025b7f7626SShmulik Ravid 13035b7f7626SShmulik Ravid if (netdev->dcbnl_ops->getdcbx) 13045b7f7626SShmulik Ravid dcbx = netdev->dcbnl_ops->getdcbx(netdev); 13055b7f7626SShmulik Ravid else 13065b7f7626SShmulik Ravid dcbx = -EOPNOTSUPP; 13075b7f7626SShmulik Ravid 130852cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 13095b7f7626SShmulik Ravid 13105b7f7626SShmulik Ravid /* features flags */ 13115b7f7626SShmulik Ravid if (ops->getfeatcfg) { 1312ae0be8deSMichal Kubecek struct nlattr *feat = nla_nest_start_noflag(skb, 1313ae0be8deSMichal Kubecek DCB_ATTR_CEE_FEAT); 13145b7f7626SShmulik Ravid if (!feat) 13155b7f7626SShmulik Ravid goto nla_put_failure; 13165b7f7626SShmulik Ravid 13175b7f7626SShmulik Ravid for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; 13185b7f7626SShmulik Ravid i++) 13191eb4c977SDavid S. Miller if (!ops->getfeatcfg(netdev, i, &value) && 13201eb4c977SDavid S. Miller nla_put_u8(skb, i, value)) 13211eb4c977SDavid S. Miller goto nla_put_failure; 13225b7f7626SShmulik Ravid 13235b7f7626SShmulik Ravid nla_nest_end(skb, feat); 13245b7f7626SShmulik Ravid } 13255b7f7626SShmulik Ravid 13265b7f7626SShmulik Ravid /* peer info if available */ 13275b7f7626SShmulik Ravid if (ops->cee_peer_getpg) { 13285b7f7626SShmulik Ravid struct cee_pg pg; 132929cd8ae0SMathias Krause memset(&pg, 0, sizeof(pg)); 13305b7f7626SShmulik Ravid err = ops->cee_peer_getpg(netdev, &pg); 13311eb4c977SDavid S. Miller if (!err && 13321eb4c977SDavid S. Miller nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg)) 13331eb4c977SDavid S. Miller goto nla_put_failure; 13345b7f7626SShmulik Ravid } 13355b7f7626SShmulik Ravid 13365b7f7626SShmulik Ravid if (ops->cee_peer_getpfc) { 13375b7f7626SShmulik Ravid struct cee_pfc pfc; 133829cd8ae0SMathias Krause memset(&pfc, 0, sizeof(pfc)); 13395b7f7626SShmulik Ravid err = ops->cee_peer_getpfc(netdev, &pfc); 13401eb4c977SDavid S. Miller if (!err && 13411eb4c977SDavid S. Miller nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc)) 13421eb4c977SDavid S. Miller goto nla_put_failure; 13435b7f7626SShmulik Ravid } 13445b7f7626SShmulik Ravid 13455b7f7626SShmulik Ravid if (ops->peer_getappinfo && ops->peer_getapptable) { 13465b7f7626SShmulik Ravid err = dcbnl_build_peer_app(netdev, skb, 13475b7f7626SShmulik Ravid DCB_ATTR_CEE_PEER_APP_TABLE, 13485b7f7626SShmulik Ravid DCB_ATTR_CEE_PEER_APP_INFO, 13495b7f7626SShmulik Ravid DCB_ATTR_CEE_PEER_APP); 13505b7f7626SShmulik Ravid if (err) 13515b7f7626SShmulik Ravid goto nla_put_failure; 13525b7f7626SShmulik Ravid } 13535b7f7626SShmulik Ravid nla_nest_end(skb, cee); 13545b7f7626SShmulik Ravid 13555b7f7626SShmulik Ravid /* DCBX state */ 13565b7f7626SShmulik Ravid if (dcbx >= 0) { 13575b7f7626SShmulik Ravid err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 13585b7f7626SShmulik Ravid if (err) 13595b7f7626SShmulik Ravid goto nla_put_failure; 13605b7f7626SShmulik Ravid } 13615b7f7626SShmulik Ravid return 0; 13625b7f7626SShmulik Ravid 13635b7f7626SShmulik Ravid dcb_unlock: 136452cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 13655b7f7626SShmulik Ravid nla_put_failure: 1366c66ebf2dSPan Bian err = -EMSGSIZE; 13675b7f7626SShmulik Ravid return err; 13685b7f7626SShmulik Ravid } 13695b7f7626SShmulik Ravid 13705b7f7626SShmulik Ravid static int dcbnl_notify(struct net_device *dev, int event, int cmd, 137115e47304SEric W. Biederman u32 seq, u32 portid, int dcbx_ver) 1372314b4778SJohn Fastabend { 1373314b4778SJohn Fastabend struct net *net = dev_net(dev); 1374314b4778SJohn Fastabend struct sk_buff *skb; 1375314b4778SJohn Fastabend struct nlmsghdr *nlh; 1376314b4778SJohn Fastabend const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1377314b4778SJohn Fastabend int err; 1378314b4778SJohn Fastabend 1379314b4778SJohn Fastabend if (!ops) 1380314b4778SJohn Fastabend return -EOPNOTSUPP; 1381314b4778SJohn Fastabend 138215e47304SEric W. Biederman skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh); 1383314b4778SJohn Fastabend if (!skb) 1384b923cda9SZheng Yongjun return -ENOMEM; 1385314b4778SJohn Fastabend 13865b7f7626SShmulik Ravid if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) 1387314b4778SJohn Fastabend err = dcbnl_ieee_fill(skb, dev); 13885b7f7626SShmulik Ravid else 13895b7f7626SShmulik Ravid err = dcbnl_cee_fill(skb, dev); 13905b7f7626SShmulik Ravid 1391314b4778SJohn Fastabend if (err < 0) { 1392314b4778SJohn Fastabend /* Report error to broadcast listeners */ 1393ab6d4707SThomas Graf nlmsg_free(skb); 1394314b4778SJohn Fastabend rtnl_set_sk_err(net, RTNLGRP_DCB, err); 1395314b4778SJohn Fastabend } else { 1396314b4778SJohn Fastabend /* End nlmsg and notify broadcast listeners */ 1397314b4778SJohn Fastabend nlmsg_end(skb, nlh); 1398314b4778SJohn Fastabend rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); 1399314b4778SJohn Fastabend } 1400314b4778SJohn Fastabend 1401314b4778SJohn Fastabend return err; 1402314b4778SJohn Fastabend } 14035b7f7626SShmulik Ravid 14045b7f7626SShmulik Ravid int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, 140515e47304SEric W. Biederman u32 seq, u32 portid) 14065b7f7626SShmulik Ravid { 140715e47304SEric W. Biederman return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE); 14085b7f7626SShmulik Ravid } 14095b7f7626SShmulik Ravid EXPORT_SYMBOL(dcbnl_ieee_notify); 14105b7f7626SShmulik Ravid 14115b7f7626SShmulik Ravid int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, 141215e47304SEric W. Biederman u32 seq, u32 portid) 14135b7f7626SShmulik Ravid { 141415e47304SEric W. Biederman return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE); 14155b7f7626SShmulik Ravid } 14165b7f7626SShmulik Ravid EXPORT_SYMBOL(dcbnl_cee_notify); 1417314b4778SJohn Fastabend 1418c9368247SShani Michaeli /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb SET commands. 1419c9368247SShani Michaeli * If any requested operation can not be completed 1420c9368247SShani Michaeli * the entire msg is aborted and error value is returned. 1421314b4778SJohn Fastabend * No attempt is made to reconcile the case where only part of the 1422314b4778SJohn Fastabend * cmd can be completed. 1423314b4778SJohn Fastabend */ 14247be99413SThomas Graf static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, 14257be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 1426314b4778SJohn Fastabend { 1427314b4778SJohn Fastabend const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1428314b4778SJohn Fastabend struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1429297e77e5SPetr Machata int prio; 14303d1f4869SThomas Graf int err; 1431314b4778SJohn Fastabend 1432314b4778SJohn Fastabend if (!ops) 14333d1f4869SThomas Graf return -EOPNOTSUPP; 1434314b4778SJohn Fastabend 14354003b658SJohn Fastabend if (!tb[DCB_ATTR_IEEE]) 14364003b658SJohn Fastabend return -EINVAL; 14374003b658SJohn Fastabend 14388cb08174SJohannes Berg err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX, 14398cb08174SJohannes Berg tb[DCB_ATTR_IEEE], 1440fceb6435SJohannes Berg dcbnl_ieee_policy, NULL); 1441314b4778SJohn Fastabend if (err) 1442314b4778SJohn Fastabend return err; 1443314b4778SJohn Fastabend 1444314b4778SJohn Fastabend if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { 1445314b4778SJohn Fastabend struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); 1446314b4778SJohn Fastabend err = ops->ieee_setets(netdev, ets); 1447314b4778SJohn Fastabend if (err) 1448314b4778SJohn Fastabend goto err; 1449314b4778SJohn Fastabend } 1450314b4778SJohn Fastabend 145108f10affSAmir Vadai if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) { 145208f10affSAmir Vadai struct ieee_maxrate *maxrate = 145308f10affSAmir Vadai nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]); 145408f10affSAmir Vadai err = ops->ieee_setmaxrate(netdev, maxrate); 145508f10affSAmir Vadai if (err) 145608f10affSAmir Vadai goto err; 145708f10affSAmir Vadai } 145808f10affSAmir Vadai 1459c9368247SShani Michaeli if (ieee[DCB_ATTR_IEEE_QCN] && ops->ieee_setqcn) { 1460c9368247SShani Michaeli struct ieee_qcn *qcn = 1461c9368247SShani Michaeli nla_data(ieee[DCB_ATTR_IEEE_QCN]); 1462c9368247SShani Michaeli 1463c9368247SShani Michaeli err = ops->ieee_setqcn(netdev, qcn); 1464c9368247SShani Michaeli if (err) 1465c9368247SShani Michaeli goto err; 1466c9368247SShani Michaeli } 1467c9368247SShani Michaeli 1468314b4778SJohn Fastabend if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { 1469314b4778SJohn Fastabend struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); 1470314b4778SJohn Fastabend err = ops->ieee_setpfc(netdev, pfc); 1471314b4778SJohn Fastabend if (err) 1472314b4778SJohn Fastabend goto err; 1473314b4778SJohn Fastabend } 1474314b4778SJohn Fastabend 1475e549f6f9SHuy Nguyen if (ieee[DCB_ATTR_DCB_BUFFER] && ops->dcbnl_setbuffer) { 1476e549f6f9SHuy Nguyen struct dcbnl_buffer *buffer = 1477e549f6f9SHuy Nguyen nla_data(ieee[DCB_ATTR_DCB_BUFFER]); 1478e549f6f9SHuy Nguyen 1479297e77e5SPetr Machata for (prio = 0; prio < ARRAY_SIZE(buffer->prio2buffer); prio++) { 1480297e77e5SPetr Machata if (buffer->prio2buffer[prio] >= DCBX_MAX_BUFFERS) { 1481297e77e5SPetr Machata err = -EINVAL; 1482297e77e5SPetr Machata goto err; 1483297e77e5SPetr Machata } 1484297e77e5SPetr Machata } 1485297e77e5SPetr Machata 1486e549f6f9SHuy Nguyen err = ops->dcbnl_setbuffer(netdev, buffer); 1487e549f6f9SHuy Nguyen if (err) 1488e549f6f9SHuy Nguyen goto err; 1489e549f6f9SHuy Nguyen } 1490e549f6f9SHuy Nguyen 1491314b4778SJohn Fastabend if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1492314b4778SJohn Fastabend struct nlattr *attr; 1493314b4778SJohn Fastabend int rem; 1494314b4778SJohn Fastabend 1495314b4778SJohn Fastabend nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1496314b4778SJohn Fastabend struct dcb_app *app_data; 1497332b4fc8Sstephen hemminger 1498314b4778SJohn Fastabend if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1499314b4778SJohn Fastabend continue; 1500332b4fc8Sstephen hemminger 1501332b4fc8Sstephen hemminger if (nla_len(attr) < sizeof(struct dcb_app)) { 1502332b4fc8Sstephen hemminger err = -ERANGE; 1503332b4fc8Sstephen hemminger goto err; 1504332b4fc8Sstephen hemminger } 1505332b4fc8Sstephen hemminger 1506314b4778SJohn Fastabend app_data = nla_data(attr); 1507314b4778SJohn Fastabend if (ops->ieee_setapp) 1508314b4778SJohn Fastabend err = ops->ieee_setapp(netdev, app_data); 1509314b4778SJohn Fastabend else 1510b6db2174SJohn Fastabend err = dcb_ieee_setapp(netdev, app_data); 1511314b4778SJohn Fastabend if (err) 1512314b4778SJohn Fastabend goto err; 1513314b4778SJohn Fastabend } 1514314b4778SJohn Fastabend } 1515314b4778SJohn Fastabend 1516314b4778SJohn Fastabend err: 15177be99413SThomas Graf err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 15185b7f7626SShmulik Ravid dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); 1519314b4778SJohn Fastabend return err; 1520314b4778SJohn Fastabend } 1521314b4778SJohn Fastabend 15227be99413SThomas Graf static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh, 15237be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 1524314b4778SJohn Fastabend { 1525314b4778SJohn Fastabend const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1526314b4778SJohn Fastabend 1527314b4778SJohn Fastabend if (!ops) 1528314b4778SJohn Fastabend return -EOPNOTSUPP; 1529314b4778SJohn Fastabend 15307be99413SThomas Graf return dcbnl_ieee_fill(skb, netdev); 1531314b4778SJohn Fastabend } 1532314b4778SJohn Fastabend 15337be99413SThomas Graf static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh, 15347be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 1535f9ae7e4bSJohn Fastabend { 1536f9ae7e4bSJohn Fastabend const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1537f9ae7e4bSJohn Fastabend struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 15383d1f4869SThomas Graf int err; 1539f9ae7e4bSJohn Fastabend 1540f9ae7e4bSJohn Fastabend if (!ops) 1541f9ae7e4bSJohn Fastabend return -EOPNOTSUPP; 1542f9ae7e4bSJohn Fastabend 1543f9ae7e4bSJohn Fastabend if (!tb[DCB_ATTR_IEEE]) 1544f9ae7e4bSJohn Fastabend return -EINVAL; 1545f9ae7e4bSJohn Fastabend 15468cb08174SJohannes Berg err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX, 15478cb08174SJohannes Berg tb[DCB_ATTR_IEEE], 1548fceb6435SJohannes Berg dcbnl_ieee_policy, NULL); 1549f9ae7e4bSJohn Fastabend if (err) 1550f9ae7e4bSJohn Fastabend return err; 1551f9ae7e4bSJohn Fastabend 1552f9ae7e4bSJohn Fastabend if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1553f9ae7e4bSJohn Fastabend struct nlattr *attr; 1554f9ae7e4bSJohn Fastabend int rem; 1555f9ae7e4bSJohn Fastabend 1556f9ae7e4bSJohn Fastabend nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1557f9ae7e4bSJohn Fastabend struct dcb_app *app_data; 1558f9ae7e4bSJohn Fastabend 1559f9ae7e4bSJohn Fastabend if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1560f9ae7e4bSJohn Fastabend continue; 1561f9ae7e4bSJohn Fastabend app_data = nla_data(attr); 1562f9ae7e4bSJohn Fastabend if (ops->ieee_delapp) 1563f9ae7e4bSJohn Fastabend err = ops->ieee_delapp(netdev, app_data); 1564f9ae7e4bSJohn Fastabend else 1565f9ae7e4bSJohn Fastabend err = dcb_ieee_delapp(netdev, app_data); 1566f9ae7e4bSJohn Fastabend if (err) 1567f9ae7e4bSJohn Fastabend goto err; 1568f9ae7e4bSJohn Fastabend } 1569f9ae7e4bSJohn Fastabend } 1570f9ae7e4bSJohn Fastabend 1571f9ae7e4bSJohn Fastabend err: 15727be99413SThomas Graf err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 15735b7f7626SShmulik Ravid dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); 1574f9ae7e4bSJohn Fastabend return err; 1575f9ae7e4bSJohn Fastabend } 1576f9ae7e4bSJohn Fastabend 1577f9ae7e4bSJohn Fastabend 15786241b625SShmulik Ravid /* DCBX configuration */ 15797be99413SThomas Graf static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 15807be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 15816241b625SShmulik Ravid { 15826241b625SShmulik Ravid if (!netdev->dcbnl_ops->getdcbx) 15837f891cf1SShmulik Ravid return -EOPNOTSUPP; 15846241b625SShmulik Ravid 15857be99413SThomas Graf return nla_put_u8(skb, DCB_ATTR_DCBX, 15867be99413SThomas Graf netdev->dcbnl_ops->getdcbx(netdev)); 15876241b625SShmulik Ravid } 15886241b625SShmulik Ravid 15897be99413SThomas Graf static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 15907be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 15916241b625SShmulik Ravid { 15926241b625SShmulik Ravid u8 value; 15936241b625SShmulik Ravid 15947f891cf1SShmulik Ravid if (!netdev->dcbnl_ops->setdcbx) 15957f891cf1SShmulik Ravid return -EOPNOTSUPP; 15967f891cf1SShmulik Ravid 15977f891cf1SShmulik Ravid if (!tb[DCB_ATTR_DCBX]) 15987f891cf1SShmulik Ravid return -EINVAL; 15996241b625SShmulik Ravid 16006241b625SShmulik Ravid value = nla_get_u8(tb[DCB_ATTR_DCBX]); 16016241b625SShmulik Ravid 16027be99413SThomas Graf return nla_put_u8(skb, DCB_ATTR_DCBX, 16037be99413SThomas Graf netdev->dcbnl_ops->setdcbx(netdev, value)); 16046241b625SShmulik Ravid } 16056241b625SShmulik Ravid 16067be99413SThomas Graf static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 16077be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 1608ea45fe4eSShmulik Ravid { 1609ea45fe4eSShmulik Ravid struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; 1610ea45fe4eSShmulik Ravid u8 value; 16117f891cf1SShmulik Ravid int ret, i; 1612ea45fe4eSShmulik Ravid int getall = 0; 1613ea45fe4eSShmulik Ravid 16147f891cf1SShmulik Ravid if (!netdev->dcbnl_ops->getfeatcfg) 16157f891cf1SShmulik Ravid return -EOPNOTSUPP; 16167f891cf1SShmulik Ravid 16177f891cf1SShmulik Ravid if (!tb[DCB_ATTR_FEATCFG]) 16187f891cf1SShmulik Ravid return -EINVAL; 1619ea45fe4eSShmulik Ravid 16208cb08174SJohannes Berg ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX, 16218cb08174SJohannes Berg tb[DCB_ATTR_FEATCFG], 16228cb08174SJohannes Berg dcbnl_featcfg_nest, NULL); 16237f891cf1SShmulik Ravid if (ret) 16247be99413SThomas Graf return ret; 1625ea45fe4eSShmulik Ravid 1626ae0be8deSMichal Kubecek nest = nla_nest_start_noflag(skb, DCB_ATTR_FEATCFG); 16277be99413SThomas Graf if (!nest) 16287be99413SThomas Graf return -EMSGSIZE; 1629ea45fe4eSShmulik Ravid 1630ea45fe4eSShmulik Ravid if (data[DCB_FEATCFG_ATTR_ALL]) 1631ea45fe4eSShmulik Ravid getall = 1; 1632ea45fe4eSShmulik Ravid 1633ea45fe4eSShmulik Ravid for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1634ea45fe4eSShmulik Ravid if (!getall && !data[i]) 1635ea45fe4eSShmulik Ravid continue; 1636ea45fe4eSShmulik Ravid 1637ea45fe4eSShmulik Ravid ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); 16387f891cf1SShmulik Ravid if (!ret) 16397be99413SThomas Graf ret = nla_put_u8(skb, i, value); 1640ea45fe4eSShmulik Ravid 1641ea45fe4eSShmulik Ravid if (ret) { 16427be99413SThomas Graf nla_nest_cancel(skb, nest); 16437f891cf1SShmulik Ravid goto nla_put_failure; 1644ea45fe4eSShmulik Ravid } 1645ea45fe4eSShmulik Ravid } 16467be99413SThomas Graf nla_nest_end(skb, nest); 1647ea45fe4eSShmulik Ravid 16487f891cf1SShmulik Ravid nla_put_failure: 1649ea45fe4eSShmulik Ravid return ret; 1650ea45fe4eSShmulik Ravid } 1651ea45fe4eSShmulik Ravid 16527be99413SThomas Graf static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 16537be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 1654ea45fe4eSShmulik Ravid { 1655ea45fe4eSShmulik Ravid struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; 16567f891cf1SShmulik Ravid int ret, i; 1657ea45fe4eSShmulik Ravid u8 value; 1658ea45fe4eSShmulik Ravid 16597f891cf1SShmulik Ravid if (!netdev->dcbnl_ops->setfeatcfg) 16607f891cf1SShmulik Ravid return -ENOTSUPP; 16617f891cf1SShmulik Ravid 16627f891cf1SShmulik Ravid if (!tb[DCB_ATTR_FEATCFG]) 16637f891cf1SShmulik Ravid return -EINVAL; 1664ea45fe4eSShmulik Ravid 16658cb08174SJohannes Berg ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX, 16668cb08174SJohannes Berg tb[DCB_ATTR_FEATCFG], 16678cb08174SJohannes Berg dcbnl_featcfg_nest, NULL); 1668ea45fe4eSShmulik Ravid 16697f891cf1SShmulik Ravid if (ret) 1670ea45fe4eSShmulik Ravid goto err; 1671ea45fe4eSShmulik Ravid 1672ea45fe4eSShmulik Ravid for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1673ea45fe4eSShmulik Ravid if (data[i] == NULL) 1674ea45fe4eSShmulik Ravid continue; 1675ea45fe4eSShmulik Ravid 1676ea45fe4eSShmulik Ravid value = nla_get_u8(data[i]); 1677ea45fe4eSShmulik Ravid 1678ea45fe4eSShmulik Ravid ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); 1679ea45fe4eSShmulik Ravid 1680ea45fe4eSShmulik Ravid if (ret) 16817f891cf1SShmulik Ravid goto err; 1682ea45fe4eSShmulik Ravid } 1683ea45fe4eSShmulik Ravid err: 16847be99413SThomas Graf ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret); 16857f891cf1SShmulik Ravid 1686ea45fe4eSShmulik Ravid return ret; 1687ea45fe4eSShmulik Ravid } 1688ea45fe4eSShmulik Ravid 1689dc6ed1dfSShmulik Ravid /* Handle CEE DCBX GET commands. */ 16907be99413SThomas Graf static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh, 16917be99413SThomas Graf u32 seq, struct nlattr **tb, struct sk_buff *skb) 1692dc6ed1dfSShmulik Ravid { 1693dc6ed1dfSShmulik Ravid const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1694dc6ed1dfSShmulik Ravid 1695dc6ed1dfSShmulik Ravid if (!ops) 1696dc6ed1dfSShmulik Ravid return -EOPNOTSUPP; 1697dc6ed1dfSShmulik Ravid 16987be99413SThomas Graf return dcbnl_cee_fill(skb, netdev); 1699dc6ed1dfSShmulik Ravid } 1700dc6ed1dfSShmulik Ravid 170133a03aadSThomas Graf struct reply_func { 170233a03aadSThomas Graf /* reply netlink message type */ 170333a03aadSThomas Graf int type; 170433a03aadSThomas Graf 170533a03aadSThomas Graf /* function to fill message contents */ 170633a03aadSThomas Graf int (*cb)(struct net_device *, struct nlmsghdr *, u32, 170733a03aadSThomas Graf struct nlattr **, struct sk_buff *); 170833a03aadSThomas Graf }; 170933a03aadSThomas Graf 171033a03aadSThomas Graf static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = { 17117be99413SThomas Graf [DCB_CMD_GSTATE] = { RTM_GETDCB, dcbnl_getstate }, 17127be99413SThomas Graf [DCB_CMD_SSTATE] = { RTM_SETDCB, dcbnl_setstate }, 17137be99413SThomas Graf [DCB_CMD_PFC_GCFG] = { RTM_GETDCB, dcbnl_getpfccfg }, 17147be99413SThomas Graf [DCB_CMD_PFC_SCFG] = { RTM_SETDCB, dcbnl_setpfccfg }, 17157be99413SThomas Graf [DCB_CMD_GPERM_HWADDR] = { RTM_GETDCB, dcbnl_getperm_hwaddr }, 17167be99413SThomas Graf [DCB_CMD_GCAP] = { RTM_GETDCB, dcbnl_getcap }, 17177be99413SThomas Graf [DCB_CMD_GNUMTCS] = { RTM_GETDCB, dcbnl_getnumtcs }, 17187be99413SThomas Graf [DCB_CMD_SNUMTCS] = { RTM_SETDCB, dcbnl_setnumtcs }, 17197be99413SThomas Graf [DCB_CMD_PFC_GSTATE] = { RTM_GETDCB, dcbnl_getpfcstate }, 17207be99413SThomas Graf [DCB_CMD_PFC_SSTATE] = { RTM_SETDCB, dcbnl_setpfcstate }, 17217be99413SThomas Graf [DCB_CMD_GAPP] = { RTM_GETDCB, dcbnl_getapp }, 17227be99413SThomas Graf [DCB_CMD_SAPP] = { RTM_SETDCB, dcbnl_setapp }, 17237be99413SThomas Graf [DCB_CMD_PGTX_GCFG] = { RTM_GETDCB, dcbnl_pgtx_getcfg }, 17247be99413SThomas Graf [DCB_CMD_PGTX_SCFG] = { RTM_SETDCB, dcbnl_pgtx_setcfg }, 17257be99413SThomas Graf [DCB_CMD_PGRX_GCFG] = { RTM_GETDCB, dcbnl_pgrx_getcfg }, 17267be99413SThomas Graf [DCB_CMD_PGRX_SCFG] = { RTM_SETDCB, dcbnl_pgrx_setcfg }, 17277be99413SThomas Graf [DCB_CMD_SET_ALL] = { RTM_SETDCB, dcbnl_setall }, 17287be99413SThomas Graf [DCB_CMD_BCN_GCFG] = { RTM_GETDCB, dcbnl_bcn_getcfg }, 17297be99413SThomas Graf [DCB_CMD_BCN_SCFG] = { RTM_SETDCB, dcbnl_bcn_setcfg }, 17307be99413SThomas Graf [DCB_CMD_IEEE_GET] = { RTM_GETDCB, dcbnl_ieee_get }, 17317be99413SThomas Graf [DCB_CMD_IEEE_SET] = { RTM_SETDCB, dcbnl_ieee_set }, 17327be99413SThomas Graf [DCB_CMD_IEEE_DEL] = { RTM_SETDCB, dcbnl_ieee_del }, 17337be99413SThomas Graf [DCB_CMD_GDCBX] = { RTM_GETDCB, dcbnl_getdcbx }, 17347be99413SThomas Graf [DCB_CMD_SDCBX] = { RTM_SETDCB, dcbnl_setdcbx }, 17357be99413SThomas Graf [DCB_CMD_GFEATCFG] = { RTM_GETDCB, dcbnl_getfeatcfg }, 17367be99413SThomas Graf [DCB_CMD_SFEATCFG] = { RTM_SETDCB, dcbnl_setfeatcfg }, 17377be99413SThomas Graf [DCB_CMD_CEE_GET] = { RTM_GETDCB, dcbnl_cee_get }, 173833a03aadSThomas Graf }; 173933a03aadSThomas Graf 1740c21ef3e3SDavid Ahern static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 1741c21ef3e3SDavid Ahern struct netlink_ext_ack *extack) 17422f90b865SAlexander Duyck { 17432f90b865SAlexander Duyck struct net *net = sock_net(skb->sk); 17442f90b865SAlexander Duyck struct net_device *netdev; 17457a282bc3SThomas Graf struct dcbmsg *dcb = nlmsg_data(nlh); 17462f90b865SAlexander Duyck struct nlattr *tb[DCB_ATTR_MAX + 1]; 17470cc55e69SGaurav Singh u32 portid = NETLINK_CB(skb).portid; 17482f90b865SAlexander Duyck int ret = -EINVAL; 174933a03aadSThomas Graf struct sk_buff *reply_skb; 175039912f9cSThomas Graf struct nlmsghdr *reply_nlh = NULL; 175133a03aadSThomas Graf const struct reply_func *fn; 17522f90b865SAlexander Duyck 175390f62cf3SEric W. Biederman if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN)) 1754dfc47ef8SEric W. Biederman return -EPERM; 1755dfc47ef8SEric W. Biederman 17568cb08174SJohannes Berg ret = nlmsg_parse_deprecated(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 1757c21ef3e3SDavid Ahern dcbnl_rtnl_policy, extack); 17582f90b865SAlexander Duyck if (ret < 0) 17592f90b865SAlexander Duyck return ret; 17602f90b865SAlexander Duyck 176133a03aadSThomas Graf if (dcb->cmd > DCB_CMD_MAX) 176233a03aadSThomas Graf return -EINVAL; 176333a03aadSThomas Graf 176433a03aadSThomas Graf /* check if a reply function has been defined for the command */ 176533a03aadSThomas Graf fn = &reply_funcs[dcb->cmd]; 176633a03aadSThomas Graf if (!fn->cb) 176733a03aadSThomas Graf return -EOPNOTSUPP; 1768df85bc14SPetr Machata if (fn->type == RTM_SETDCB && !netlink_capable(skb, CAP_NET_ADMIN)) 1769826f328eSPetr Machata return -EPERM; 177033a03aadSThomas Graf 17712f90b865SAlexander Duyck if (!tb[DCB_ATTR_IFNAME]) 17722f90b865SAlexander Duyck return -EINVAL; 17732f90b865SAlexander Duyck 1774d9ac62beSYing Xue netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); 17752f90b865SAlexander Duyck if (!netdev) 17763d1f4869SThomas Graf return -ENODEV; 17772f90b865SAlexander Duyck 1778d9ac62beSYing Xue if (!netdev->dcbnl_ops) 1779d9ac62beSYing Xue return -EOPNOTSUPP; 17802f90b865SAlexander Duyck 178115e47304SEric W. Biederman reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, 178233a03aadSThomas Graf nlh->nlmsg_flags, &reply_nlh); 1783d9ac62beSYing Xue if (!reply_skb) 1784b923cda9SZheng Yongjun return -ENOMEM; 178533a03aadSThomas Graf 178633a03aadSThomas Graf ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); 178733a03aadSThomas Graf if (ret < 0) { 178833a03aadSThomas Graf nlmsg_free(reply_skb); 178933a03aadSThomas Graf goto out; 179033a03aadSThomas Graf } 179133a03aadSThomas Graf 179233a03aadSThomas Graf nlmsg_end(reply_skb, reply_nlh); 179333a03aadSThomas Graf 17947c77ab24SJohn Fastabend ret = rtnl_unicast(reply_skb, net, portid); 17952f90b865SAlexander Duyck out: 17962f90b865SAlexander Duyck return ret; 17972f90b865SAlexander Duyck } 17982f90b865SAlexander Duyck 1799716b31abSThomas Graf static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app, 1800716b31abSThomas Graf int ifindex, int prio) 1801716b31abSThomas Graf { 1802716b31abSThomas Graf struct dcb_app_type *itr; 1803716b31abSThomas Graf 1804716b31abSThomas Graf list_for_each_entry(itr, &dcb_app_list, list) { 1805716b31abSThomas Graf if (itr->app.selector == app->selector && 1806716b31abSThomas Graf itr->app.protocol == app->protocol && 1807716b31abSThomas Graf itr->ifindex == ifindex && 180808193d1aSPetr Machata ((prio == -1) || itr->app.priority == prio)) 1809716b31abSThomas Graf return itr; 1810716b31abSThomas Graf } 1811716b31abSThomas Graf 1812716b31abSThomas Graf return NULL; 1813716b31abSThomas Graf } 1814716b31abSThomas Graf 18154e4f2f69SThomas Graf static int dcb_app_add(const struct dcb_app *app, int ifindex) 18164e4f2f69SThomas Graf { 18174e4f2f69SThomas Graf struct dcb_app_type *entry; 18184e4f2f69SThomas Graf 18194e4f2f69SThomas Graf entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 18204e4f2f69SThomas Graf if (!entry) 18214e4f2f69SThomas Graf return -ENOMEM; 18224e4f2f69SThomas Graf 18234e4f2f69SThomas Graf memcpy(&entry->app, app, sizeof(*app)); 18244e4f2f69SThomas Graf entry->ifindex = ifindex; 18254e4f2f69SThomas Graf list_add(&entry->list, &dcb_app_list); 18264e4f2f69SThomas Graf 18274e4f2f69SThomas Graf return 0; 18284e4f2f69SThomas Graf } 18294e4f2f69SThomas Graf 18309ab933abSJohn Fastabend /** 18319ab933abSJohn Fastabend * dcb_getapp - retrieve the DCBX application user priority 1832a89a501cSAndrew Lunn * @dev: network interface 1833a89a501cSAndrew Lunn * @app: application to get user priority of 18349ab933abSJohn Fastabend * 18359ab933abSJohn Fastabend * On success returns a non-zero 802.1p user priority bitmap 18369ab933abSJohn Fastabend * otherwise returns 0 as the invalid user priority bitmap to 18379ab933abSJohn Fastabend * indicate an error. 18389ab933abSJohn Fastabend */ 18399ab933abSJohn Fastabend u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) 18409ab933abSJohn Fastabend { 18419ab933abSJohn Fastabend struct dcb_app_type *itr; 18429ab933abSJohn Fastabend u8 prio = 0; 18439ab933abSJohn Fastabend 184452cff74eSAnish Bhatt spin_lock_bh(&dcb_lock); 184508193d1aSPetr Machata itr = dcb_app_lookup(app, dev->ifindex, -1); 184608193d1aSPetr Machata if (itr) 18479ab933abSJohn Fastabend prio = itr->app.priority; 184852cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 18499ab933abSJohn Fastabend 18509ab933abSJohn Fastabend return prio; 18519ab933abSJohn Fastabend } 18529ab933abSJohn Fastabend EXPORT_SYMBOL(dcb_getapp); 18539ab933abSJohn Fastabend 18549ab933abSJohn Fastabend /** 1855b6db2174SJohn Fastabend * dcb_setapp - add CEE dcb application data to app list 1856a89a501cSAndrew Lunn * @dev: network interface 1857a89a501cSAndrew Lunn * @new: application data to add 18589ab933abSJohn Fastabend * 1859b6db2174SJohn Fastabend * Priority 0 is an invalid priority in CEE spec. This routine 1860b6db2174SJohn Fastabend * removes applications from the app list if the priority is 186116eecd9bSAnish Bhatt * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap 18629ab933abSJohn Fastabend */ 1863ab6baf98SJohn Fastabend int dcb_setapp(struct net_device *dev, struct dcb_app *new) 18649ab933abSJohn Fastabend { 18659ab933abSJohn Fastabend struct dcb_app_type *itr; 18667ec79270SJohn Fastabend struct dcb_app_type event; 18674e4f2f69SThomas Graf int err = 0; 18687ec79270SJohn Fastabend 1869e290ed81SMark Rustad event.ifindex = dev->ifindex; 18707ec79270SJohn Fastabend memcpy(&event.app, new, sizeof(event.app)); 18716bd0e1cbSJohn Fastabend if (dev->dcbnl_ops->getdcbx) 18726bd0e1cbSJohn Fastabend event.dcbx = dev->dcbnl_ops->getdcbx(dev); 18739ab933abSJohn Fastabend 187452cff74eSAnish Bhatt spin_lock_bh(&dcb_lock); 18759ab933abSJohn Fastabend /* Search for existing match and replace */ 187608193d1aSPetr Machata itr = dcb_app_lookup(new, dev->ifindex, -1); 187708193d1aSPetr Machata if (itr) { 18789ab933abSJohn Fastabend if (new->priority) 18799ab933abSJohn Fastabend itr->app.priority = new->priority; 18809ab933abSJohn Fastabend else { 18819ab933abSJohn Fastabend list_del(&itr->list); 18829ab933abSJohn Fastabend kfree(itr); 18839ab933abSJohn Fastabend } 18849ab933abSJohn Fastabend goto out; 18859ab933abSJohn Fastabend } 18869ab933abSJohn Fastabend /* App type does not exist add new application type */ 18874e4f2f69SThomas Graf if (new->priority) 18884e4f2f69SThomas Graf err = dcb_app_add(new, dev->ifindex); 18899ab933abSJohn Fastabend out: 189052cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 18914e4f2f69SThomas Graf if (!err) 18927ec79270SJohn Fastabend call_dcbevent_notifiers(DCB_APP_EVENT, &event); 18934e4f2f69SThomas Graf return err; 18949ab933abSJohn Fastabend } 18959ab933abSJohn Fastabend EXPORT_SYMBOL(dcb_setapp); 18969ab933abSJohn Fastabend 1897b6db2174SJohn Fastabend /** 1898a364c8cfSJohn Fastabend * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority 1899a89a501cSAndrew Lunn * @dev: network interface 1900a89a501cSAndrew Lunn * @app: where to store the retrieve application data 1901a364c8cfSJohn Fastabend * 1902a364c8cfSJohn Fastabend * Helper routine which on success returns a non-zero 802.1Qaz user 1903a364c8cfSJohn Fastabend * priority bitmap otherwise returns 0 to indicate the dcb_app was 1904a364c8cfSJohn Fastabend * not found in APP list. 1905a364c8cfSJohn Fastabend */ 1906a364c8cfSJohn Fastabend u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) 1907a364c8cfSJohn Fastabend { 1908a364c8cfSJohn Fastabend struct dcb_app_type *itr; 1909a364c8cfSJohn Fastabend u8 prio = 0; 1910a364c8cfSJohn Fastabend 191152cff74eSAnish Bhatt spin_lock_bh(&dcb_lock); 191208193d1aSPetr Machata itr = dcb_app_lookup(app, dev->ifindex, -1); 191308193d1aSPetr Machata if (itr) 1914a364c8cfSJohn Fastabend prio |= 1 << itr->app.priority; 191552cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 1916a364c8cfSJohn Fastabend 1917a364c8cfSJohn Fastabend return prio; 1918a364c8cfSJohn Fastabend } 1919a364c8cfSJohn Fastabend EXPORT_SYMBOL(dcb_ieee_getapp_mask); 1920a364c8cfSJohn Fastabend 1921a364c8cfSJohn Fastabend /** 1922b6db2174SJohn Fastabend * dcb_ieee_setapp - add IEEE dcb application data to app list 1923a89a501cSAndrew Lunn * @dev: network interface 1924a89a501cSAndrew Lunn * @new: application data to add 1925b6db2174SJohn Fastabend * 1926b6db2174SJohn Fastabend * This adds Application data to the list. Multiple application 1927b6db2174SJohn Fastabend * entries may exists for the same selector and protocol as long 192816eecd9bSAnish Bhatt * as the priorities are different. Priority is expected to be a 192916eecd9bSAnish Bhatt * 3-bit unsigned integer 1930b6db2174SJohn Fastabend */ 1931b6db2174SJohn Fastabend int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) 1932b6db2174SJohn Fastabend { 1933b6db2174SJohn Fastabend struct dcb_app_type event; 1934b6db2174SJohn Fastabend int err = 0; 1935b6db2174SJohn Fastabend 1936e290ed81SMark Rustad event.ifindex = dev->ifindex; 1937b6db2174SJohn Fastabend memcpy(&event.app, new, sizeof(event.app)); 19386bd0e1cbSJohn Fastabend if (dev->dcbnl_ops->getdcbx) 19396bd0e1cbSJohn Fastabend event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1940b6db2174SJohn Fastabend 194152cff74eSAnish Bhatt spin_lock_bh(&dcb_lock); 1942b6db2174SJohn Fastabend /* Search for existing match and abort if found */ 1943716b31abSThomas Graf if (dcb_app_lookup(new, dev->ifindex, new->priority)) { 1944b6db2174SJohn Fastabend err = -EEXIST; 1945b6db2174SJohn Fastabend goto out; 1946b6db2174SJohn Fastabend } 1947b6db2174SJohn Fastabend 19484e4f2f69SThomas Graf err = dcb_app_add(new, dev->ifindex); 1949b6db2174SJohn Fastabend out: 195052cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 1951b6db2174SJohn Fastabend if (!err) 1952b6db2174SJohn Fastabend call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1953b6db2174SJohn Fastabend return err; 1954b6db2174SJohn Fastabend } 1955b6db2174SJohn Fastabend EXPORT_SYMBOL(dcb_ieee_setapp); 1956b6db2174SJohn Fastabend 1957f9ae7e4bSJohn Fastabend /** 1958f9ae7e4bSJohn Fastabend * dcb_ieee_delapp - delete IEEE dcb application data from list 1959a89a501cSAndrew Lunn * @dev: network interface 1960a89a501cSAndrew Lunn * @del: application data to delete 1961f9ae7e4bSJohn Fastabend * 1962f9ae7e4bSJohn Fastabend * This removes a matching APP data from the APP list 1963f9ae7e4bSJohn Fastabend */ 1964f9ae7e4bSJohn Fastabend int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) 1965f9ae7e4bSJohn Fastabend { 1966f9ae7e4bSJohn Fastabend struct dcb_app_type *itr; 1967f9ae7e4bSJohn Fastabend struct dcb_app_type event; 1968f9ae7e4bSJohn Fastabend int err = -ENOENT; 1969f9ae7e4bSJohn Fastabend 1970e290ed81SMark Rustad event.ifindex = dev->ifindex; 1971f9ae7e4bSJohn Fastabend memcpy(&event.app, del, sizeof(event.app)); 19726bd0e1cbSJohn Fastabend if (dev->dcbnl_ops->getdcbx) 19736bd0e1cbSJohn Fastabend event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1974f9ae7e4bSJohn Fastabend 197552cff74eSAnish Bhatt spin_lock_bh(&dcb_lock); 1976f9ae7e4bSJohn Fastabend /* Search for existing match and remove it. */ 1977716b31abSThomas Graf if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) { 1978f9ae7e4bSJohn Fastabend list_del(&itr->list); 1979f9ae7e4bSJohn Fastabend kfree(itr); 1980f9ae7e4bSJohn Fastabend err = 0; 1981f9ae7e4bSJohn Fastabend } 1982f9ae7e4bSJohn Fastabend 198352cff74eSAnish Bhatt spin_unlock_bh(&dcb_lock); 1984f9ae7e4bSJohn Fastabend if (!err) 1985f9ae7e4bSJohn Fastabend call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1986f9ae7e4bSJohn Fastabend return err; 1987f9ae7e4bSJohn Fastabend } 1988f9ae7e4bSJohn Fastabend EXPORT_SYMBOL(dcb_ieee_delapp); 1989f9ae7e4bSJohn Fastabend 1990a89a501cSAndrew Lunn /* 1991b67c540bSPetr Machata * dcb_ieee_getapp_prio_dscp_mask_map - For a given device, find mapping from 1992b67c540bSPetr Machata * priorities to the DSCP values assigned to that priority. Initialize p_map 1993b67c540bSPetr Machata * such that each map element holds a bit mask of DSCP values configured for 1994b67c540bSPetr Machata * that priority by APP entries. 1995b67c540bSPetr Machata */ 1996b67c540bSPetr Machata void dcb_ieee_getapp_prio_dscp_mask_map(const struct net_device *dev, 1997b67c540bSPetr Machata struct dcb_ieee_app_prio_map *p_map) 1998b67c540bSPetr Machata { 1999b67c540bSPetr Machata int ifindex = dev->ifindex; 2000b67c540bSPetr Machata struct dcb_app_type *itr; 2001b67c540bSPetr Machata u8 prio; 2002b67c540bSPetr Machata 2003b67c540bSPetr Machata memset(p_map->map, 0, sizeof(p_map->map)); 2004b67c540bSPetr Machata 2005b67c540bSPetr Machata spin_lock_bh(&dcb_lock); 2006b67c540bSPetr Machata list_for_each_entry(itr, &dcb_app_list, list) { 2007b67c540bSPetr Machata if (itr->ifindex == ifindex && 2008b67c540bSPetr Machata itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP && 2009b67c540bSPetr Machata itr->app.protocol < 64 && 2010b67c540bSPetr Machata itr->app.priority < IEEE_8021QAZ_MAX_TCS) { 2011b67c540bSPetr Machata prio = itr->app.priority; 2012b67c540bSPetr Machata p_map->map[prio] |= 1ULL << itr->app.protocol; 2013b67c540bSPetr Machata } 2014b67c540bSPetr Machata } 2015b67c540bSPetr Machata spin_unlock_bh(&dcb_lock); 2016b67c540bSPetr Machata } 2017b67c540bSPetr Machata EXPORT_SYMBOL(dcb_ieee_getapp_prio_dscp_mask_map); 2018b67c540bSPetr Machata 2019a89a501cSAndrew Lunn /* 2020b67c540bSPetr Machata * dcb_ieee_getapp_dscp_prio_mask_map - For a given device, find mapping from 2021b67c540bSPetr Machata * DSCP values to the priorities assigned to that DSCP value. Initialize p_map 2022b67c540bSPetr Machata * such that each map element holds a bit mask of priorities configured for a 2023b67c540bSPetr Machata * given DSCP value by APP entries. 2024b67c540bSPetr Machata */ 2025b67c540bSPetr Machata void 2026b67c540bSPetr Machata dcb_ieee_getapp_dscp_prio_mask_map(const struct net_device *dev, 2027b67c540bSPetr Machata struct dcb_ieee_app_dscp_map *p_map) 2028b67c540bSPetr Machata { 2029b67c540bSPetr Machata int ifindex = dev->ifindex; 2030b67c540bSPetr Machata struct dcb_app_type *itr; 2031b67c540bSPetr Machata 2032b67c540bSPetr Machata memset(p_map->map, 0, sizeof(p_map->map)); 2033b67c540bSPetr Machata 2034b67c540bSPetr Machata spin_lock_bh(&dcb_lock); 2035b67c540bSPetr Machata list_for_each_entry(itr, &dcb_app_list, list) { 2036b67c540bSPetr Machata if (itr->ifindex == ifindex && 2037b67c540bSPetr Machata itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP && 2038b67c540bSPetr Machata itr->app.protocol < 64 && 2039b67c540bSPetr Machata itr->app.priority < IEEE_8021QAZ_MAX_TCS) 2040b67c540bSPetr Machata p_map->map[itr->app.protocol] |= 1 << itr->app.priority; 2041b67c540bSPetr Machata } 2042b67c540bSPetr Machata spin_unlock_bh(&dcb_lock); 2043b67c540bSPetr Machata } 2044b67c540bSPetr Machata EXPORT_SYMBOL(dcb_ieee_getapp_dscp_prio_mask_map); 2045b67c540bSPetr Machata 2046a89a501cSAndrew Lunn /* 2047b67c540bSPetr Machata * Per 802.1Q-2014, the selector value of 1 is used for matching on Ethernet 2048b67c540bSPetr Machata * type, with valid PID values >= 1536. A special meaning is then assigned to 2049b67c540bSPetr Machata * protocol value of 0: "default priority. For use when priority is not 2050b67c540bSPetr Machata * otherwise specified". 2051b67c540bSPetr Machata * 2052b67c540bSPetr Machata * dcb_ieee_getapp_default_prio_mask - For a given device, find all APP entries 2053b67c540bSPetr Machata * of the form {$PRIO, ETHERTYPE, 0} and construct a bit mask of all default 2054b67c540bSPetr Machata * priorities set by these entries. 2055b67c540bSPetr Machata */ 2056b67c540bSPetr Machata u8 dcb_ieee_getapp_default_prio_mask(const struct net_device *dev) 2057b67c540bSPetr Machata { 2058b67c540bSPetr Machata int ifindex = dev->ifindex; 2059b67c540bSPetr Machata struct dcb_app_type *itr; 2060b67c540bSPetr Machata u8 mask = 0; 2061b67c540bSPetr Machata 2062b67c540bSPetr Machata spin_lock_bh(&dcb_lock); 2063b67c540bSPetr Machata list_for_each_entry(itr, &dcb_app_list, list) { 2064b67c540bSPetr Machata if (itr->ifindex == ifindex && 2065b67c540bSPetr Machata itr->app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && 2066b67c540bSPetr Machata itr->app.protocol == 0 && 2067b67c540bSPetr Machata itr->app.priority < IEEE_8021QAZ_MAX_TCS) 2068b67c540bSPetr Machata mask |= 1 << itr->app.priority; 2069b67c540bSPetr Machata } 2070b67c540bSPetr Machata spin_unlock_bh(&dcb_lock); 2071b67c540bSPetr Machata 2072b67c540bSPetr Machata return mask; 2073b67c540bSPetr Machata } 2074b67c540bSPetr Machata EXPORT_SYMBOL(dcb_ieee_getapp_default_prio_mask); 2075b67c540bSPetr Machata 2076*91b0383fSVladimir Oltean static void dcbnl_flush_dev(struct net_device *dev) 2077*91b0383fSVladimir Oltean { 2078*91b0383fSVladimir Oltean struct dcb_app_type *itr, *tmp; 2079*91b0383fSVladimir Oltean 2080*91b0383fSVladimir Oltean spin_lock(&dcb_lock); 2081*91b0383fSVladimir Oltean 2082*91b0383fSVladimir Oltean list_for_each_entry_safe(itr, tmp, &dcb_app_list, list) { 2083*91b0383fSVladimir Oltean if (itr->ifindex == dev->ifindex) { 2084*91b0383fSVladimir Oltean list_del(&itr->list); 2085*91b0383fSVladimir Oltean kfree(itr); 2086*91b0383fSVladimir Oltean } 2087*91b0383fSVladimir Oltean } 2088*91b0383fSVladimir Oltean 2089*91b0383fSVladimir Oltean spin_unlock(&dcb_lock); 2090*91b0383fSVladimir Oltean } 2091*91b0383fSVladimir Oltean 2092*91b0383fSVladimir Oltean static int dcbnl_netdevice_event(struct notifier_block *nb, 2093*91b0383fSVladimir Oltean unsigned long event, void *ptr) 2094*91b0383fSVladimir Oltean { 2095*91b0383fSVladimir Oltean struct net_device *dev = netdev_notifier_info_to_dev(ptr); 2096*91b0383fSVladimir Oltean 2097*91b0383fSVladimir Oltean switch (event) { 2098*91b0383fSVladimir Oltean case NETDEV_UNREGISTER: 2099*91b0383fSVladimir Oltean if (!dev->dcbnl_ops) 2100*91b0383fSVladimir Oltean return NOTIFY_DONE; 2101*91b0383fSVladimir Oltean 2102*91b0383fSVladimir Oltean dcbnl_flush_dev(dev); 2103*91b0383fSVladimir Oltean 2104*91b0383fSVladimir Oltean return NOTIFY_OK; 2105*91b0383fSVladimir Oltean default: 2106*91b0383fSVladimir Oltean return NOTIFY_DONE; 2107*91b0383fSVladimir Oltean } 2108*91b0383fSVladimir Oltean } 2109*91b0383fSVladimir Oltean 2110*91b0383fSVladimir Oltean static struct notifier_block dcbnl_nb __read_mostly = { 2111*91b0383fSVladimir Oltean .notifier_call = dcbnl_netdevice_event, 2112*91b0383fSVladimir Oltean }; 2113*91b0383fSVladimir Oltean 21142f90b865SAlexander Duyck static int __init dcbnl_init(void) 21152f90b865SAlexander Duyck { 2116*91b0383fSVladimir Oltean int err; 2117*91b0383fSVladimir Oltean 2118*91b0383fSVladimir Oltean err = register_netdevice_notifier(&dcbnl_nb); 2119*91b0383fSVladimir Oltean if (err) 2120*91b0383fSVladimir Oltean return err; 2121*91b0383fSVladimir Oltean 2122b97bac64SFlorian Westphal rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, 0); 2123b97bac64SFlorian Westphal rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, 0); 21242f90b865SAlexander Duyck 21252f90b865SAlexander Duyck return 0; 21262f90b865SAlexander Duyck } 212736b9ad80SPaul Gortmaker device_initcall(dcbnl_init); 2128