1 /* 2 * Copyright (c) 2008, Intel Corporation. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 15 * Place - Suite 330, Boston, MA 02111-1307 USA. 16 * 17 * Author: Lucy Liu <lucy.liu@intel.com> 18 */ 19 20 #include <linux/netdevice.h> 21 #include <linux/netlink.h> 22 #include <linux/slab.h> 23 #include <net/netlink.h> 24 #include <net/rtnetlink.h> 25 #include <linux/dcbnl.h> 26 #include <net/dcbevent.h> 27 #include <linux/rtnetlink.h> 28 #include <net/sock.h> 29 30 /** 31 * Data Center Bridging (DCB) is a collection of Ethernet enhancements 32 * intended to allow network traffic with differing requirements 33 * (highly reliable, no drops vs. best effort vs. low latency) to operate 34 * and co-exist on Ethernet. Current DCB features are: 35 * 36 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a 37 * framework for assigning bandwidth guarantees to traffic classes. 38 * 39 * Priority-based Flow Control (PFC) - provides a flow control mechanism which 40 * can work independently for each 802.1p priority. 41 * 42 * Congestion Notification - provides a mechanism for end-to-end congestion 43 * control for protocols which do not have built-in congestion management. 44 * 45 * More information about the emerging standards for these Ethernet features 46 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html 47 * 48 * This file implements an rtnetlink interface to allow configuration of DCB 49 * features for capable devices. 50 */ 51 52 MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>"); 53 MODULE_DESCRIPTION("Data Center Bridging netlink interface"); 54 MODULE_LICENSE("GPL"); 55 56 /**************** DCB attribute policies *************************************/ 57 58 /* DCB netlink attributes policy */ 59 static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { 60 [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, 61 [DCB_ATTR_STATE] = {.type = NLA_U8}, 62 [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, 63 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 64 [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 65 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 66 [DCB_ATTR_CAP] = {.type = NLA_NESTED}, 67 [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, 68 [DCB_ATTR_BCN] = {.type = NLA_NESTED}, 69 [DCB_ATTR_APP] = {.type = NLA_NESTED}, 70 [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, 71 [DCB_ATTR_DCBX] = {.type = NLA_U8}, 72 [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, 73 }; 74 75 /* DCB priority flow control to User Priority nested attributes */ 76 static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { 77 [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, 78 [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, 79 [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, 80 [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, 81 [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, 82 [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, 83 [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, 84 [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, 85 [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, 86 }; 87 88 /* DCB priority grouping nested attributes */ 89 static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { 90 [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, 91 [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, 92 [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, 93 [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, 94 [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, 95 [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, 96 [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, 97 [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, 98 [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, 99 [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, 100 [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, 101 [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, 102 [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, 103 [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, 104 [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, 105 [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, 106 [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, 107 [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, 108 }; 109 110 /* DCB traffic class nested attributes. */ 111 static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { 112 [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, 113 [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, 114 [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, 115 [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, 116 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 117 }; 118 119 /* DCB capabilities nested attributes. */ 120 static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { 121 [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, 122 [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, 123 [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, 124 [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, 125 [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, 126 [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, 127 [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, 128 [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, 129 [DCB_CAP_ATTR_DCBX] = {.type = NLA_U8}, 130 }; 131 132 /* DCB capabilities nested attributes. */ 133 static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { 134 [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, 135 [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, 136 [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, 137 }; 138 139 /* DCB BCN nested attributes. */ 140 static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { 141 [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, 142 [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, 143 [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, 144 [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, 145 [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, 146 [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, 147 [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, 148 [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, 149 [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, 150 [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, 151 [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, 152 [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, 153 [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, 154 [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, 155 [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, 156 [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, 157 [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, 158 [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, 159 [DCB_BCN_ATTR_W] = {.type = NLA_U32}, 160 [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, 161 [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, 162 [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, 163 [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, 164 [DCB_BCN_ATTR_C] = {.type = NLA_U32}, 165 [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, 166 }; 167 168 /* DCB APP nested attributes. */ 169 static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { 170 [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8}, 171 [DCB_APP_ATTR_ID] = {.type = NLA_U16}, 172 [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, 173 }; 174 175 /* IEEE 802.1Qaz nested attributes. */ 176 static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { 177 [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, 178 [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, 179 [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, 180 }; 181 182 static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { 183 [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, 184 }; 185 186 /* DCB number of traffic classes nested attributes. */ 187 static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { 188 [DCB_FEATCFG_ATTR_ALL] = {.type = NLA_FLAG}, 189 [DCB_FEATCFG_ATTR_PG] = {.type = NLA_U8}, 190 [DCB_FEATCFG_ATTR_PFC] = {.type = NLA_U8}, 191 [DCB_FEATCFG_ATTR_APP] = {.type = NLA_U8}, 192 }; 193 194 static LIST_HEAD(dcb_app_list); 195 static DEFINE_SPINLOCK(dcb_lock); 196 197 /* standard netlink reply call */ 198 static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, 199 u32 seq, u16 flags) 200 { 201 struct sk_buff *dcbnl_skb; 202 struct dcbmsg *dcb; 203 struct nlmsghdr *nlh; 204 int ret = -EINVAL; 205 206 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 207 if (!dcbnl_skb) 208 return ret; 209 210 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags); 211 212 dcb = NLMSG_DATA(nlh); 213 dcb->dcb_family = AF_UNSPEC; 214 dcb->cmd = cmd; 215 dcb->dcb_pad = 0; 216 217 ret = nla_put_u8(dcbnl_skb, attr, value); 218 if (ret) 219 goto err; 220 221 /* end the message, assign the nlmsg_len. */ 222 nlmsg_end(dcbnl_skb, nlh); 223 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 224 if (ret) 225 return -EINVAL; 226 227 return 0; 228 nlmsg_failure: 229 err: 230 kfree_skb(dcbnl_skb); 231 return ret; 232 } 233 234 static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb, 235 u32 pid, u32 seq, u16 flags) 236 { 237 int ret = -EINVAL; 238 239 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ 240 if (!netdev->dcbnl_ops->getstate) 241 return ret; 242 243 ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB, 244 DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags); 245 246 return ret; 247 } 248 249 static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, 250 u32 pid, u32 seq, u16 flags) 251 { 252 struct sk_buff *dcbnl_skb; 253 struct nlmsghdr *nlh; 254 struct dcbmsg *dcb; 255 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; 256 u8 value; 257 int ret = -EINVAL; 258 int i; 259 int getall = 0; 260 261 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg) 262 return ret; 263 264 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 265 tb[DCB_ATTR_PFC_CFG], 266 dcbnl_pfc_up_nest); 267 if (ret) 268 goto err_out; 269 270 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 271 if (!dcbnl_skb) 272 goto err_out; 273 274 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 275 276 dcb = NLMSG_DATA(nlh); 277 dcb->dcb_family = AF_UNSPEC; 278 dcb->cmd = DCB_CMD_PFC_GCFG; 279 280 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG); 281 if (!nest) 282 goto err; 283 284 if (data[DCB_PFC_UP_ATTR_ALL]) 285 getall = 1; 286 287 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 288 if (!getall && !data[i]) 289 continue; 290 291 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, 292 &value); 293 ret = nla_put_u8(dcbnl_skb, i, value); 294 295 if (ret) { 296 nla_nest_cancel(dcbnl_skb, nest); 297 goto err; 298 } 299 } 300 nla_nest_end(dcbnl_skb, nest); 301 302 nlmsg_end(dcbnl_skb, nlh); 303 304 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 305 if (ret) 306 goto err_out; 307 308 return 0; 309 nlmsg_failure: 310 err: 311 kfree_skb(dcbnl_skb); 312 err_out: 313 return -EINVAL; 314 } 315 316 static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, 317 u32 pid, u32 seq, u16 flags) 318 { 319 struct sk_buff *dcbnl_skb; 320 struct nlmsghdr *nlh; 321 struct dcbmsg *dcb; 322 u8 perm_addr[MAX_ADDR_LEN]; 323 int ret = -EINVAL; 324 325 if (!netdev->dcbnl_ops->getpermhwaddr) 326 return ret; 327 328 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 329 if (!dcbnl_skb) 330 goto err_out; 331 332 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 333 334 dcb = NLMSG_DATA(nlh); 335 dcb->dcb_family = AF_UNSPEC; 336 dcb->cmd = DCB_CMD_GPERM_HWADDR; 337 338 netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); 339 340 ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), 341 perm_addr); 342 343 nlmsg_end(dcbnl_skb, nlh); 344 345 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 346 if (ret) 347 goto err_out; 348 349 return 0; 350 351 nlmsg_failure: 352 kfree_skb(dcbnl_skb); 353 err_out: 354 return -EINVAL; 355 } 356 357 static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, 358 u32 pid, u32 seq, u16 flags) 359 { 360 struct sk_buff *dcbnl_skb; 361 struct nlmsghdr *nlh; 362 struct dcbmsg *dcb; 363 struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; 364 u8 value; 365 int ret = -EINVAL; 366 int i; 367 int getall = 0; 368 369 if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap) 370 return ret; 371 372 ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], 373 dcbnl_cap_nest); 374 if (ret) 375 goto err_out; 376 377 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 378 if (!dcbnl_skb) 379 goto err_out; 380 381 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 382 383 dcb = NLMSG_DATA(nlh); 384 dcb->dcb_family = AF_UNSPEC; 385 dcb->cmd = DCB_CMD_GCAP; 386 387 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP); 388 if (!nest) 389 goto err; 390 391 if (data[DCB_CAP_ATTR_ALL]) 392 getall = 1; 393 394 for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { 395 if (!getall && !data[i]) 396 continue; 397 398 if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { 399 ret = nla_put_u8(dcbnl_skb, i, value); 400 401 if (ret) { 402 nla_nest_cancel(dcbnl_skb, nest); 403 goto err; 404 } 405 } 406 } 407 nla_nest_end(dcbnl_skb, nest); 408 409 nlmsg_end(dcbnl_skb, nlh); 410 411 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 412 if (ret) 413 goto err_out; 414 415 return 0; 416 nlmsg_failure: 417 err: 418 kfree_skb(dcbnl_skb); 419 err_out: 420 return -EINVAL; 421 } 422 423 static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, 424 u32 pid, u32 seq, u16 flags) 425 { 426 struct sk_buff *dcbnl_skb; 427 struct nlmsghdr *nlh; 428 struct dcbmsg *dcb; 429 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; 430 u8 value; 431 int ret = -EINVAL; 432 int i; 433 int getall = 0; 434 435 if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) 436 return ret; 437 438 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 439 dcbnl_numtcs_nest); 440 if (ret) { 441 ret = -EINVAL; 442 goto err_out; 443 } 444 445 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 446 if (!dcbnl_skb) { 447 ret = -EINVAL; 448 goto err_out; 449 } 450 451 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 452 453 dcb = NLMSG_DATA(nlh); 454 dcb->dcb_family = AF_UNSPEC; 455 dcb->cmd = DCB_CMD_GNUMTCS; 456 457 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); 458 if (!nest) { 459 ret = -EINVAL; 460 goto err; 461 } 462 463 if (data[DCB_NUMTCS_ATTR_ALL]) 464 getall = 1; 465 466 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 467 if (!getall && !data[i]) 468 continue; 469 470 ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); 471 if (!ret) { 472 ret = nla_put_u8(dcbnl_skb, i, value); 473 474 if (ret) { 475 nla_nest_cancel(dcbnl_skb, nest); 476 ret = -EINVAL; 477 goto err; 478 } 479 } else { 480 goto err; 481 } 482 } 483 nla_nest_end(dcbnl_skb, nest); 484 485 nlmsg_end(dcbnl_skb, nlh); 486 487 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 488 if (ret) { 489 ret = -EINVAL; 490 goto err_out; 491 } 492 493 return 0; 494 nlmsg_failure: 495 err: 496 kfree_skb(dcbnl_skb); 497 err_out: 498 return ret; 499 } 500 501 static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, 502 u32 pid, u32 seq, u16 flags) 503 { 504 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; 505 int ret = -EINVAL; 506 u8 value; 507 int i; 508 509 if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs) 510 return ret; 511 512 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 513 dcbnl_numtcs_nest); 514 515 if (ret) { 516 ret = -EINVAL; 517 goto err; 518 } 519 520 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 521 if (data[i] == NULL) 522 continue; 523 524 value = nla_get_u8(data[i]); 525 526 ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); 527 528 if (ret) 529 goto operr; 530 } 531 532 operr: 533 ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS, 534 DCB_ATTR_NUMTCS, pid, seq, flags); 535 536 err: 537 return ret; 538 } 539 540 static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb, 541 u32 pid, u32 seq, u16 flags) 542 { 543 int ret = -EINVAL; 544 545 if (!netdev->dcbnl_ops->getpfcstate) 546 return ret; 547 548 ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB, 549 DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE, 550 pid, seq, flags); 551 552 return ret; 553 } 554 555 static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, 556 u32 pid, u32 seq, u16 flags) 557 { 558 int ret = -EINVAL; 559 u8 value; 560 561 if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate) 562 return ret; 563 564 value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); 565 566 netdev->dcbnl_ops->setpfcstate(netdev, value); 567 568 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE, 569 pid, seq, flags); 570 571 return ret; 572 } 573 574 static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, 575 u32 pid, u32 seq, u16 flags) 576 { 577 struct sk_buff *dcbnl_skb; 578 struct nlmsghdr *nlh; 579 struct dcbmsg *dcb; 580 struct nlattr *app_nest; 581 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 582 u16 id; 583 u8 up, idtype; 584 int ret = -EINVAL; 585 586 if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp) 587 goto out; 588 589 ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], 590 dcbnl_app_nest); 591 if (ret) 592 goto out; 593 594 ret = -EINVAL; 595 /* all must be non-null */ 596 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 597 (!app_tb[DCB_APP_ATTR_ID])) 598 goto out; 599 600 /* either by eth type or by socket number */ 601 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 602 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 603 (idtype != DCB_APP_IDTYPE_PORTNUM)) 604 goto out; 605 606 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 607 up = netdev->dcbnl_ops->getapp(netdev, idtype, id); 608 609 /* send this back */ 610 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 611 if (!dcbnl_skb) 612 goto out; 613 614 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 615 dcb = NLMSG_DATA(nlh); 616 dcb->dcb_family = AF_UNSPEC; 617 dcb->cmd = DCB_CMD_GAPP; 618 619 app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP); 620 ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype); 621 if (ret) 622 goto out_cancel; 623 624 ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id); 625 if (ret) 626 goto out_cancel; 627 628 ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up); 629 if (ret) 630 goto out_cancel; 631 632 nla_nest_end(dcbnl_skb, app_nest); 633 nlmsg_end(dcbnl_skb, nlh); 634 635 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 636 if (ret) 637 goto nlmsg_failure; 638 639 goto out; 640 641 out_cancel: 642 nla_nest_cancel(dcbnl_skb, app_nest); 643 nlmsg_failure: 644 kfree_skb(dcbnl_skb); 645 out: 646 return ret; 647 } 648 649 static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, 650 u32 pid, u32 seq, u16 flags) 651 { 652 int err, ret = -EINVAL; 653 u16 id; 654 u8 up, idtype; 655 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 656 657 if (!tb[DCB_ATTR_APP]) 658 goto out; 659 660 ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], 661 dcbnl_app_nest); 662 if (ret) 663 goto out; 664 665 ret = -EINVAL; 666 /* all must be non-null */ 667 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 668 (!app_tb[DCB_APP_ATTR_ID]) || 669 (!app_tb[DCB_APP_ATTR_PRIORITY])) 670 goto out; 671 672 /* either by eth type or by socket number */ 673 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 674 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 675 (idtype != DCB_APP_IDTYPE_PORTNUM)) 676 goto out; 677 678 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 679 up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); 680 681 if (netdev->dcbnl_ops->setapp) { 682 err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); 683 } else { 684 struct dcb_app app; 685 app.selector = idtype; 686 app.protocol = id; 687 app.priority = up; 688 err = dcb_setapp(netdev, &app); 689 } 690 691 ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, 692 pid, seq, flags); 693 out: 694 return ret; 695 } 696 697 static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, 698 u32 pid, u32 seq, u16 flags, int dir) 699 { 700 struct sk_buff *dcbnl_skb; 701 struct nlmsghdr *nlh; 702 struct dcbmsg *dcb; 703 struct nlattr *pg_nest, *param_nest, *data; 704 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 705 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 706 u8 prio, pgid, tc_pct, up_map; 707 int ret = -EINVAL; 708 int getall = 0; 709 int i; 710 711 if (!tb[DCB_ATTR_PG_CFG] || 712 !netdev->dcbnl_ops->getpgtccfgtx || 713 !netdev->dcbnl_ops->getpgtccfgrx || 714 !netdev->dcbnl_ops->getpgbwgcfgtx || 715 !netdev->dcbnl_ops->getpgbwgcfgrx) 716 return ret; 717 718 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 719 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 720 721 if (ret) 722 goto err_out; 723 724 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 725 if (!dcbnl_skb) 726 goto err_out; 727 728 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 729 730 dcb = NLMSG_DATA(nlh); 731 dcb->dcb_family = AF_UNSPEC; 732 dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG; 733 734 pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG); 735 if (!pg_nest) 736 goto err; 737 738 if (pg_tb[DCB_PG_ATTR_TC_ALL]) 739 getall = 1; 740 741 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 742 if (!getall && !pg_tb[i]) 743 continue; 744 745 if (pg_tb[DCB_PG_ATTR_TC_ALL]) 746 data = pg_tb[DCB_PG_ATTR_TC_ALL]; 747 else 748 data = pg_tb[i]; 749 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 750 data, dcbnl_tc_param_nest); 751 if (ret) 752 goto err_pg; 753 754 param_nest = nla_nest_start(dcbnl_skb, i); 755 if (!param_nest) 756 goto err_pg; 757 758 pgid = DCB_ATTR_VALUE_UNDEFINED; 759 prio = DCB_ATTR_VALUE_UNDEFINED; 760 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 761 up_map = DCB_ATTR_VALUE_UNDEFINED; 762 763 if (dir) { 764 /* Rx */ 765 netdev->dcbnl_ops->getpgtccfgrx(netdev, 766 i - DCB_PG_ATTR_TC_0, &prio, 767 &pgid, &tc_pct, &up_map); 768 } else { 769 /* Tx */ 770 netdev->dcbnl_ops->getpgtccfgtx(netdev, 771 i - DCB_PG_ATTR_TC_0, &prio, 772 &pgid, &tc_pct, &up_map); 773 } 774 775 if (param_tb[DCB_TC_ATTR_PARAM_PGID] || 776 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 777 ret = nla_put_u8(dcbnl_skb, 778 DCB_TC_ATTR_PARAM_PGID, pgid); 779 if (ret) 780 goto err_param; 781 } 782 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || 783 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 784 ret = nla_put_u8(dcbnl_skb, 785 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); 786 if (ret) 787 goto err_param; 788 } 789 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || 790 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 791 ret = nla_put_u8(dcbnl_skb, 792 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); 793 if (ret) 794 goto err_param; 795 } 796 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || 797 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 798 ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT, 799 tc_pct); 800 if (ret) 801 goto err_param; 802 } 803 nla_nest_end(dcbnl_skb, param_nest); 804 } 805 806 if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) 807 getall = 1; 808 else 809 getall = 0; 810 811 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 812 if (!getall && !pg_tb[i]) 813 continue; 814 815 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 816 817 if (dir) { 818 /* Rx */ 819 netdev->dcbnl_ops->getpgbwgcfgrx(netdev, 820 i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 821 } else { 822 /* Tx */ 823 netdev->dcbnl_ops->getpgbwgcfgtx(netdev, 824 i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 825 } 826 ret = nla_put_u8(dcbnl_skb, i, tc_pct); 827 828 if (ret) 829 goto err_pg; 830 } 831 832 nla_nest_end(dcbnl_skb, pg_nest); 833 834 nlmsg_end(dcbnl_skb, nlh); 835 836 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 837 if (ret) 838 goto err_out; 839 840 return 0; 841 842 err_param: 843 nla_nest_cancel(dcbnl_skb, param_nest); 844 err_pg: 845 nla_nest_cancel(dcbnl_skb, pg_nest); 846 nlmsg_failure: 847 err: 848 kfree_skb(dcbnl_skb); 849 err_out: 850 ret = -EINVAL; 851 return ret; 852 } 853 854 static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb, 855 u32 pid, u32 seq, u16 flags) 856 { 857 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0); 858 } 859 860 static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb, 861 u32 pid, u32 seq, u16 flags) 862 { 863 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1); 864 } 865 866 static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb, 867 u32 pid, u32 seq, u16 flags) 868 { 869 int ret = -EINVAL; 870 u8 value; 871 872 if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate) 873 return ret; 874 875 value = nla_get_u8(tb[DCB_ATTR_STATE]); 876 877 ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value), 878 RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, 879 pid, seq, flags); 880 881 return ret; 882 } 883 884 static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb, 885 u32 pid, u32 seq, u16 flags) 886 { 887 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; 888 int i; 889 int ret = -EINVAL; 890 u8 value; 891 892 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg) 893 return ret; 894 895 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 896 tb[DCB_ATTR_PFC_CFG], 897 dcbnl_pfc_up_nest); 898 if (ret) 899 goto err; 900 901 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 902 if (data[i] == NULL) 903 continue; 904 value = nla_get_u8(data[i]); 905 netdev->dcbnl_ops->setpfccfg(netdev, 906 data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); 907 } 908 909 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG, 910 pid, seq, flags); 911 err: 912 return ret; 913 } 914 915 static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb, 916 u32 pid, u32 seq, u16 flags) 917 { 918 int ret = -EINVAL; 919 920 if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall) 921 return ret; 922 923 ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB, 924 DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags); 925 926 return ret; 927 } 928 929 static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb, 930 u32 pid, u32 seq, u16 flags, int dir) 931 { 932 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 933 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 934 int ret = -EINVAL; 935 int i; 936 u8 pgid; 937 u8 up_map; 938 u8 prio; 939 u8 tc_pct; 940 941 if (!tb[DCB_ATTR_PG_CFG] || 942 !netdev->dcbnl_ops->setpgtccfgtx || 943 !netdev->dcbnl_ops->setpgtccfgrx || 944 !netdev->dcbnl_ops->setpgbwgcfgtx || 945 !netdev->dcbnl_ops->setpgbwgcfgrx) 946 return ret; 947 948 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 949 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 950 if (ret) 951 goto err; 952 953 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 954 if (!pg_tb[i]) 955 continue; 956 957 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 958 pg_tb[i], dcbnl_tc_param_nest); 959 if (ret) 960 goto err; 961 962 pgid = DCB_ATTR_VALUE_UNDEFINED; 963 prio = DCB_ATTR_VALUE_UNDEFINED; 964 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 965 up_map = DCB_ATTR_VALUE_UNDEFINED; 966 967 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]) 968 prio = 969 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]); 970 971 if (param_tb[DCB_TC_ATTR_PARAM_PGID]) 972 pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]); 973 974 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT]) 975 tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]); 976 977 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]) 978 up_map = 979 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]); 980 981 /* dir: Tx = 0, Rx = 1 */ 982 if (dir) { 983 /* Rx */ 984 netdev->dcbnl_ops->setpgtccfgrx(netdev, 985 i - DCB_PG_ATTR_TC_0, 986 prio, pgid, tc_pct, up_map); 987 } else { 988 /* Tx */ 989 netdev->dcbnl_ops->setpgtccfgtx(netdev, 990 i - DCB_PG_ATTR_TC_0, 991 prio, pgid, tc_pct, up_map); 992 } 993 } 994 995 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 996 if (!pg_tb[i]) 997 continue; 998 999 tc_pct = nla_get_u8(pg_tb[i]); 1000 1001 /* dir: Tx = 0, Rx = 1 */ 1002 if (dir) { 1003 /* Rx */ 1004 netdev->dcbnl_ops->setpgbwgcfgrx(netdev, 1005 i - DCB_PG_ATTR_BW_ID_0, tc_pct); 1006 } else { 1007 /* Tx */ 1008 netdev->dcbnl_ops->setpgbwgcfgtx(netdev, 1009 i - DCB_PG_ATTR_BW_ID_0, tc_pct); 1010 } 1011 } 1012 1013 ret = dcbnl_reply(0, RTM_SETDCB, 1014 (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG), 1015 DCB_ATTR_PG_CFG, pid, seq, flags); 1016 1017 err: 1018 return ret; 1019 } 1020 1021 static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb, 1022 u32 pid, u32 seq, u16 flags) 1023 { 1024 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0); 1025 } 1026 1027 static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb, 1028 u32 pid, u32 seq, u16 flags) 1029 { 1030 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1); 1031 } 1032 1033 static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, 1034 u32 pid, u32 seq, u16 flags) 1035 { 1036 struct sk_buff *dcbnl_skb; 1037 struct nlmsghdr *nlh; 1038 struct dcbmsg *dcb; 1039 struct nlattr *bcn_nest; 1040 struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; 1041 u8 value_byte; 1042 u32 value_integer; 1043 int ret = -EINVAL; 1044 bool getall = false; 1045 int i; 1046 1047 if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp || 1048 !netdev->dcbnl_ops->getbcncfg) 1049 return ret; 1050 1051 ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, 1052 tb[DCB_ATTR_BCN], dcbnl_bcn_nest); 1053 1054 if (ret) 1055 goto err_out; 1056 1057 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1058 if (!dcbnl_skb) 1059 goto err_out; 1060 1061 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 1062 1063 dcb = NLMSG_DATA(nlh); 1064 dcb->dcb_family = AF_UNSPEC; 1065 dcb->cmd = DCB_CMD_BCN_GCFG; 1066 1067 bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN); 1068 if (!bcn_nest) 1069 goto err; 1070 1071 if (bcn_tb[DCB_BCN_ATTR_ALL]) 1072 getall = true; 1073 1074 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 1075 if (!getall && !bcn_tb[i]) 1076 continue; 1077 1078 netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, 1079 &value_byte); 1080 ret = nla_put_u8(dcbnl_skb, i, value_byte); 1081 if (ret) 1082 goto err_bcn; 1083 } 1084 1085 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 1086 if (!getall && !bcn_tb[i]) 1087 continue; 1088 1089 netdev->dcbnl_ops->getbcncfg(netdev, i, 1090 &value_integer); 1091 ret = nla_put_u32(dcbnl_skb, i, value_integer); 1092 if (ret) 1093 goto err_bcn; 1094 } 1095 1096 nla_nest_end(dcbnl_skb, bcn_nest); 1097 1098 nlmsg_end(dcbnl_skb, nlh); 1099 1100 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 1101 if (ret) 1102 goto err_out; 1103 1104 return 0; 1105 1106 err_bcn: 1107 nla_nest_cancel(dcbnl_skb, bcn_nest); 1108 nlmsg_failure: 1109 err: 1110 kfree_skb(dcbnl_skb); 1111 err_out: 1112 ret = -EINVAL; 1113 return ret; 1114 } 1115 1116 static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, 1117 u32 pid, u32 seq, u16 flags) 1118 { 1119 struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; 1120 int i; 1121 int ret = -EINVAL; 1122 u8 value_byte; 1123 u32 value_int; 1124 1125 if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg || 1126 !netdev->dcbnl_ops->setbcnrp) 1127 return ret; 1128 1129 ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, 1130 tb[DCB_ATTR_BCN], 1131 dcbnl_pfc_up_nest); 1132 if (ret) 1133 goto err; 1134 1135 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 1136 if (data[i] == NULL) 1137 continue; 1138 value_byte = nla_get_u8(data[i]); 1139 netdev->dcbnl_ops->setbcnrp(netdev, 1140 data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); 1141 } 1142 1143 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 1144 if (data[i] == NULL) 1145 continue; 1146 value_int = nla_get_u32(data[i]); 1147 netdev->dcbnl_ops->setbcncfg(netdev, 1148 i, value_int); 1149 } 1150 1151 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN, 1152 pid, seq, flags); 1153 err: 1154 return ret; 1155 } 1156 1157 /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not 1158 * be completed the entire msg is aborted and error value is returned. 1159 * No attempt is made to reconcile the case where only part of the 1160 * cmd can be completed. 1161 */ 1162 static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, 1163 u32 pid, u32 seq, u16 flags) 1164 { 1165 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1166 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1167 int err = -EOPNOTSUPP; 1168 1169 if (!ops) 1170 goto err; 1171 1172 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1173 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1174 if (err) 1175 goto err; 1176 1177 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { 1178 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); 1179 err = ops->ieee_setets(netdev, ets); 1180 if (err) 1181 goto err; 1182 } 1183 1184 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) { 1185 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); 1186 err = ops->ieee_setpfc(netdev, pfc); 1187 if (err) 1188 goto err; 1189 } 1190 1191 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1192 struct nlattr *attr; 1193 int rem; 1194 1195 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1196 struct dcb_app *app_data; 1197 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1198 continue; 1199 app_data = nla_data(attr); 1200 if (ops->ieee_setapp) 1201 err = ops->ieee_setapp(netdev, app_data); 1202 else 1203 err = dcb_setapp(netdev, app_data); 1204 if (err) 1205 goto err; 1206 } 1207 } 1208 1209 err: 1210 dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, 1211 pid, seq, flags); 1212 return err; 1213 } 1214 1215 1216 /* Handle IEEE 802.1Qaz GET commands. */ 1217 static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, 1218 u32 pid, u32 seq, u16 flags) 1219 { 1220 struct sk_buff *skb; 1221 struct nlmsghdr *nlh; 1222 struct dcbmsg *dcb; 1223 struct nlattr *ieee, *app; 1224 struct dcb_app_type *itr; 1225 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1226 int err; 1227 1228 if (!ops) 1229 return -EOPNOTSUPP; 1230 1231 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1232 if (!skb) 1233 return -ENOBUFS; 1234 1235 nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 1236 1237 dcb = NLMSG_DATA(nlh); 1238 dcb->dcb_family = AF_UNSPEC; 1239 dcb->cmd = DCB_CMD_IEEE_GET; 1240 1241 NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); 1242 1243 ieee = nla_nest_start(skb, DCB_ATTR_IEEE); 1244 if (!ieee) 1245 goto nla_put_failure; 1246 1247 if (ops->ieee_getets) { 1248 struct ieee_ets ets; 1249 err = ops->ieee_getets(netdev, &ets); 1250 if (!err) 1251 NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets); 1252 } 1253 1254 if (ops->ieee_getpfc) { 1255 struct ieee_pfc pfc; 1256 err = ops->ieee_getpfc(netdev, &pfc); 1257 if (!err) 1258 NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); 1259 } 1260 1261 app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); 1262 if (!app) 1263 goto nla_put_failure; 1264 1265 spin_lock(&dcb_lock); 1266 list_for_each_entry(itr, &dcb_app_list, list) { 1267 if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) { 1268 err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), 1269 &itr->app); 1270 if (err) { 1271 spin_unlock(&dcb_lock); 1272 goto nla_put_failure; 1273 } 1274 } 1275 } 1276 spin_unlock(&dcb_lock); 1277 nla_nest_end(skb, app); 1278 1279 nla_nest_end(skb, ieee); 1280 nlmsg_end(skb, nlh); 1281 1282 return rtnl_unicast(skb, &init_net, pid); 1283 nla_put_failure: 1284 nlmsg_cancel(skb, nlh); 1285 nlmsg_failure: 1286 kfree_skb(skb); 1287 return -1; 1288 } 1289 1290 /* DCBX configuration */ 1291 static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, 1292 u32 pid, u32 seq, u16 flags) 1293 { 1294 int ret; 1295 1296 if (!netdev->dcbnl_ops->getdcbx) 1297 return -EOPNOTSUPP; 1298 1299 ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB, 1300 DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags); 1301 1302 return ret; 1303 } 1304 1305 static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb, 1306 u32 pid, u32 seq, u16 flags) 1307 { 1308 int ret; 1309 u8 value; 1310 1311 if (!netdev->dcbnl_ops->setdcbx) 1312 return -EOPNOTSUPP; 1313 1314 if (!tb[DCB_ATTR_DCBX]) 1315 return -EINVAL; 1316 1317 value = nla_get_u8(tb[DCB_ATTR_DCBX]); 1318 1319 ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value), 1320 RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX, 1321 pid, seq, flags); 1322 1323 return ret; 1324 } 1325 1326 static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb, 1327 u32 pid, u32 seq, u16 flags) 1328 { 1329 struct sk_buff *dcbnl_skb; 1330 struct nlmsghdr *nlh; 1331 struct dcbmsg *dcb; 1332 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; 1333 u8 value; 1334 int ret, i; 1335 int getall = 0; 1336 1337 if (!netdev->dcbnl_ops->getfeatcfg) 1338 return -EOPNOTSUPP; 1339 1340 if (!tb[DCB_ATTR_FEATCFG]) 1341 return -EINVAL; 1342 1343 ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1344 dcbnl_featcfg_nest); 1345 if (ret) 1346 goto err_out; 1347 1348 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1349 if (!dcbnl_skb) { 1350 ret = -ENOBUFS; 1351 goto err_out; 1352 } 1353 1354 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 1355 1356 dcb = NLMSG_DATA(nlh); 1357 dcb->dcb_family = AF_UNSPEC; 1358 dcb->cmd = DCB_CMD_GFEATCFG; 1359 1360 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG); 1361 if (!nest) { 1362 ret = -EMSGSIZE; 1363 goto nla_put_failure; 1364 } 1365 1366 if (data[DCB_FEATCFG_ATTR_ALL]) 1367 getall = 1; 1368 1369 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1370 if (!getall && !data[i]) 1371 continue; 1372 1373 ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); 1374 if (!ret) 1375 ret = nla_put_u8(dcbnl_skb, i, value); 1376 1377 if (ret) { 1378 nla_nest_cancel(dcbnl_skb, nest); 1379 goto nla_put_failure; 1380 } 1381 } 1382 nla_nest_end(dcbnl_skb, nest); 1383 1384 nlmsg_end(dcbnl_skb, nlh); 1385 1386 return rtnl_unicast(dcbnl_skb, &init_net, pid); 1387 nla_put_failure: 1388 nlmsg_cancel(dcbnl_skb, nlh); 1389 nlmsg_failure: 1390 kfree_skb(dcbnl_skb); 1391 err_out: 1392 return ret; 1393 } 1394 1395 static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb, 1396 u32 pid, u32 seq, u16 flags) 1397 { 1398 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; 1399 int ret, i; 1400 u8 value; 1401 1402 if (!netdev->dcbnl_ops->setfeatcfg) 1403 return -ENOTSUPP; 1404 1405 if (!tb[DCB_ATTR_FEATCFG]) 1406 return -EINVAL; 1407 1408 ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1409 dcbnl_featcfg_nest); 1410 1411 if (ret) 1412 goto err; 1413 1414 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1415 if (data[i] == NULL) 1416 continue; 1417 1418 value = nla_get_u8(data[i]); 1419 1420 ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); 1421 1422 if (ret) 1423 goto err; 1424 } 1425 err: 1426 dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG, 1427 pid, seq, flags); 1428 1429 return ret; 1430 } 1431 1432 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 1433 { 1434 struct net *net = sock_net(skb->sk); 1435 struct net_device *netdev; 1436 struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh); 1437 struct nlattr *tb[DCB_ATTR_MAX + 1]; 1438 u32 pid = skb ? NETLINK_CB(skb).pid : 0; 1439 int ret = -EINVAL; 1440 1441 if (!net_eq(net, &init_net)) 1442 return -EINVAL; 1443 1444 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 1445 dcbnl_rtnl_policy); 1446 if (ret < 0) 1447 return ret; 1448 1449 if (!tb[DCB_ATTR_IFNAME]) 1450 return -EINVAL; 1451 1452 netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME])); 1453 if (!netdev) 1454 return -EINVAL; 1455 1456 if (!netdev->dcbnl_ops) 1457 goto errout; 1458 1459 switch (dcb->cmd) { 1460 case DCB_CMD_GSTATE: 1461 ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, 1462 nlh->nlmsg_flags); 1463 goto out; 1464 case DCB_CMD_PFC_GCFG: 1465 ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq, 1466 nlh->nlmsg_flags); 1467 goto out; 1468 case DCB_CMD_GPERM_HWADDR: 1469 ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq, 1470 nlh->nlmsg_flags); 1471 goto out; 1472 case DCB_CMD_PGTX_GCFG: 1473 ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 1474 nlh->nlmsg_flags); 1475 goto out; 1476 case DCB_CMD_PGRX_GCFG: 1477 ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 1478 nlh->nlmsg_flags); 1479 goto out; 1480 case DCB_CMD_BCN_GCFG: 1481 ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 1482 nlh->nlmsg_flags); 1483 goto out; 1484 case DCB_CMD_SSTATE: 1485 ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq, 1486 nlh->nlmsg_flags); 1487 goto out; 1488 case DCB_CMD_PFC_SCFG: 1489 ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq, 1490 nlh->nlmsg_flags); 1491 goto out; 1492 1493 case DCB_CMD_SET_ALL: 1494 ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq, 1495 nlh->nlmsg_flags); 1496 goto out; 1497 case DCB_CMD_PGTX_SCFG: 1498 ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 1499 nlh->nlmsg_flags); 1500 goto out; 1501 case DCB_CMD_PGRX_SCFG: 1502 ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 1503 nlh->nlmsg_flags); 1504 goto out; 1505 case DCB_CMD_GCAP: 1506 ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, 1507 nlh->nlmsg_flags); 1508 goto out; 1509 case DCB_CMD_GNUMTCS: 1510 ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq, 1511 nlh->nlmsg_flags); 1512 goto out; 1513 case DCB_CMD_SNUMTCS: 1514 ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq, 1515 nlh->nlmsg_flags); 1516 goto out; 1517 case DCB_CMD_PFC_GSTATE: 1518 ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq, 1519 nlh->nlmsg_flags); 1520 goto out; 1521 case DCB_CMD_PFC_SSTATE: 1522 ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq, 1523 nlh->nlmsg_flags); 1524 goto out; 1525 case DCB_CMD_BCN_SCFG: 1526 ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 1527 nlh->nlmsg_flags); 1528 goto out; 1529 case DCB_CMD_GAPP: 1530 ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq, 1531 nlh->nlmsg_flags); 1532 goto out; 1533 case DCB_CMD_SAPP: 1534 ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, 1535 nlh->nlmsg_flags); 1536 goto out; 1537 case DCB_CMD_IEEE_SET: 1538 ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, 1539 nlh->nlmsg_flags); 1540 goto out; 1541 case DCB_CMD_IEEE_GET: 1542 ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, 1543 nlh->nlmsg_flags); 1544 goto out; 1545 case DCB_CMD_GDCBX: 1546 ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, 1547 nlh->nlmsg_flags); 1548 goto out; 1549 case DCB_CMD_SDCBX: 1550 ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq, 1551 nlh->nlmsg_flags); 1552 goto out; 1553 case DCB_CMD_GFEATCFG: 1554 ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, 1555 nlh->nlmsg_flags); 1556 goto out; 1557 case DCB_CMD_SFEATCFG: 1558 ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, 1559 nlh->nlmsg_flags); 1560 goto out; 1561 default: 1562 goto errout; 1563 } 1564 errout: 1565 ret = -EINVAL; 1566 out: 1567 dev_put(netdev); 1568 return ret; 1569 } 1570 1571 /** 1572 * dcb_getapp - retrieve the DCBX application user priority 1573 * 1574 * On success returns a non-zero 802.1p user priority bitmap 1575 * otherwise returns 0 as the invalid user priority bitmap to 1576 * indicate an error. 1577 */ 1578 u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) 1579 { 1580 struct dcb_app_type *itr; 1581 u8 prio = 0; 1582 1583 spin_lock(&dcb_lock); 1584 list_for_each_entry(itr, &dcb_app_list, list) { 1585 if (itr->app.selector == app->selector && 1586 itr->app.protocol == app->protocol && 1587 (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { 1588 prio = itr->app.priority; 1589 break; 1590 } 1591 } 1592 spin_unlock(&dcb_lock); 1593 1594 return prio; 1595 } 1596 EXPORT_SYMBOL(dcb_getapp); 1597 1598 /** 1599 * ixgbe_dcbnl_setapp - add dcb application data to app list 1600 * 1601 * Priority 0 is the default priority this removes applications 1602 * from the app list if the priority is set to zero. 1603 */ 1604 u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) 1605 { 1606 struct dcb_app_type *itr; 1607 1608 spin_lock(&dcb_lock); 1609 /* Search for existing match and replace */ 1610 list_for_each_entry(itr, &dcb_app_list, list) { 1611 if (itr->app.selector == new->selector && 1612 itr->app.protocol == new->protocol && 1613 (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { 1614 if (new->priority) 1615 itr->app.priority = new->priority; 1616 else { 1617 list_del(&itr->list); 1618 kfree(itr); 1619 } 1620 goto out; 1621 } 1622 } 1623 /* App type does not exist add new application type */ 1624 if (new->priority) { 1625 struct dcb_app_type *entry; 1626 entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); 1627 if (!entry) { 1628 spin_unlock(&dcb_lock); 1629 return -ENOMEM; 1630 } 1631 1632 memcpy(&entry->app, new, sizeof(*new)); 1633 strncpy(entry->name, dev->name, IFNAMSIZ); 1634 list_add(&entry->list, &dcb_app_list); 1635 } 1636 out: 1637 spin_unlock(&dcb_lock); 1638 call_dcbevent_notifiers(DCB_APP_EVENT, new); 1639 return 0; 1640 } 1641 EXPORT_SYMBOL(dcb_setapp); 1642 1643 static void dcb_flushapp(void) 1644 { 1645 struct dcb_app_type *app; 1646 struct dcb_app_type *tmp; 1647 1648 spin_lock(&dcb_lock); 1649 list_for_each_entry_safe(app, tmp, &dcb_app_list, list) { 1650 list_del(&app->list); 1651 kfree(app); 1652 } 1653 spin_unlock(&dcb_lock); 1654 } 1655 1656 static int __init dcbnl_init(void) 1657 { 1658 INIT_LIST_HEAD(&dcb_app_list); 1659 1660 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); 1661 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); 1662 1663 return 0; 1664 } 1665 module_init(dcbnl_init); 1666 1667 static void __exit dcbnl_exit(void) 1668 { 1669 rtnl_unregister(PF_UNSPEC, RTM_GETDCB); 1670 rtnl_unregister(PF_UNSPEC, RTM_SETDCB); 1671 dcb_flushapp(); 1672 } 1673 module_exit(dcbnl_exit); 1674