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 <net/netlink.h> 23 #include <net/rtnetlink.h> 24 #include <linux/dcbnl.h> 25 #include <linux/rtnetlink.h> 26 #include <net/sock.h> 27 28 /** 29 * Data Center Bridging (DCB) is a collection of Ethernet enhancements 30 * intended to allow network traffic with differing requirements 31 * (highly reliable, no drops vs. best effort vs. low latency) to operate 32 * and co-exist on Ethernet. Current DCB features are: 33 * 34 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a 35 * framework for assigning bandwidth guarantees to traffic classes. 36 * 37 * Priority-based Flow Control (PFC) - provides a flow control mechanism which 38 * can work independently for each 802.1p priority. 39 * 40 * Congestion Notification - provides a mechanism for end-to-end congestion 41 * control for protocols which do not have built-in congestion management. 42 * 43 * More information about the emerging standards for these Ethernet features 44 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html 45 * 46 * This file implements an rtnetlink interface to allow configuration of DCB 47 * features for capable devices. 48 */ 49 50 MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>"); 51 MODULE_DESCRIPTION("Data Center Bridging netlink interface"); 52 MODULE_LICENSE("GPL"); 53 54 /**************** DCB attribute policies *************************************/ 55 56 /* DCB netlink attributes policy */ 57 static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { 58 [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, 59 [DCB_ATTR_STATE] = {.type = NLA_U8}, 60 [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, 61 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 62 [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 63 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 64 [DCB_ATTR_CAP] = {.type = NLA_NESTED}, 65 [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, 66 [DCB_ATTR_BCN] = {.type = NLA_NESTED}, 67 }; 68 69 /* DCB priority flow control to User Priority nested attributes */ 70 static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { 71 [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, 72 [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, 73 [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, 74 [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, 75 [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, 76 [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, 77 [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, 78 [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, 79 [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, 80 }; 81 82 /* DCB priority grouping nested attributes */ 83 static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { 84 [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, 85 [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, 86 [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, 87 [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, 88 [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, 89 [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, 90 [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, 91 [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, 92 [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, 93 [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, 94 [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, 95 [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, 96 [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, 97 [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, 98 [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, 99 [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, 100 [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, 101 [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, 102 }; 103 104 /* DCB traffic class nested attributes. */ 105 static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { 106 [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, 107 [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, 108 [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, 109 [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, 110 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 111 }; 112 113 /* DCB capabilities nested attributes. */ 114 static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { 115 [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, 116 [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, 117 [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, 118 [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, 119 [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, 120 [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, 121 [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, 122 [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, 123 }; 124 125 /* DCB capabilities nested attributes. */ 126 static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { 127 [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, 128 [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, 129 [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, 130 }; 131 132 /* DCB BCN nested attributes. */ 133 static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { 134 [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, 135 [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, 136 [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, 137 [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, 138 [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, 139 [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, 140 [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, 141 [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, 142 [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, 143 [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, 144 [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, 145 [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, 146 [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, 147 [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, 148 [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, 149 [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, 150 [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, 151 [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, 152 [DCB_BCN_ATTR_W] = {.type = NLA_U32}, 153 [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, 154 [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, 155 [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, 156 [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, 157 [DCB_BCN_ATTR_C] = {.type = NLA_U32}, 158 [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, 159 }; 160 161 /* standard netlink reply call */ 162 static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, 163 u32 seq, u16 flags) 164 { 165 struct sk_buff *dcbnl_skb; 166 struct dcbmsg *dcb; 167 struct nlmsghdr *nlh; 168 int ret = -EINVAL; 169 170 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 171 if (!dcbnl_skb) 172 return ret; 173 174 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags); 175 176 dcb = NLMSG_DATA(nlh); 177 dcb->dcb_family = AF_UNSPEC; 178 dcb->cmd = cmd; 179 dcb->dcb_pad = 0; 180 181 ret = nla_put_u8(dcbnl_skb, attr, value); 182 if (ret) 183 goto err; 184 185 /* end the message, assign the nlmsg_len. */ 186 nlmsg_end(dcbnl_skb, nlh); 187 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 188 if (ret) 189 goto err; 190 191 return 0; 192 nlmsg_failure: 193 err: 194 kfree_skb(dcbnl_skb); 195 return ret; 196 } 197 198 static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb, 199 u32 pid, u32 seq, u16 flags) 200 { 201 int ret = -EINVAL; 202 203 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ 204 if (!netdev->dcbnl_ops->getstate) 205 return ret; 206 207 ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB, 208 DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags); 209 210 return ret; 211 } 212 213 static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, 214 u32 pid, u32 seq, u16 flags) 215 { 216 struct sk_buff *dcbnl_skb; 217 struct nlmsghdr *nlh; 218 struct dcbmsg *dcb; 219 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; 220 u8 value; 221 int ret = -EINVAL; 222 int i; 223 int getall = 0; 224 225 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg) 226 return ret; 227 228 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 229 tb[DCB_ATTR_PFC_CFG], 230 dcbnl_pfc_up_nest); 231 if (ret) 232 goto err_out; 233 234 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 235 if (!dcbnl_skb) 236 goto err_out; 237 238 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 239 240 dcb = NLMSG_DATA(nlh); 241 dcb->dcb_family = AF_UNSPEC; 242 dcb->cmd = DCB_CMD_PFC_GCFG; 243 244 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG); 245 if (!nest) 246 goto err; 247 248 if (data[DCB_PFC_UP_ATTR_ALL]) 249 getall = 1; 250 251 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 252 if (!getall && !data[i]) 253 continue; 254 255 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, 256 &value); 257 ret = nla_put_u8(dcbnl_skb, i, value); 258 259 if (ret) { 260 nla_nest_cancel(dcbnl_skb, nest); 261 goto err; 262 } 263 } 264 nla_nest_end(dcbnl_skb, nest); 265 266 nlmsg_end(dcbnl_skb, nlh); 267 268 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 269 if (ret) 270 goto err; 271 272 return 0; 273 nlmsg_failure: 274 err: 275 kfree_skb(dcbnl_skb); 276 err_out: 277 return -EINVAL; 278 } 279 280 static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, 281 u32 pid, u32 seq, u16 flags) 282 { 283 struct sk_buff *dcbnl_skb; 284 struct nlmsghdr *nlh; 285 struct dcbmsg *dcb; 286 u8 perm_addr[MAX_ADDR_LEN]; 287 int ret = -EINVAL; 288 289 if (!netdev->dcbnl_ops->getpermhwaddr) 290 return ret; 291 292 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 293 if (!dcbnl_skb) 294 goto err_out; 295 296 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 297 298 dcb = NLMSG_DATA(nlh); 299 dcb->dcb_family = AF_UNSPEC; 300 dcb->cmd = DCB_CMD_GPERM_HWADDR; 301 302 netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); 303 304 ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), 305 perm_addr); 306 307 nlmsg_end(dcbnl_skb, nlh); 308 309 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 310 if (ret) 311 goto err; 312 313 return 0; 314 315 nlmsg_failure: 316 err: 317 kfree_skb(dcbnl_skb); 318 err_out: 319 return -EINVAL; 320 } 321 322 static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, 323 u32 pid, u32 seq, u16 flags) 324 { 325 struct sk_buff *dcbnl_skb; 326 struct nlmsghdr *nlh; 327 struct dcbmsg *dcb; 328 struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; 329 u8 value; 330 int ret = -EINVAL; 331 int i; 332 int getall = 0; 333 334 if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap) 335 return ret; 336 337 ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], 338 dcbnl_cap_nest); 339 if (ret) 340 goto err_out; 341 342 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 343 if (!dcbnl_skb) 344 goto err_out; 345 346 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 347 348 dcb = NLMSG_DATA(nlh); 349 dcb->dcb_family = AF_UNSPEC; 350 dcb->cmd = DCB_CMD_GCAP; 351 352 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP); 353 if (!nest) 354 goto err; 355 356 if (data[DCB_CAP_ATTR_ALL]) 357 getall = 1; 358 359 for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { 360 if (!getall && !data[i]) 361 continue; 362 363 if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { 364 ret = nla_put_u8(dcbnl_skb, i, value); 365 366 if (ret) { 367 nla_nest_cancel(dcbnl_skb, nest); 368 goto err; 369 } 370 } 371 } 372 nla_nest_end(dcbnl_skb, nest); 373 374 nlmsg_end(dcbnl_skb, nlh); 375 376 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 377 if (ret) 378 goto err; 379 380 return 0; 381 nlmsg_failure: 382 err: 383 kfree_skb(dcbnl_skb); 384 err_out: 385 return -EINVAL; 386 } 387 388 static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, 389 u32 pid, u32 seq, u16 flags) 390 { 391 struct sk_buff *dcbnl_skb; 392 struct nlmsghdr *nlh; 393 struct dcbmsg *dcb; 394 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; 395 u8 value; 396 int ret = -EINVAL; 397 int i; 398 int getall = 0; 399 400 if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) 401 return ret; 402 403 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 404 dcbnl_numtcs_nest); 405 if (ret) { 406 ret = -EINVAL; 407 goto err_out; 408 } 409 410 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 411 if (!dcbnl_skb) { 412 ret = -EINVAL; 413 goto err_out; 414 } 415 416 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 417 418 dcb = NLMSG_DATA(nlh); 419 dcb->dcb_family = AF_UNSPEC; 420 dcb->cmd = DCB_CMD_GNUMTCS; 421 422 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); 423 if (!nest) { 424 ret = -EINVAL; 425 goto err; 426 } 427 428 if (data[DCB_NUMTCS_ATTR_ALL]) 429 getall = 1; 430 431 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 432 if (!getall && !data[i]) 433 continue; 434 435 ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); 436 if (!ret) { 437 ret = nla_put_u8(dcbnl_skb, i, value); 438 439 if (ret) { 440 nla_nest_cancel(dcbnl_skb, nest); 441 ret = -EINVAL; 442 goto err; 443 } 444 } else { 445 goto err; 446 } 447 } 448 nla_nest_end(dcbnl_skb, nest); 449 450 nlmsg_end(dcbnl_skb, nlh); 451 452 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 453 if (ret) { 454 ret = -EINVAL; 455 goto err; 456 } 457 458 return 0; 459 nlmsg_failure: 460 err: 461 kfree_skb(dcbnl_skb); 462 err_out: 463 return ret; 464 } 465 466 static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, 467 u32 pid, u32 seq, u16 flags) 468 { 469 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; 470 int ret = -EINVAL; 471 u8 value; 472 int i; 473 474 if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs) 475 return ret; 476 477 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 478 dcbnl_numtcs_nest); 479 480 if (ret) { 481 ret = -EINVAL; 482 goto err; 483 } 484 485 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 486 if (data[i] == NULL) 487 continue; 488 489 value = nla_get_u8(data[i]); 490 491 ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); 492 493 if (ret) 494 goto operr; 495 } 496 497 operr: 498 ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS, 499 DCB_ATTR_NUMTCS, pid, seq, flags); 500 501 err: 502 return ret; 503 } 504 505 static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb, 506 u32 pid, u32 seq, u16 flags) 507 { 508 int ret = -EINVAL; 509 510 if (!netdev->dcbnl_ops->getpfcstate) 511 return ret; 512 513 ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB, 514 DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE, 515 pid, seq, flags); 516 517 return ret; 518 } 519 520 static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, 521 u32 pid, u32 seq, u16 flags) 522 { 523 int ret = -EINVAL; 524 u8 value; 525 526 if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate) 527 return ret; 528 529 value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); 530 531 netdev->dcbnl_ops->setpfcstate(netdev, value); 532 533 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE, 534 pid, seq, flags); 535 536 return ret; 537 } 538 539 static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, 540 u32 pid, u32 seq, u16 flags, int dir) 541 { 542 struct sk_buff *dcbnl_skb; 543 struct nlmsghdr *nlh; 544 struct dcbmsg *dcb; 545 struct nlattr *pg_nest, *param_nest, *data; 546 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 547 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 548 u8 prio, pgid, tc_pct, up_map; 549 int ret = -EINVAL; 550 int getall = 0; 551 int i; 552 553 if (!tb[DCB_ATTR_PG_CFG] || 554 !netdev->dcbnl_ops->getpgtccfgtx || 555 !netdev->dcbnl_ops->getpgtccfgrx || 556 !netdev->dcbnl_ops->getpgbwgcfgtx || 557 !netdev->dcbnl_ops->getpgbwgcfgrx) 558 return ret; 559 560 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 561 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 562 563 if (ret) 564 goto err_out; 565 566 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 567 if (!dcbnl_skb) 568 goto err_out; 569 570 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 571 572 dcb = NLMSG_DATA(nlh); 573 dcb->dcb_family = AF_UNSPEC; 574 dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG; 575 576 pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG); 577 if (!pg_nest) 578 goto err; 579 580 if (pg_tb[DCB_PG_ATTR_TC_ALL]) 581 getall = 1; 582 583 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 584 if (!getall && !pg_tb[i]) 585 continue; 586 587 if (pg_tb[DCB_PG_ATTR_TC_ALL]) 588 data = pg_tb[DCB_PG_ATTR_TC_ALL]; 589 else 590 data = pg_tb[i]; 591 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 592 data, dcbnl_tc_param_nest); 593 if (ret) 594 goto err_pg; 595 596 param_nest = nla_nest_start(dcbnl_skb, i); 597 if (!param_nest) 598 goto err_pg; 599 600 pgid = DCB_ATTR_VALUE_UNDEFINED; 601 prio = DCB_ATTR_VALUE_UNDEFINED; 602 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 603 up_map = DCB_ATTR_VALUE_UNDEFINED; 604 605 if (dir) { 606 /* Rx */ 607 netdev->dcbnl_ops->getpgtccfgrx(netdev, 608 i - DCB_PG_ATTR_TC_0, &prio, 609 &pgid, &tc_pct, &up_map); 610 } else { 611 /* Tx */ 612 netdev->dcbnl_ops->getpgtccfgtx(netdev, 613 i - DCB_PG_ATTR_TC_0, &prio, 614 &pgid, &tc_pct, &up_map); 615 } 616 617 if (param_tb[DCB_TC_ATTR_PARAM_PGID] || 618 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 619 ret = nla_put_u8(dcbnl_skb, 620 DCB_TC_ATTR_PARAM_PGID, pgid); 621 if (ret) 622 goto err_param; 623 } 624 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || 625 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 626 ret = nla_put_u8(dcbnl_skb, 627 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); 628 if (ret) 629 goto err_param; 630 } 631 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || 632 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 633 ret = nla_put_u8(dcbnl_skb, 634 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); 635 if (ret) 636 goto err_param; 637 } 638 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || 639 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 640 ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT, 641 tc_pct); 642 if (ret) 643 goto err_param; 644 } 645 nla_nest_end(dcbnl_skb, param_nest); 646 } 647 648 if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) 649 getall = 1; 650 else 651 getall = 0; 652 653 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 654 if (!getall && !pg_tb[i]) 655 continue; 656 657 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 658 659 if (dir) { 660 /* Rx */ 661 netdev->dcbnl_ops->getpgbwgcfgrx(netdev, 662 i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 663 } else { 664 /* Tx */ 665 netdev->dcbnl_ops->getpgbwgcfgtx(netdev, 666 i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 667 } 668 ret = nla_put_u8(dcbnl_skb, i, tc_pct); 669 670 if (ret) 671 goto err_pg; 672 } 673 674 nla_nest_end(dcbnl_skb, pg_nest); 675 676 nlmsg_end(dcbnl_skb, nlh); 677 678 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 679 if (ret) 680 goto err; 681 682 return 0; 683 684 err_param: 685 nla_nest_cancel(dcbnl_skb, param_nest); 686 err_pg: 687 nla_nest_cancel(dcbnl_skb, pg_nest); 688 nlmsg_failure: 689 err: 690 kfree_skb(dcbnl_skb); 691 err_out: 692 ret = -EINVAL; 693 return ret; 694 } 695 696 static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb, 697 u32 pid, u32 seq, u16 flags) 698 { 699 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0); 700 } 701 702 static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb, 703 u32 pid, u32 seq, u16 flags) 704 { 705 return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1); 706 } 707 708 static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb, 709 u32 pid, u32 seq, u16 flags) 710 { 711 int ret = -EINVAL; 712 u8 value; 713 714 if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate) 715 return ret; 716 717 value = nla_get_u8(tb[DCB_ATTR_STATE]); 718 719 ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value), 720 RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, 721 pid, seq, flags); 722 723 return ret; 724 } 725 726 static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb, 727 u32 pid, u32 seq, u16 flags) 728 { 729 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; 730 int i; 731 int ret = -EINVAL; 732 u8 value; 733 734 if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg) 735 return ret; 736 737 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 738 tb[DCB_ATTR_PFC_CFG], 739 dcbnl_pfc_up_nest); 740 if (ret) 741 goto err; 742 743 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 744 if (data[i] == NULL) 745 continue; 746 value = nla_get_u8(data[i]); 747 netdev->dcbnl_ops->setpfccfg(netdev, 748 data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); 749 } 750 751 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG, 752 pid, seq, flags); 753 err: 754 return ret; 755 } 756 757 static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb, 758 u32 pid, u32 seq, u16 flags) 759 { 760 int ret = -EINVAL; 761 762 if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall) 763 return ret; 764 765 ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB, 766 DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags); 767 768 return ret; 769 } 770 771 static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb, 772 u32 pid, u32 seq, u16 flags, int dir) 773 { 774 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 775 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 776 int ret = -EINVAL; 777 int i; 778 u8 pgid; 779 u8 up_map; 780 u8 prio; 781 u8 tc_pct; 782 783 if (!tb[DCB_ATTR_PG_CFG] || 784 !netdev->dcbnl_ops->setpgtccfgtx || 785 !netdev->dcbnl_ops->setpgtccfgrx || 786 !netdev->dcbnl_ops->setpgbwgcfgtx || 787 !netdev->dcbnl_ops->setpgbwgcfgrx) 788 return ret; 789 790 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 791 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 792 if (ret) 793 goto err; 794 795 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 796 if (!pg_tb[i]) 797 continue; 798 799 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 800 pg_tb[i], dcbnl_tc_param_nest); 801 if (ret) 802 goto err; 803 804 pgid = DCB_ATTR_VALUE_UNDEFINED; 805 prio = DCB_ATTR_VALUE_UNDEFINED; 806 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 807 up_map = DCB_ATTR_VALUE_UNDEFINED; 808 809 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]) 810 prio = 811 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]); 812 813 if (param_tb[DCB_TC_ATTR_PARAM_PGID]) 814 pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]); 815 816 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT]) 817 tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]); 818 819 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]) 820 up_map = 821 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]); 822 823 /* dir: Tx = 0, Rx = 1 */ 824 if (dir) { 825 /* Rx */ 826 netdev->dcbnl_ops->setpgtccfgrx(netdev, 827 i - DCB_PG_ATTR_TC_0, 828 prio, pgid, tc_pct, up_map); 829 } else { 830 /* Tx */ 831 netdev->dcbnl_ops->setpgtccfgtx(netdev, 832 i - DCB_PG_ATTR_TC_0, 833 prio, pgid, tc_pct, up_map); 834 } 835 } 836 837 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 838 if (!pg_tb[i]) 839 continue; 840 841 tc_pct = nla_get_u8(pg_tb[i]); 842 843 /* dir: Tx = 0, Rx = 1 */ 844 if (dir) { 845 /* Rx */ 846 netdev->dcbnl_ops->setpgbwgcfgrx(netdev, 847 i - DCB_PG_ATTR_BW_ID_0, tc_pct); 848 } else { 849 /* Tx */ 850 netdev->dcbnl_ops->setpgbwgcfgtx(netdev, 851 i - DCB_PG_ATTR_BW_ID_0, tc_pct); 852 } 853 } 854 855 ret = dcbnl_reply(0, RTM_SETDCB, 856 (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG), 857 DCB_ATTR_PG_CFG, pid, seq, flags); 858 859 err: 860 return ret; 861 } 862 863 static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb, 864 u32 pid, u32 seq, u16 flags) 865 { 866 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0); 867 } 868 869 static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb, 870 u32 pid, u32 seq, u16 flags) 871 { 872 return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1); 873 } 874 875 static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, 876 u32 pid, u32 seq, u16 flags) 877 { 878 struct sk_buff *dcbnl_skb; 879 struct nlmsghdr *nlh; 880 struct dcbmsg *dcb; 881 struct nlattr *bcn_nest; 882 struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; 883 u8 value_byte; 884 u32 value_integer; 885 int ret = -EINVAL; 886 bool getall = false; 887 int i; 888 889 if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp || 890 !netdev->dcbnl_ops->getbcncfg) 891 return ret; 892 893 ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, 894 tb[DCB_ATTR_BCN], dcbnl_bcn_nest); 895 896 if (ret) 897 goto err_out; 898 899 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 900 if (!dcbnl_skb) 901 goto err_out; 902 903 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); 904 905 dcb = NLMSG_DATA(nlh); 906 dcb->dcb_family = AF_UNSPEC; 907 dcb->cmd = DCB_CMD_BCN_GCFG; 908 909 bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN); 910 if (!bcn_nest) 911 goto err; 912 913 if (bcn_tb[DCB_BCN_ATTR_ALL]) 914 getall = true; 915 916 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 917 if (!getall && !bcn_tb[i]) 918 continue; 919 920 netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, 921 &value_byte); 922 ret = nla_put_u8(dcbnl_skb, i, value_byte); 923 if (ret) 924 goto err_bcn; 925 } 926 927 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 928 if (!getall && !bcn_tb[i]) 929 continue; 930 931 netdev->dcbnl_ops->getbcncfg(netdev, i, 932 &value_integer); 933 ret = nla_put_u32(dcbnl_skb, i, value_integer); 934 if (ret) 935 goto err_bcn; 936 } 937 938 nla_nest_end(dcbnl_skb, bcn_nest); 939 940 nlmsg_end(dcbnl_skb, nlh); 941 942 ret = rtnl_unicast(dcbnl_skb, &init_net, pid); 943 if (ret) 944 goto err; 945 946 return 0; 947 948 err_bcn: 949 nla_nest_cancel(dcbnl_skb, bcn_nest); 950 nlmsg_failure: 951 err: 952 kfree_skb(dcbnl_skb); 953 err_out: 954 ret = -EINVAL; 955 return ret; 956 } 957 958 static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, 959 u32 pid, u32 seq, u16 flags) 960 { 961 struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; 962 int i; 963 int ret = -EINVAL; 964 u8 value_byte; 965 u32 value_int; 966 967 if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg 968 || !netdev->dcbnl_ops->setbcnrp) 969 return ret; 970 971 ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, 972 tb[DCB_ATTR_BCN], 973 dcbnl_pfc_up_nest); 974 if (ret) 975 goto err; 976 977 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 978 if (data[i] == NULL) 979 continue; 980 value_byte = nla_get_u8(data[i]); 981 netdev->dcbnl_ops->setbcnrp(netdev, 982 data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); 983 } 984 985 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 986 if (data[i] == NULL) 987 continue; 988 value_int = nla_get_u32(data[i]); 989 netdev->dcbnl_ops->setbcncfg(netdev, 990 i, value_int); 991 } 992 993 ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN, 994 pid, seq, flags); 995 err: 996 return ret; 997 } 998 999 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 1000 { 1001 struct net *net = sock_net(skb->sk); 1002 struct net_device *netdev; 1003 struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh); 1004 struct nlattr *tb[DCB_ATTR_MAX + 1]; 1005 u32 pid = skb ? NETLINK_CB(skb).pid : 0; 1006 int ret = -EINVAL; 1007 1008 if (net != &init_net) 1009 return -EINVAL; 1010 1011 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 1012 dcbnl_rtnl_policy); 1013 if (ret < 0) 1014 return ret; 1015 1016 if (!tb[DCB_ATTR_IFNAME]) 1017 return -EINVAL; 1018 1019 netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME])); 1020 if (!netdev) 1021 return -EINVAL; 1022 1023 if (!netdev->dcbnl_ops) 1024 goto errout; 1025 1026 switch (dcb->cmd) { 1027 case DCB_CMD_GSTATE: 1028 ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, 1029 nlh->nlmsg_flags); 1030 goto out; 1031 case DCB_CMD_PFC_GCFG: 1032 ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq, 1033 nlh->nlmsg_flags); 1034 goto out; 1035 case DCB_CMD_GPERM_HWADDR: 1036 ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq, 1037 nlh->nlmsg_flags); 1038 goto out; 1039 case DCB_CMD_PGTX_GCFG: 1040 ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 1041 nlh->nlmsg_flags); 1042 goto out; 1043 case DCB_CMD_PGRX_GCFG: 1044 ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 1045 nlh->nlmsg_flags); 1046 goto out; 1047 case DCB_CMD_BCN_GCFG: 1048 ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq, 1049 nlh->nlmsg_flags); 1050 goto out; 1051 case DCB_CMD_SSTATE: 1052 ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq, 1053 nlh->nlmsg_flags); 1054 goto out; 1055 case DCB_CMD_PFC_SCFG: 1056 ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq, 1057 nlh->nlmsg_flags); 1058 goto out; 1059 1060 case DCB_CMD_SET_ALL: 1061 ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq, 1062 nlh->nlmsg_flags); 1063 goto out; 1064 case DCB_CMD_PGTX_SCFG: 1065 ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 1066 nlh->nlmsg_flags); 1067 goto out; 1068 case DCB_CMD_PGRX_SCFG: 1069 ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 1070 nlh->nlmsg_flags); 1071 goto out; 1072 case DCB_CMD_GCAP: 1073 ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, 1074 nlh->nlmsg_flags); 1075 goto out; 1076 case DCB_CMD_GNUMTCS: 1077 ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq, 1078 nlh->nlmsg_flags); 1079 goto out; 1080 case DCB_CMD_SNUMTCS: 1081 ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq, 1082 nlh->nlmsg_flags); 1083 goto out; 1084 case DCB_CMD_PFC_GSTATE: 1085 ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq, 1086 nlh->nlmsg_flags); 1087 goto out; 1088 case DCB_CMD_PFC_SSTATE: 1089 ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq, 1090 nlh->nlmsg_flags); 1091 goto out; 1092 case DCB_CMD_BCN_SCFG: 1093 ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 1094 nlh->nlmsg_flags); 1095 goto out; 1096 default: 1097 goto errout; 1098 } 1099 errout: 1100 ret = -EINVAL; 1101 out: 1102 dev_put(netdev); 1103 return ret; 1104 } 1105 1106 static int __init dcbnl_init(void) 1107 { 1108 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); 1109 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); 1110 1111 return 0; 1112 } 1113 module_init(dcbnl_init); 1114 1115 static void __exit dcbnl_exit(void) 1116 { 1117 rtnl_unregister(PF_UNSPEC, RTM_GETDCB); 1118 rtnl_unregister(PF_UNSPEC, RTM_SETDCB); 1119 } 1120 module_exit(dcbnl_exit); 1121 1122 1123