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