12f90b865SAlexander Duyck /* 22f90b865SAlexander Duyck * Copyright (c) 2008, Intel Corporation. 32f90b865SAlexander Duyck * 42f90b865SAlexander Duyck * This program is free software; you can redistribute it and/or modify it 52f90b865SAlexander Duyck * under the terms and conditions of the GNU General Public License, 62f90b865SAlexander Duyck * version 2, as published by the Free Software Foundation. 72f90b865SAlexander Duyck * 82f90b865SAlexander Duyck * This program is distributed in the hope it will be useful, but WITHOUT 92f90b865SAlexander Duyck * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 102f90b865SAlexander Duyck * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 112f90b865SAlexander Duyck * more details. 122f90b865SAlexander Duyck * 132f90b865SAlexander Duyck * You should have received a copy of the GNU General Public License along with 142f90b865SAlexander Duyck * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 152f90b865SAlexander Duyck * Place - Suite 330, Boston, MA 02111-1307 USA. 162f90b865SAlexander Duyck * 172f90b865SAlexander Duyck * Author: Lucy Liu <lucy.liu@intel.com> 182f90b865SAlexander Duyck */ 192f90b865SAlexander Duyck 202f90b865SAlexander Duyck #include <linux/netdevice.h> 212f90b865SAlexander Duyck #include <linux/netlink.h> 222f90b865SAlexander Duyck #include <net/netlink.h> 232f90b865SAlexander Duyck #include <net/rtnetlink.h> 242f90b865SAlexander Duyck #include <linux/dcbnl.h> 252f90b865SAlexander Duyck #include <linux/rtnetlink.h> 262f90b865SAlexander Duyck #include <net/sock.h> 272f90b865SAlexander Duyck 282f90b865SAlexander Duyck /** 292f90b865SAlexander Duyck * Data Center Bridging (DCB) is a collection of Ethernet enhancements 302f90b865SAlexander Duyck * intended to allow network traffic with differing requirements 312f90b865SAlexander Duyck * (highly reliable, no drops vs. best effort vs. low latency) to operate 322f90b865SAlexander Duyck * and co-exist on Ethernet. Current DCB features are: 332f90b865SAlexander Duyck * 342f90b865SAlexander Duyck * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a 352f90b865SAlexander Duyck * framework for assigning bandwidth guarantees to traffic classes. 362f90b865SAlexander Duyck * 372f90b865SAlexander Duyck * Priority-based Flow Control (PFC) - provides a flow control mechanism which 382f90b865SAlexander Duyck * can work independently for each 802.1p priority. 392f90b865SAlexander Duyck * 402f90b865SAlexander Duyck * Congestion Notification - provides a mechanism for end-to-end congestion 412f90b865SAlexander Duyck * control for protocols which do not have built-in congestion management. 422f90b865SAlexander Duyck * 432f90b865SAlexander Duyck * More information about the emerging standards for these Ethernet features 442f90b865SAlexander Duyck * can be found at: http://www.ieee802.org/1/pages/dcbridges.html 452f90b865SAlexander Duyck * 462f90b865SAlexander Duyck * This file implements an rtnetlink interface to allow configuration of DCB 472f90b865SAlexander Duyck * features for capable devices. 482f90b865SAlexander Duyck */ 492f90b865SAlexander Duyck 502f90b865SAlexander Duyck MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>"); 517a6b6f51SJeff Kirsher MODULE_DESCRIPTION("Data Center Bridging netlink interface"); 522f90b865SAlexander Duyck MODULE_LICENSE("GPL"); 532f90b865SAlexander Duyck 542f90b865SAlexander Duyck /**************** DCB attribute policies *************************************/ 552f90b865SAlexander Duyck 562f90b865SAlexander Duyck /* DCB netlink attributes policy */ 572f90b865SAlexander Duyck static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { 58859ee3c4SAlexander Duyck [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, 592f90b865SAlexander Duyck [DCB_ATTR_STATE] = {.type = NLA_U8}, 602f90b865SAlexander Duyck [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, 612f90b865SAlexander Duyck [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 622f90b865SAlexander Duyck [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 632f90b865SAlexander Duyck [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 6446132188SAlexander Duyck [DCB_ATTR_CAP] = {.type = NLA_NESTED}, 650eb3aa9bSAlexander Duyck [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, 66859ee3c4SAlexander Duyck [DCB_ATTR_BCN] = {.type = NLA_NESTED}, 672f90b865SAlexander Duyck }; 682f90b865SAlexander Duyck 692f90b865SAlexander Duyck /* DCB priority flow control to User Priority nested attributes */ 702f90b865SAlexander Duyck static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { 712f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, 722f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, 732f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, 742f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, 752f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, 762f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, 772f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, 782f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, 792f90b865SAlexander Duyck [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, 802f90b865SAlexander Duyck }; 812f90b865SAlexander Duyck 822f90b865SAlexander Duyck /* DCB priority grouping nested attributes */ 832f90b865SAlexander Duyck static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { 842f90b865SAlexander Duyck [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, 852f90b865SAlexander Duyck [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, 862f90b865SAlexander Duyck [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, 872f90b865SAlexander Duyck [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, 882f90b865SAlexander Duyck [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, 892f90b865SAlexander Duyck [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, 902f90b865SAlexander Duyck [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, 912f90b865SAlexander Duyck [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, 922f90b865SAlexander Duyck [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, 932f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, 942f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, 952f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, 962f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, 972f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, 982f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, 992f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, 1002f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, 1012f90b865SAlexander Duyck [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, 1022f90b865SAlexander Duyck }; 1032f90b865SAlexander Duyck 1042f90b865SAlexander Duyck /* DCB traffic class nested attributes. */ 1052f90b865SAlexander Duyck static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { 1062f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, 1072f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, 1082f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, 1092f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, 1102f90b865SAlexander Duyck [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 1112f90b865SAlexander Duyck }; 1122f90b865SAlexander Duyck 11346132188SAlexander Duyck /* DCB capabilities nested attributes. */ 11446132188SAlexander Duyck static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { 11546132188SAlexander Duyck [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, 11646132188SAlexander Duyck [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, 11746132188SAlexander Duyck [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, 11846132188SAlexander Duyck [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, 11946132188SAlexander Duyck [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, 12046132188SAlexander Duyck [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, 12146132188SAlexander Duyck [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, 12246132188SAlexander Duyck [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, 12346132188SAlexander Duyck }; 1242f90b865SAlexander Duyck 12533dbabc4SAlexander Duyck /* DCB capabilities nested attributes. */ 12633dbabc4SAlexander Duyck static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { 12733dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, 12833dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, 12933dbabc4SAlexander Duyck [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, 13033dbabc4SAlexander Duyck }; 13133dbabc4SAlexander Duyck 132859ee3c4SAlexander Duyck /* DCB BCN nested attributes. */ 133859ee3c4SAlexander Duyck static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { 134859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, 135859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, 136859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, 137859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, 138859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, 139859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, 140859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, 141859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, 142859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, 143f4314e81SDon Skidmore [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, 144f4314e81SDon Skidmore [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, 145859ee3c4SAlexander Duyck [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, 146859ee3c4SAlexander Duyck [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, 147859ee3c4SAlexander Duyck [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, 148859ee3c4SAlexander Duyck [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, 149859ee3c4SAlexander Duyck [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, 150859ee3c4SAlexander Duyck [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, 151859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, 152859ee3c4SAlexander Duyck [DCB_BCN_ATTR_W] = {.type = NLA_U32}, 153859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, 154859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, 155859ee3c4SAlexander Duyck [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, 156859ee3c4SAlexander Duyck [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, 157859ee3c4SAlexander Duyck [DCB_BCN_ATTR_C] = {.type = NLA_U32}, 158859ee3c4SAlexander Duyck [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, 159859ee3c4SAlexander Duyck }; 160859ee3c4SAlexander Duyck 1612f90b865SAlexander Duyck /* standard netlink reply call */ 1622f90b865SAlexander Duyck static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, 1632f90b865SAlexander Duyck u32 seq, u16 flags) 1642f90b865SAlexander Duyck { 1652f90b865SAlexander Duyck struct sk_buff *dcbnl_skb; 1662f90b865SAlexander Duyck struct dcbmsg *dcb; 1672f90b865SAlexander Duyck struct nlmsghdr *nlh; 1682f90b865SAlexander Duyck int ret = -EINVAL; 1692f90b865SAlexander Duyck 1702f90b865SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1712f90b865SAlexander Duyck if (!dcbnl_skb) 1722f90b865SAlexander Duyck return ret; 1732f90b865SAlexander Duyck 1742f90b865SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags); 1752f90b865SAlexander Duyck 1762f90b865SAlexander Duyck dcb = NLMSG_DATA(nlh); 1772f90b865SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 1782f90b865SAlexander Duyck dcb->cmd = cmd; 1792f90b865SAlexander Duyck dcb->dcb_pad = 0; 1802f90b865SAlexander Duyck 1812f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, attr, value); 1822f90b865SAlexander Duyck if (ret) 1832f90b865SAlexander Duyck goto err; 1842f90b865SAlexander Duyck 1852f90b865SAlexander Duyck /* end the message, assign the nlmsg_len. */ 1862f90b865SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 1872f90b865SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 1882f90b865SAlexander Duyck if (ret) 1892f90b865SAlexander Duyck goto err; 1902f90b865SAlexander Duyck 1912f90b865SAlexander Duyck return 0; 1922f90b865SAlexander Duyck nlmsg_failure: 1932f90b865SAlexander Duyck err: 194858eb711SRoel Kluin kfree_skb(dcbnl_skb); 1952f90b865SAlexander Duyck return ret; 1962f90b865SAlexander Duyck } 1972f90b865SAlexander Duyck 1982f90b865SAlexander Duyck static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb, 1992f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 2002f90b865SAlexander Duyck { 2012f90b865SAlexander Duyck int ret = -EINVAL; 2022f90b865SAlexander Duyck 2032f90b865SAlexander Duyck /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ 2042f90b865SAlexander Duyck if (!netdev->dcbnl_ops->getstate) 2052f90b865SAlexander Duyck return ret; 2062f90b865SAlexander Duyck 2072f90b865SAlexander Duyck ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB, 2082f90b865SAlexander Duyck DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags); 2092f90b865SAlexander Duyck 2102f90b865SAlexander Duyck return ret; 2112f90b865SAlexander Duyck } 2122f90b865SAlexander Duyck 2132f90b865SAlexander Duyck static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, 2142f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 2152f90b865SAlexander Duyck { 2162f90b865SAlexander Duyck struct sk_buff *dcbnl_skb; 2172f90b865SAlexander Duyck struct nlmsghdr *nlh; 2182f90b865SAlexander Duyck struct dcbmsg *dcb; 2192f90b865SAlexander Duyck struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; 2202f90b865SAlexander Duyck u8 value; 2212f90b865SAlexander Duyck int ret = -EINVAL; 2222f90b865SAlexander Duyck int i; 2232f90b865SAlexander Duyck int getall = 0; 2242f90b865SAlexander Duyck 2252f90b865SAlexander Duyck if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg) 2262f90b865SAlexander Duyck return ret; 2272f90b865SAlexander Duyck 2282f90b865SAlexander Duyck ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 2292f90b865SAlexander Duyck tb[DCB_ATTR_PFC_CFG], 2302f90b865SAlexander Duyck dcbnl_pfc_up_nest); 2312f90b865SAlexander Duyck if (ret) 2322f90b865SAlexander Duyck goto err_out; 2332f90b865SAlexander Duyck 2342f90b865SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 2352f90b865SAlexander Duyck if (!dcbnl_skb) 2362f90b865SAlexander Duyck goto err_out; 2372f90b865SAlexander Duyck 2382f90b865SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 2392f90b865SAlexander Duyck 2402f90b865SAlexander Duyck dcb = NLMSG_DATA(nlh); 2412f90b865SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 2422f90b865SAlexander Duyck dcb->cmd = DCB_CMD_PFC_GCFG; 2432f90b865SAlexander Duyck 2442f90b865SAlexander Duyck nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG); 2452f90b865SAlexander Duyck if (!nest) 2462f90b865SAlexander Duyck goto err; 2472f90b865SAlexander Duyck 2482f90b865SAlexander Duyck if (data[DCB_PFC_UP_ATTR_ALL]) 2492f90b865SAlexander Duyck getall = 1; 2502f90b865SAlexander Duyck 2512f90b865SAlexander Duyck for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 2522f90b865SAlexander Duyck if (!getall && !data[i]) 2532f90b865SAlexander Duyck continue; 2542f90b865SAlexander Duyck 2552f90b865SAlexander Duyck netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, 2562f90b865SAlexander Duyck &value); 2572f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, value); 2582f90b865SAlexander Duyck 2592f90b865SAlexander Duyck if (ret) { 2602f90b865SAlexander Duyck nla_nest_cancel(dcbnl_skb, nest); 2612f90b865SAlexander Duyck goto err; 2622f90b865SAlexander Duyck } 2632f90b865SAlexander Duyck } 2642f90b865SAlexander Duyck nla_nest_end(dcbnl_skb, nest); 2652f90b865SAlexander Duyck 2662f90b865SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 2672f90b865SAlexander Duyck 2682f90b865SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 2692f90b865SAlexander Duyck if (ret) 2702f90b865SAlexander Duyck goto err; 2712f90b865SAlexander Duyck 2722f90b865SAlexander Duyck return 0; 2732f90b865SAlexander Duyck nlmsg_failure: 2742f90b865SAlexander Duyck err: 275858eb711SRoel Kluin kfree_skb(dcbnl_skb); 2762f90b865SAlexander Duyck err_out: 2772f90b865SAlexander Duyck return -EINVAL; 2782f90b865SAlexander Duyck } 2792f90b865SAlexander Duyck 2802f90b865SAlexander Duyck static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, 2812f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 2822f90b865SAlexander Duyck { 2832f90b865SAlexander Duyck struct sk_buff *dcbnl_skb; 2842f90b865SAlexander Duyck struct nlmsghdr *nlh; 2852f90b865SAlexander Duyck struct dcbmsg *dcb; 2862f90b865SAlexander Duyck u8 perm_addr[MAX_ADDR_LEN]; 2872f90b865SAlexander Duyck int ret = -EINVAL; 2882f90b865SAlexander Duyck 2892f90b865SAlexander Duyck if (!netdev->dcbnl_ops->getpermhwaddr) 2902f90b865SAlexander Duyck return ret; 2912f90b865SAlexander Duyck 2922f90b865SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 2932f90b865SAlexander Duyck if (!dcbnl_skb) 2942f90b865SAlexander Duyck goto err_out; 2952f90b865SAlexander Duyck 2962f90b865SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 2972f90b865SAlexander Duyck 2982f90b865SAlexander Duyck dcb = NLMSG_DATA(nlh); 2992f90b865SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 3002f90b865SAlexander Duyck dcb->cmd = DCB_CMD_GPERM_HWADDR; 3012f90b865SAlexander Duyck 3022f90b865SAlexander Duyck netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); 3032f90b865SAlexander Duyck 3042f90b865SAlexander Duyck ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), 3052f90b865SAlexander Duyck perm_addr); 3062f90b865SAlexander Duyck 3072f90b865SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 3082f90b865SAlexander Duyck 3092f90b865SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 3102f90b865SAlexander Duyck if (ret) 3112f90b865SAlexander Duyck goto err; 3122f90b865SAlexander Duyck 3132f90b865SAlexander Duyck return 0; 3142f90b865SAlexander Duyck 3152f90b865SAlexander Duyck nlmsg_failure: 3162f90b865SAlexander Duyck err: 317858eb711SRoel Kluin kfree_skb(dcbnl_skb); 3182f90b865SAlexander Duyck err_out: 3192f90b865SAlexander Duyck return -EINVAL; 3202f90b865SAlexander Duyck } 3212f90b865SAlexander Duyck 32246132188SAlexander Duyck static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, 32346132188SAlexander Duyck u32 pid, u32 seq, u16 flags) 32446132188SAlexander Duyck { 32546132188SAlexander Duyck struct sk_buff *dcbnl_skb; 32646132188SAlexander Duyck struct nlmsghdr *nlh; 32746132188SAlexander Duyck struct dcbmsg *dcb; 32846132188SAlexander Duyck struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; 32946132188SAlexander Duyck u8 value; 33046132188SAlexander Duyck int ret = -EINVAL; 33146132188SAlexander Duyck int i; 33246132188SAlexander Duyck int getall = 0; 33346132188SAlexander Duyck 33446132188SAlexander Duyck if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap) 33546132188SAlexander Duyck return ret; 33646132188SAlexander Duyck 33746132188SAlexander Duyck ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], 33846132188SAlexander Duyck dcbnl_cap_nest); 33946132188SAlexander Duyck if (ret) 34046132188SAlexander Duyck goto err_out; 34146132188SAlexander Duyck 34246132188SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 34346132188SAlexander Duyck if (!dcbnl_skb) 34446132188SAlexander Duyck goto err_out; 34546132188SAlexander Duyck 34646132188SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 34746132188SAlexander Duyck 34846132188SAlexander Duyck dcb = NLMSG_DATA(nlh); 34946132188SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 35046132188SAlexander Duyck dcb->cmd = DCB_CMD_GCAP; 35146132188SAlexander Duyck 35246132188SAlexander Duyck nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP); 35346132188SAlexander Duyck if (!nest) 35446132188SAlexander Duyck goto err; 35546132188SAlexander Duyck 35646132188SAlexander Duyck if (data[DCB_CAP_ATTR_ALL]) 35746132188SAlexander Duyck getall = 1; 35846132188SAlexander Duyck 35946132188SAlexander Duyck for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { 36046132188SAlexander Duyck if (!getall && !data[i]) 36146132188SAlexander Duyck continue; 36246132188SAlexander Duyck 36346132188SAlexander Duyck if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { 36446132188SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, value); 36546132188SAlexander Duyck 36646132188SAlexander Duyck if (ret) { 36746132188SAlexander Duyck nla_nest_cancel(dcbnl_skb, nest); 36846132188SAlexander Duyck goto err; 36946132188SAlexander Duyck } 37046132188SAlexander Duyck } 37146132188SAlexander Duyck } 37246132188SAlexander Duyck nla_nest_end(dcbnl_skb, nest); 37346132188SAlexander Duyck 37446132188SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 37546132188SAlexander Duyck 37646132188SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 37746132188SAlexander Duyck if (ret) 37846132188SAlexander Duyck goto err; 37946132188SAlexander Duyck 38046132188SAlexander Duyck return 0; 38146132188SAlexander Duyck nlmsg_failure: 38246132188SAlexander Duyck err: 383858eb711SRoel Kluin kfree_skb(dcbnl_skb); 38446132188SAlexander Duyck err_out: 38546132188SAlexander Duyck return -EINVAL; 38646132188SAlexander Duyck } 38746132188SAlexander Duyck 38833dbabc4SAlexander Duyck static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, 38933dbabc4SAlexander Duyck u32 pid, u32 seq, u16 flags) 39033dbabc4SAlexander Duyck { 39133dbabc4SAlexander Duyck struct sk_buff *dcbnl_skb; 39233dbabc4SAlexander Duyck struct nlmsghdr *nlh; 39333dbabc4SAlexander Duyck struct dcbmsg *dcb; 39433dbabc4SAlexander Duyck struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; 39533dbabc4SAlexander Duyck u8 value; 39633dbabc4SAlexander Duyck int ret = -EINVAL; 39733dbabc4SAlexander Duyck int i; 39833dbabc4SAlexander Duyck int getall = 0; 39933dbabc4SAlexander Duyck 40033dbabc4SAlexander Duyck if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) 40133dbabc4SAlexander Duyck return ret; 40233dbabc4SAlexander Duyck 40333dbabc4SAlexander Duyck ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 40433dbabc4SAlexander Duyck dcbnl_numtcs_nest); 40533dbabc4SAlexander Duyck if (ret) { 40633dbabc4SAlexander Duyck ret = -EINVAL; 40733dbabc4SAlexander Duyck goto err_out; 40833dbabc4SAlexander Duyck } 40933dbabc4SAlexander Duyck 41033dbabc4SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 41133dbabc4SAlexander Duyck if (!dcbnl_skb) { 41233dbabc4SAlexander Duyck ret = -EINVAL; 41333dbabc4SAlexander Duyck goto err_out; 41433dbabc4SAlexander Duyck } 41533dbabc4SAlexander Duyck 41633dbabc4SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 41733dbabc4SAlexander Duyck 41833dbabc4SAlexander Duyck dcb = NLMSG_DATA(nlh); 41933dbabc4SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 42033dbabc4SAlexander Duyck dcb->cmd = DCB_CMD_GNUMTCS; 42133dbabc4SAlexander Duyck 42233dbabc4SAlexander Duyck nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); 42333dbabc4SAlexander Duyck if (!nest) { 42433dbabc4SAlexander Duyck ret = -EINVAL; 42533dbabc4SAlexander Duyck goto err; 42633dbabc4SAlexander Duyck } 42733dbabc4SAlexander Duyck 42833dbabc4SAlexander Duyck if (data[DCB_NUMTCS_ATTR_ALL]) 42933dbabc4SAlexander Duyck getall = 1; 43033dbabc4SAlexander Duyck 43133dbabc4SAlexander Duyck for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 43233dbabc4SAlexander Duyck if (!getall && !data[i]) 43333dbabc4SAlexander Duyck continue; 43433dbabc4SAlexander Duyck 43533dbabc4SAlexander Duyck ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); 43633dbabc4SAlexander Duyck if (!ret) { 43733dbabc4SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, value); 43833dbabc4SAlexander Duyck 43933dbabc4SAlexander Duyck if (ret) { 44033dbabc4SAlexander Duyck nla_nest_cancel(dcbnl_skb, nest); 44133dbabc4SAlexander Duyck ret = -EINVAL; 44233dbabc4SAlexander Duyck goto err; 44333dbabc4SAlexander Duyck } 44433dbabc4SAlexander Duyck } else { 44533dbabc4SAlexander Duyck goto err; 44633dbabc4SAlexander Duyck } 44733dbabc4SAlexander Duyck } 44833dbabc4SAlexander Duyck nla_nest_end(dcbnl_skb, nest); 44933dbabc4SAlexander Duyck 45033dbabc4SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 45133dbabc4SAlexander Duyck 45233dbabc4SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 45333dbabc4SAlexander Duyck if (ret) { 45433dbabc4SAlexander Duyck ret = -EINVAL; 45533dbabc4SAlexander Duyck goto err; 45633dbabc4SAlexander Duyck } 45733dbabc4SAlexander Duyck 45833dbabc4SAlexander Duyck return 0; 45933dbabc4SAlexander Duyck nlmsg_failure: 46033dbabc4SAlexander Duyck err: 461858eb711SRoel Kluin kfree_skb(dcbnl_skb); 46233dbabc4SAlexander Duyck err_out: 46333dbabc4SAlexander Duyck return ret; 46433dbabc4SAlexander Duyck } 46533dbabc4SAlexander Duyck 46633dbabc4SAlexander Duyck static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, 46733dbabc4SAlexander Duyck u32 pid, u32 seq, u16 flags) 46833dbabc4SAlexander Duyck { 46933dbabc4SAlexander Duyck struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; 47033dbabc4SAlexander Duyck int ret = -EINVAL; 47133dbabc4SAlexander Duyck u8 value; 47233dbabc4SAlexander Duyck int i; 47333dbabc4SAlexander Duyck 4748b124a8eSDon Skidmore if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs) 47533dbabc4SAlexander Duyck return ret; 47633dbabc4SAlexander Duyck 47733dbabc4SAlexander Duyck ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 47833dbabc4SAlexander Duyck dcbnl_numtcs_nest); 47933dbabc4SAlexander Duyck 48033dbabc4SAlexander Duyck if (ret) { 48133dbabc4SAlexander Duyck ret = -EINVAL; 48233dbabc4SAlexander Duyck goto err; 48333dbabc4SAlexander Duyck } 48433dbabc4SAlexander Duyck 48533dbabc4SAlexander Duyck for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 48633dbabc4SAlexander Duyck if (data[i] == NULL) 48733dbabc4SAlexander Duyck continue; 48833dbabc4SAlexander Duyck 48933dbabc4SAlexander Duyck value = nla_get_u8(data[i]); 49033dbabc4SAlexander Duyck 49133dbabc4SAlexander Duyck ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); 49233dbabc4SAlexander Duyck 49333dbabc4SAlexander Duyck if (ret) 49433dbabc4SAlexander Duyck goto operr; 49533dbabc4SAlexander Duyck } 49633dbabc4SAlexander Duyck 49733dbabc4SAlexander Duyck operr: 49833dbabc4SAlexander Duyck ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS, 49933dbabc4SAlexander Duyck DCB_ATTR_NUMTCS, pid, seq, flags); 50033dbabc4SAlexander Duyck 50133dbabc4SAlexander Duyck err: 50233dbabc4SAlexander Duyck return ret; 50333dbabc4SAlexander Duyck } 50433dbabc4SAlexander Duyck 5050eb3aa9bSAlexander Duyck static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb, 5060eb3aa9bSAlexander Duyck u32 pid, u32 seq, u16 flags) 5070eb3aa9bSAlexander Duyck { 5080eb3aa9bSAlexander Duyck int ret = -EINVAL; 5090eb3aa9bSAlexander Duyck 5100eb3aa9bSAlexander Duyck if (!netdev->dcbnl_ops->getpfcstate) 5110eb3aa9bSAlexander Duyck return ret; 5120eb3aa9bSAlexander Duyck 5130eb3aa9bSAlexander Duyck ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB, 5140eb3aa9bSAlexander Duyck DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE, 5150eb3aa9bSAlexander Duyck pid, seq, flags); 5160eb3aa9bSAlexander Duyck 5170eb3aa9bSAlexander Duyck return ret; 5180eb3aa9bSAlexander Duyck } 5190eb3aa9bSAlexander Duyck 5200eb3aa9bSAlexander Duyck static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, 5210eb3aa9bSAlexander Duyck u32 pid, u32 seq, u16 flags) 5220eb3aa9bSAlexander Duyck { 5230eb3aa9bSAlexander Duyck int ret = -EINVAL; 5240eb3aa9bSAlexander Duyck u8 value; 5250eb3aa9bSAlexander Duyck 5260eb3aa9bSAlexander Duyck if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate) 5270eb3aa9bSAlexander Duyck return ret; 5280eb3aa9bSAlexander Duyck 5290eb3aa9bSAlexander Duyck value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); 5300eb3aa9bSAlexander Duyck 5310eb3aa9bSAlexander Duyck netdev->dcbnl_ops->setpfcstate(netdev, value); 5320eb3aa9bSAlexander Duyck 5330eb3aa9bSAlexander Duyck ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE, 5340eb3aa9bSAlexander Duyck pid, seq, flags); 5350eb3aa9bSAlexander Duyck 5360eb3aa9bSAlexander Duyck return ret; 5370eb3aa9bSAlexander Duyck } 5380eb3aa9bSAlexander Duyck 5392f90b865SAlexander Duyck static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, 5402f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags, int dir) 5412f90b865SAlexander Duyck { 5422f90b865SAlexander Duyck struct sk_buff *dcbnl_skb; 5432f90b865SAlexander Duyck struct nlmsghdr *nlh; 5442f90b865SAlexander Duyck struct dcbmsg *dcb; 5452f90b865SAlexander Duyck struct nlattr *pg_nest, *param_nest, *data; 5462f90b865SAlexander Duyck struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 5472f90b865SAlexander Duyck struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 5482f90b865SAlexander Duyck u8 prio, pgid, tc_pct, up_map; 5492f90b865SAlexander Duyck int ret = -EINVAL; 5502f90b865SAlexander Duyck int getall = 0; 5512f90b865SAlexander Duyck int i; 5522f90b865SAlexander Duyck 5532f90b865SAlexander Duyck if (!tb[DCB_ATTR_PG_CFG] || 5542f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgtccfgtx || 5552f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgtccfgrx || 5562f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgbwgcfgtx || 5572f90b865SAlexander Duyck !netdev->dcbnl_ops->getpgbwgcfgrx) 5582f90b865SAlexander Duyck return ret; 5592f90b865SAlexander Duyck 5602f90b865SAlexander Duyck ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 5612f90b865SAlexander Duyck tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 5622f90b865SAlexander Duyck 5632f90b865SAlexander Duyck if (ret) 5642f90b865SAlexander Duyck goto err_out; 5652f90b865SAlexander Duyck 5662f90b865SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 5672f90b865SAlexander Duyck if (!dcbnl_skb) 5682f90b865SAlexander Duyck goto err_out; 5692f90b865SAlexander Duyck 5702f90b865SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 5712f90b865SAlexander Duyck 5722f90b865SAlexander Duyck dcb = NLMSG_DATA(nlh); 5732f90b865SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 5742f90b865SAlexander Duyck dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG; 5752f90b865SAlexander Duyck 5762f90b865SAlexander Duyck pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG); 5772f90b865SAlexander Duyck if (!pg_nest) 5782f90b865SAlexander Duyck goto err; 5792f90b865SAlexander Duyck 5802f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_TC_ALL]) 5812f90b865SAlexander Duyck getall = 1; 5822f90b865SAlexander Duyck 5832f90b865SAlexander Duyck for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 5842f90b865SAlexander Duyck if (!getall && !pg_tb[i]) 5852f90b865SAlexander Duyck continue; 5862f90b865SAlexander Duyck 5872f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_TC_ALL]) 5882f90b865SAlexander Duyck data = pg_tb[DCB_PG_ATTR_TC_ALL]; 5892f90b865SAlexander Duyck else 5902f90b865SAlexander Duyck data = pg_tb[i]; 5912f90b865SAlexander Duyck ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 5922f90b865SAlexander Duyck data, dcbnl_tc_param_nest); 5932f90b865SAlexander Duyck if (ret) 5942f90b865SAlexander Duyck goto err_pg; 5952f90b865SAlexander Duyck 5962f90b865SAlexander Duyck param_nest = nla_nest_start(dcbnl_skb, i); 5972f90b865SAlexander Duyck if (!param_nest) 5982f90b865SAlexander Duyck goto err_pg; 5992f90b865SAlexander Duyck 6002f90b865SAlexander Duyck pgid = DCB_ATTR_VALUE_UNDEFINED; 6012f90b865SAlexander Duyck prio = DCB_ATTR_VALUE_UNDEFINED; 6022f90b865SAlexander Duyck tc_pct = DCB_ATTR_VALUE_UNDEFINED; 6032f90b865SAlexander Duyck up_map = DCB_ATTR_VALUE_UNDEFINED; 6042f90b865SAlexander Duyck 6052f90b865SAlexander Duyck if (dir) { 6062f90b865SAlexander Duyck /* Rx */ 6072f90b865SAlexander Duyck netdev->dcbnl_ops->getpgtccfgrx(netdev, 6082f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, &prio, 6092f90b865SAlexander Duyck &pgid, &tc_pct, &up_map); 6102f90b865SAlexander Duyck } else { 6112f90b865SAlexander Duyck /* Tx */ 6122f90b865SAlexander Duyck netdev->dcbnl_ops->getpgtccfgtx(netdev, 6132f90b865SAlexander Duyck i - DCB_PG_ATTR_TC_0, &prio, 6142f90b865SAlexander Duyck &pgid, &tc_pct, &up_map); 6152f90b865SAlexander Duyck } 6162f90b865SAlexander Duyck 6172f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_PGID] || 6182f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 6192f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, 6202f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_PGID, pgid); 6212f90b865SAlexander Duyck if (ret) 6222f90b865SAlexander Duyck goto err_param; 6232f90b865SAlexander Duyck } 6242f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || 6252f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 6262f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, 6272f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); 6282f90b865SAlexander Duyck if (ret) 6292f90b865SAlexander Duyck goto err_param; 6302f90b865SAlexander Duyck } 6312f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || 6322f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 6332f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, 6342f90b865SAlexander Duyck DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); 6352f90b865SAlexander Duyck if (ret) 6362f90b865SAlexander Duyck goto err_param; 6372f90b865SAlexander Duyck } 6382f90b865SAlexander Duyck if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || 6392f90b865SAlexander Duyck param_tb[DCB_TC_ATTR_PARAM_ALL]) { 6402f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT, 6412f90b865SAlexander Duyck tc_pct); 6422f90b865SAlexander Duyck if (ret) 6432f90b865SAlexander Duyck goto err_param; 6442f90b865SAlexander Duyck } 6452f90b865SAlexander Duyck nla_nest_end(dcbnl_skb, param_nest); 6462f90b865SAlexander Duyck } 6472f90b865SAlexander Duyck 6482f90b865SAlexander Duyck if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) 6492f90b865SAlexander Duyck getall = 1; 6502f90b865SAlexander Duyck else 6512f90b865SAlexander Duyck getall = 0; 6522f90b865SAlexander Duyck 6532f90b865SAlexander Duyck for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 6542f90b865SAlexander Duyck if (!getall && !pg_tb[i]) 6552f90b865SAlexander Duyck continue; 6562f90b865SAlexander Duyck 6572f90b865SAlexander Duyck tc_pct = DCB_ATTR_VALUE_UNDEFINED; 6582f90b865SAlexander Duyck 6592f90b865SAlexander Duyck if (dir) { 6602f90b865SAlexander Duyck /* Rx */ 6612f90b865SAlexander Duyck netdev->dcbnl_ops->getpgbwgcfgrx(netdev, 6622f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 6632f90b865SAlexander Duyck } else { 6642f90b865SAlexander Duyck /* Tx */ 6652f90b865SAlexander Duyck netdev->dcbnl_ops->getpgbwgcfgtx(netdev, 6662f90b865SAlexander Duyck i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 6672f90b865SAlexander Duyck } 6682f90b865SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, tc_pct); 6692f90b865SAlexander Duyck 6702f90b865SAlexander Duyck if (ret) 6712f90b865SAlexander Duyck goto err_pg; 6722f90b865SAlexander Duyck } 6732f90b865SAlexander Duyck 6742f90b865SAlexander Duyck nla_nest_end(dcbnl_skb, pg_nest); 6752f90b865SAlexander Duyck 6762f90b865SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 6772f90b865SAlexander Duyck 6782f90b865SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 6792f90b865SAlexander Duyck if (ret) 6802f90b865SAlexander Duyck goto err; 6812f90b865SAlexander Duyck 6822f90b865SAlexander Duyck return 0; 6832f90b865SAlexander Duyck 6842f90b865SAlexander Duyck err_param: 6852f90b865SAlexander Duyck nla_nest_cancel(dcbnl_skb, param_nest); 6862f90b865SAlexander Duyck err_pg: 6872f90b865SAlexander Duyck nla_nest_cancel(dcbnl_skb, pg_nest); 6882f90b865SAlexander Duyck nlmsg_failure: 6892f90b865SAlexander Duyck err: 690858eb711SRoel Kluin kfree_skb(dcbnl_skb); 6912f90b865SAlexander Duyck err_out: 6922f90b865SAlexander Duyck ret = -EINVAL; 6932f90b865SAlexander Duyck return ret; 6942f90b865SAlexander Duyck } 6952f90b865SAlexander Duyck 6962f90b865SAlexander Duyck static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb, 6972f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 6982f90b865SAlexander Duyck { 6992f90b865SAlexander Duyck return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0); 7002f90b865SAlexander Duyck } 7012f90b865SAlexander Duyck 7022f90b865SAlexander Duyck static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb, 7032f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 7042f90b865SAlexander Duyck { 7052f90b865SAlexander Duyck return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1); 7062f90b865SAlexander Duyck } 7072f90b865SAlexander Duyck 7082f90b865SAlexander Duyck static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb, 7092f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 7102f90b865SAlexander Duyck { 7112f90b865SAlexander Duyck int ret = -EINVAL; 7122f90b865SAlexander Duyck u8 value; 7132f90b865SAlexander Duyck 7142f90b865SAlexander Duyck if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate) 7152f90b865SAlexander Duyck return ret; 7162f90b865SAlexander Duyck 7172f90b865SAlexander Duyck value = nla_get_u8(tb[DCB_ATTR_STATE]); 7182f90b865SAlexander Duyck 7191486a61eSDon Skidmore ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value), 7201486a61eSDon Skidmore RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, 7212f90b865SAlexander Duyck pid, seq, flags); 7222f90b865SAlexander Duyck 7232f90b865SAlexander Duyck return ret; 7242f90b865SAlexander Duyck } 7252f90b865SAlexander Duyck 7262f90b865SAlexander Duyck static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb, 7272f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 7282f90b865SAlexander Duyck { 7292f90b865SAlexander Duyck struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; 7302f90b865SAlexander Duyck int i; 7312f90b865SAlexander Duyck int ret = -EINVAL; 7322f90b865SAlexander Duyck u8 value; 7332f90b865SAlexander Duyck 7342f90b865SAlexander Duyck if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg) 7352f90b865SAlexander Duyck return ret; 7362f90b865SAlexander Duyck 7372f90b865SAlexander Duyck ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 7382f90b865SAlexander Duyck tb[DCB_ATTR_PFC_CFG], 7392f90b865SAlexander Duyck dcbnl_pfc_up_nest); 7402f90b865SAlexander Duyck if (ret) 7412f90b865SAlexander Duyck goto err; 7422f90b865SAlexander Duyck 7432f90b865SAlexander Duyck for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 7442f90b865SAlexander Duyck if (data[i] == NULL) 7452f90b865SAlexander Duyck continue; 7462f90b865SAlexander Duyck value = nla_get_u8(data[i]); 7472f90b865SAlexander Duyck netdev->dcbnl_ops->setpfccfg(netdev, 7482f90b865SAlexander Duyck data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); 7492f90b865SAlexander Duyck } 7502f90b865SAlexander Duyck 7512f90b865SAlexander Duyck ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG, 7522f90b865SAlexander Duyck pid, seq, flags); 7532f90b865SAlexander Duyck err: 7542f90b865SAlexander Duyck return ret; 7552f90b865SAlexander Duyck } 7562f90b865SAlexander Duyck 7572f90b865SAlexander Duyck static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb, 7582f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 7592f90b865SAlexander Duyck { 7602f90b865SAlexander Duyck int ret = -EINVAL; 7612f90b865SAlexander Duyck 7622f90b865SAlexander Duyck if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall) 7632f90b865SAlexander Duyck return ret; 7642f90b865SAlexander Duyck 7652f90b865SAlexander Duyck ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB, 7662f90b865SAlexander Duyck DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags); 7672f90b865SAlexander Duyck 7682f90b865SAlexander Duyck return ret; 7692f90b865SAlexander Duyck } 7702f90b865SAlexander Duyck 7712f90b865SAlexander Duyck static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb, 7722f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags, int dir) 7732f90b865SAlexander Duyck { 7742f90b865SAlexander Duyck struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 7752f90b865SAlexander Duyck struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 7762f90b865SAlexander Duyck int ret = -EINVAL; 7772f90b865SAlexander Duyck int i; 7782f90b865SAlexander Duyck u8 pgid; 7792f90b865SAlexander Duyck u8 up_map; 7802f90b865SAlexander Duyck u8 prio; 7812f90b865SAlexander Duyck u8 tc_pct; 7822f90b865SAlexander Duyck 7832f90b865SAlexander Duyck if (!tb[DCB_ATTR_PG_CFG] || 7842f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgtccfgtx || 7852f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgtccfgrx || 7862f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgbwgcfgtx || 7872f90b865SAlexander Duyck !netdev->dcbnl_ops->setpgbwgcfgrx) 7882f90b865SAlexander Duyck return ret; 7892f90b865SAlexander Duyck 7902f90b865SAlexander Duyck ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 7912f90b865SAlexander Duyck tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 7922f90b865SAlexander Duyck if (ret) 7932f90b865SAlexander Duyck goto err; 7942f90b865SAlexander Duyck 7952f90b865SAlexander Duyck for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 7962f90b865SAlexander Duyck if (!pg_tb[i]) 7972f90b865SAlexander Duyck continue; 7982f90b865SAlexander Duyck 7992f90b865SAlexander Duyck ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 8002f90b865SAlexander Duyck pg_tb[i], dcbnl_tc_param_nest); 8012f90b865SAlexander Duyck if (ret) 8022f90b865SAlexander Duyck goto err; 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 8552f90b865SAlexander Duyck ret = dcbnl_reply(0, RTM_SETDCB, 8562f90b865SAlexander Duyck (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG), 8572f90b865SAlexander Duyck DCB_ATTR_PG_CFG, pid, seq, flags); 8582f90b865SAlexander Duyck 8592f90b865SAlexander Duyck err: 8602f90b865SAlexander Duyck return ret; 8612f90b865SAlexander Duyck } 8622f90b865SAlexander Duyck 8632f90b865SAlexander Duyck static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb, 8642f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 8652f90b865SAlexander Duyck { 8662f90b865SAlexander Duyck return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0); 8672f90b865SAlexander Duyck } 8682f90b865SAlexander Duyck 8692f90b865SAlexander Duyck static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb, 8702f90b865SAlexander Duyck u32 pid, u32 seq, u16 flags) 8712f90b865SAlexander Duyck { 8722f90b865SAlexander Duyck return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1); 8732f90b865SAlexander Duyck } 8742f90b865SAlexander Duyck 875859ee3c4SAlexander Duyck static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, 876859ee3c4SAlexander Duyck u32 pid, u32 seq, u16 flags) 877859ee3c4SAlexander Duyck { 878859ee3c4SAlexander Duyck struct sk_buff *dcbnl_skb; 879859ee3c4SAlexander Duyck struct nlmsghdr *nlh; 880859ee3c4SAlexander Duyck struct dcbmsg *dcb; 881859ee3c4SAlexander Duyck struct nlattr *bcn_nest; 882859ee3c4SAlexander Duyck struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; 883859ee3c4SAlexander Duyck u8 value_byte; 884859ee3c4SAlexander Duyck u32 value_integer; 885859ee3c4SAlexander Duyck int ret = -EINVAL; 886859ee3c4SAlexander Duyck bool getall = false; 887859ee3c4SAlexander Duyck int i; 888859ee3c4SAlexander Duyck 889859ee3c4SAlexander Duyck if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp || 890859ee3c4SAlexander Duyck !netdev->dcbnl_ops->getbcncfg) 891859ee3c4SAlexander Duyck return ret; 892859ee3c4SAlexander Duyck 893859ee3c4SAlexander Duyck ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, 894859ee3c4SAlexander Duyck tb[DCB_ATTR_BCN], dcbnl_bcn_nest); 895859ee3c4SAlexander Duyck 896859ee3c4SAlexander Duyck if (ret) 897859ee3c4SAlexander Duyck goto err_out; 898859ee3c4SAlexander Duyck 899859ee3c4SAlexander Duyck dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 900859ee3c4SAlexander Duyck if (!dcbnl_skb) 901859ee3c4SAlexander Duyck goto err_out; 902859ee3c4SAlexander Duyck 903859ee3c4SAlexander Duyck nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 904859ee3c4SAlexander Duyck 905859ee3c4SAlexander Duyck dcb = NLMSG_DATA(nlh); 906859ee3c4SAlexander Duyck dcb->dcb_family = AF_UNSPEC; 907859ee3c4SAlexander Duyck dcb->cmd = DCB_CMD_BCN_GCFG; 908859ee3c4SAlexander Duyck 909859ee3c4SAlexander Duyck bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN); 910859ee3c4SAlexander Duyck if (!bcn_nest) 911859ee3c4SAlexander Duyck goto err; 912859ee3c4SAlexander Duyck 913859ee3c4SAlexander Duyck if (bcn_tb[DCB_BCN_ATTR_ALL]) 914859ee3c4SAlexander Duyck getall = true; 915859ee3c4SAlexander Duyck 916859ee3c4SAlexander Duyck for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 917859ee3c4SAlexander Duyck if (!getall && !bcn_tb[i]) 918859ee3c4SAlexander Duyck continue; 919859ee3c4SAlexander Duyck 920859ee3c4SAlexander Duyck netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, 921859ee3c4SAlexander Duyck &value_byte); 922859ee3c4SAlexander Duyck ret = nla_put_u8(dcbnl_skb, i, value_byte); 923859ee3c4SAlexander Duyck if (ret) 924859ee3c4SAlexander Duyck goto err_bcn; 925859ee3c4SAlexander Duyck } 926859ee3c4SAlexander Duyck 927f4314e81SDon Skidmore for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 928859ee3c4SAlexander Duyck if (!getall && !bcn_tb[i]) 929859ee3c4SAlexander Duyck continue; 930859ee3c4SAlexander Duyck 931859ee3c4SAlexander Duyck netdev->dcbnl_ops->getbcncfg(netdev, i, 932859ee3c4SAlexander Duyck &value_integer); 933859ee3c4SAlexander Duyck ret = nla_put_u32(dcbnl_skb, i, value_integer); 934859ee3c4SAlexander Duyck if (ret) 935859ee3c4SAlexander Duyck goto err_bcn; 936859ee3c4SAlexander Duyck } 937859ee3c4SAlexander Duyck 938859ee3c4SAlexander Duyck nla_nest_end(dcbnl_skb, bcn_nest); 939859ee3c4SAlexander Duyck 940859ee3c4SAlexander Duyck nlmsg_end(dcbnl_skb, nlh); 941859ee3c4SAlexander Duyck 942859ee3c4SAlexander Duyck ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 943859ee3c4SAlexander Duyck if (ret) 944859ee3c4SAlexander Duyck goto err; 945859ee3c4SAlexander Duyck 946859ee3c4SAlexander Duyck return 0; 947859ee3c4SAlexander Duyck 948859ee3c4SAlexander Duyck err_bcn: 949859ee3c4SAlexander Duyck nla_nest_cancel(dcbnl_skb, bcn_nest); 950859ee3c4SAlexander Duyck nlmsg_failure: 951859ee3c4SAlexander Duyck err: 952858eb711SRoel Kluin kfree_skb(dcbnl_skb); 953859ee3c4SAlexander Duyck err_out: 954859ee3c4SAlexander Duyck ret = -EINVAL; 955859ee3c4SAlexander Duyck return ret; 956859ee3c4SAlexander Duyck } 957859ee3c4SAlexander Duyck 958859ee3c4SAlexander Duyck static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, 959859ee3c4SAlexander Duyck u32 pid, u32 seq, u16 flags) 960859ee3c4SAlexander Duyck { 961859ee3c4SAlexander Duyck struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; 962859ee3c4SAlexander Duyck int i; 963859ee3c4SAlexander Duyck int ret = -EINVAL; 964859ee3c4SAlexander Duyck u8 value_byte; 965859ee3c4SAlexander Duyck u32 value_int; 966859ee3c4SAlexander Duyck 967859ee3c4SAlexander Duyck if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg 968859ee3c4SAlexander Duyck || !netdev->dcbnl_ops->setbcnrp) 969859ee3c4SAlexander Duyck return ret; 970859ee3c4SAlexander Duyck 971859ee3c4SAlexander Duyck ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, 972859ee3c4SAlexander Duyck tb[DCB_ATTR_BCN], 973859ee3c4SAlexander Duyck dcbnl_pfc_up_nest); 974859ee3c4SAlexander Duyck if (ret) 975859ee3c4SAlexander Duyck goto err; 976859ee3c4SAlexander Duyck 977859ee3c4SAlexander Duyck for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 978859ee3c4SAlexander Duyck if (data[i] == NULL) 979859ee3c4SAlexander Duyck continue; 980859ee3c4SAlexander Duyck value_byte = nla_get_u8(data[i]); 981859ee3c4SAlexander Duyck netdev->dcbnl_ops->setbcnrp(netdev, 982859ee3c4SAlexander Duyck data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); 983859ee3c4SAlexander Duyck } 984859ee3c4SAlexander Duyck 985f4314e81SDon Skidmore for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 986859ee3c4SAlexander Duyck if (data[i] == NULL) 987859ee3c4SAlexander Duyck continue; 988859ee3c4SAlexander Duyck value_int = nla_get_u32(data[i]); 989859ee3c4SAlexander Duyck netdev->dcbnl_ops->setbcncfg(netdev, 990859ee3c4SAlexander Duyck i, value_int); 991859ee3c4SAlexander Duyck } 992859ee3c4SAlexander Duyck 993859ee3c4SAlexander Duyck ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN, 994859ee3c4SAlexander Duyck pid, seq, flags); 995859ee3c4SAlexander Duyck err: 996859ee3c4SAlexander Duyck return ret; 997859ee3c4SAlexander Duyck } 998859ee3c4SAlexander Duyck 9992f90b865SAlexander Duyck static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 10002f90b865SAlexander Duyck { 10012f90b865SAlexander Duyck struct net *net = sock_net(skb->sk); 10022f90b865SAlexander Duyck struct net_device *netdev; 10032f90b865SAlexander Duyck struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh); 10042f90b865SAlexander Duyck struct nlattr *tb[DCB_ATTR_MAX + 1]; 10052f90b865SAlexander Duyck u32 pid = skb ? NETLINK_CB(skb).pid : 0; 10062f90b865SAlexander Duyck int ret = -EINVAL; 10072f90b865SAlexander Duyck 10082f90b865SAlexander Duyck if (net != &init_net) 10092f90b865SAlexander Duyck return -EINVAL; 10102f90b865SAlexander Duyck 10112f90b865SAlexander Duyck ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 10122f90b865SAlexander Duyck dcbnl_rtnl_policy); 10132f90b865SAlexander Duyck if (ret < 0) 10142f90b865SAlexander Duyck return ret; 10152f90b865SAlexander Duyck 10162f90b865SAlexander Duyck if (!tb[DCB_ATTR_IFNAME]) 10172f90b865SAlexander Duyck return -EINVAL; 10182f90b865SAlexander Duyck 10192f90b865SAlexander Duyck netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME])); 10202f90b865SAlexander Duyck if (!netdev) 10212f90b865SAlexander Duyck return -EINVAL; 10222f90b865SAlexander Duyck 10232f90b865SAlexander Duyck if (!netdev->dcbnl_ops) 10242f90b865SAlexander Duyck goto errout; 10252f90b865SAlexander Duyck 10262f90b865SAlexander Duyck switch (dcb->cmd) { 10272f90b865SAlexander Duyck case DCB_CMD_GSTATE: 10282f90b865SAlexander Duyck ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, 10292f90b865SAlexander Duyck nlh->nlmsg_flags); 10302f90b865SAlexander Duyck goto out; 10312f90b865SAlexander Duyck case DCB_CMD_PFC_GCFG: 10322f90b865SAlexander Duyck ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq, 10332f90b865SAlexander Duyck nlh->nlmsg_flags); 10342f90b865SAlexander Duyck goto out; 10352f90b865SAlexander Duyck case DCB_CMD_GPERM_HWADDR: 10362f90b865SAlexander Duyck ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq, 10372f90b865SAlexander Duyck nlh->nlmsg_flags); 10382f90b865SAlexander Duyck goto out; 10392f90b865SAlexander Duyck case DCB_CMD_PGTX_GCFG: 10402f90b865SAlexander Duyck ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 10412f90b865SAlexander Duyck nlh->nlmsg_flags); 10422f90b865SAlexander Duyck goto out; 10432f90b865SAlexander Duyck case DCB_CMD_PGRX_GCFG: 10442f90b865SAlexander Duyck ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 10452f90b865SAlexander Duyck nlh->nlmsg_flags); 10462f90b865SAlexander Duyck goto out; 1047859ee3c4SAlexander Duyck case DCB_CMD_BCN_GCFG: 1048859ee3c4SAlexander Duyck ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 1049859ee3c4SAlexander Duyck nlh->nlmsg_flags); 1050859ee3c4SAlexander Duyck goto out; 10512f90b865SAlexander Duyck case DCB_CMD_SSTATE: 10522f90b865SAlexander Duyck ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq, 10532f90b865SAlexander Duyck nlh->nlmsg_flags); 10542f90b865SAlexander Duyck goto out; 10552f90b865SAlexander Duyck case DCB_CMD_PFC_SCFG: 10562f90b865SAlexander Duyck ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq, 10572f90b865SAlexander Duyck nlh->nlmsg_flags); 10582f90b865SAlexander Duyck goto out; 10592f90b865SAlexander Duyck 10602f90b865SAlexander Duyck case DCB_CMD_SET_ALL: 10612f90b865SAlexander Duyck ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq, 10622f90b865SAlexander Duyck nlh->nlmsg_flags); 10632f90b865SAlexander Duyck goto out; 10642f90b865SAlexander Duyck case DCB_CMD_PGTX_SCFG: 10652f90b865SAlexander Duyck ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 10662f90b865SAlexander Duyck nlh->nlmsg_flags); 10672f90b865SAlexander Duyck goto out; 10682f90b865SAlexander Duyck case DCB_CMD_PGRX_SCFG: 10692f90b865SAlexander Duyck ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 10702f90b865SAlexander Duyck nlh->nlmsg_flags); 10712f90b865SAlexander Duyck goto out; 107246132188SAlexander Duyck case DCB_CMD_GCAP: 107346132188SAlexander Duyck ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, 107446132188SAlexander Duyck nlh->nlmsg_flags); 107546132188SAlexander Duyck goto out; 107633dbabc4SAlexander Duyck case DCB_CMD_GNUMTCS: 107733dbabc4SAlexander Duyck ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq, 107833dbabc4SAlexander Duyck nlh->nlmsg_flags); 107933dbabc4SAlexander Duyck goto out; 108033dbabc4SAlexander Duyck case DCB_CMD_SNUMTCS: 108133dbabc4SAlexander Duyck ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq, 108233dbabc4SAlexander Duyck nlh->nlmsg_flags); 108333dbabc4SAlexander Duyck goto out; 10840eb3aa9bSAlexander Duyck case DCB_CMD_PFC_GSTATE: 10850eb3aa9bSAlexander Duyck ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq, 10860eb3aa9bSAlexander Duyck nlh->nlmsg_flags); 10870eb3aa9bSAlexander Duyck goto out; 10880eb3aa9bSAlexander Duyck case DCB_CMD_PFC_SSTATE: 10890eb3aa9bSAlexander Duyck ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq, 10900eb3aa9bSAlexander Duyck nlh->nlmsg_flags); 10910eb3aa9bSAlexander Duyck goto out; 1092859ee3c4SAlexander Duyck case DCB_CMD_BCN_SCFG: 1093859ee3c4SAlexander Duyck ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 1094859ee3c4SAlexander Duyck nlh->nlmsg_flags); 1095859ee3c4SAlexander Duyck goto out; 10962f90b865SAlexander Duyck default: 10972f90b865SAlexander Duyck goto errout; 10982f90b865SAlexander Duyck } 10992f90b865SAlexander Duyck errout: 11002f90b865SAlexander Duyck ret = -EINVAL; 11012f90b865SAlexander Duyck out: 11022f90b865SAlexander Duyck dev_put(netdev); 11032f90b865SAlexander Duyck return ret; 11042f90b865SAlexander Duyck } 11052f90b865SAlexander Duyck 11062f90b865SAlexander Duyck static int __init dcbnl_init(void) 11072f90b865SAlexander Duyck { 11082f90b865SAlexander Duyck rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); 11092f90b865SAlexander Duyck rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); 11102f90b865SAlexander Duyck 11112f90b865SAlexander Duyck return 0; 11122f90b865SAlexander Duyck } 11132f90b865SAlexander Duyck module_init(dcbnl_init); 11142f90b865SAlexander Duyck 11152f90b865SAlexander Duyck static void __exit dcbnl_exit(void) 11162f90b865SAlexander Duyck { 11172f90b865SAlexander Duyck rtnl_unregister(PF_UNSPEC, RTM_GETDCB); 11182f90b865SAlexander Duyck rtnl_unregister(PF_UNSPEC, RTM_SETDCB); 11192f90b865SAlexander Duyck } 11202f90b865SAlexander Duyck module_exit(dcbnl_exit); 11212f90b865SAlexander Duyck 11222f90b865SAlexander Duyck 1123