1 /* 2 * Copyright (c) 2008-2011, 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, see <http://www.gnu.org/licenses/>. 15 * 16 * Description: Data Center Bridging netlink interface 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 <linux/init.h> 29 #include <net/sock.h> 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 /**************** DCB attribute policies *************************************/ 53 54 /* DCB netlink attributes policy */ 55 static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { 56 [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, 57 [DCB_ATTR_STATE] = {.type = NLA_U8}, 58 [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, 59 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 60 [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 61 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 62 [DCB_ATTR_CAP] = {.type = NLA_NESTED}, 63 [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, 64 [DCB_ATTR_BCN] = {.type = NLA_NESTED}, 65 [DCB_ATTR_APP] = {.type = NLA_NESTED}, 66 [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, 67 [DCB_ATTR_DCBX] = {.type = NLA_U8}, 68 [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, 69 }; 70 71 /* DCB priority flow control to User Priority nested attributes */ 72 static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { 73 [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, 74 [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, 75 [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, 76 [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, 77 [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, 78 [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, 79 [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, 80 [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, 81 [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, 82 }; 83 84 /* DCB priority grouping nested attributes */ 85 static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { 86 [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, 87 [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, 88 [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, 89 [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, 90 [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, 91 [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, 92 [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, 93 [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, 94 [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, 95 [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, 96 [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, 97 [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, 98 [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, 99 [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, 100 [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, 101 [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, 102 [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, 103 [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, 104 }; 105 106 /* DCB traffic class nested attributes. */ 107 static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { 108 [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, 109 [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, 110 [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, 111 [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, 112 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 113 }; 114 115 /* DCB capabilities nested attributes. */ 116 static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { 117 [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, 118 [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, 119 [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, 120 [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, 121 [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, 122 [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, 123 [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, 124 [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, 125 [DCB_CAP_ATTR_DCBX] = {.type = NLA_U8}, 126 }; 127 128 /* DCB capabilities nested attributes. */ 129 static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { 130 [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, 131 [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, 132 [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, 133 }; 134 135 /* DCB BCN nested attributes. */ 136 static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { 137 [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, 138 [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, 139 [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, 140 [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, 141 [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, 142 [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, 143 [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, 144 [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, 145 [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, 146 [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, 147 [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, 148 [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, 149 [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, 150 [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, 151 [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, 152 [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, 153 [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, 154 [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, 155 [DCB_BCN_ATTR_W] = {.type = NLA_U32}, 156 [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, 157 [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, 158 [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, 159 [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, 160 [DCB_BCN_ATTR_C] = {.type = NLA_U32}, 161 [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, 162 }; 163 164 /* DCB APP nested attributes. */ 165 static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { 166 [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8}, 167 [DCB_APP_ATTR_ID] = {.type = NLA_U16}, 168 [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, 169 }; 170 171 /* IEEE 802.1Qaz nested attributes. */ 172 static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { 173 [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, 174 [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, 175 [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, 176 [DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)}, 177 [DCB_ATTR_IEEE_QCN] = {.len = sizeof(struct ieee_qcn)}, 178 [DCB_ATTR_IEEE_QCN_STATS] = {.len = sizeof(struct ieee_qcn_stats)}, 179 [DCB_ATTR_DCB_BUFFER] = {.len = sizeof(struct dcbnl_buffer)}, 180 }; 181 182 /* DCB number of traffic classes nested attributes. */ 183 static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { 184 [DCB_FEATCFG_ATTR_ALL] = {.type = NLA_FLAG}, 185 [DCB_FEATCFG_ATTR_PG] = {.type = NLA_U8}, 186 [DCB_FEATCFG_ATTR_PFC] = {.type = NLA_U8}, 187 [DCB_FEATCFG_ATTR_APP] = {.type = NLA_U8}, 188 }; 189 190 static LIST_HEAD(dcb_app_list); 191 static DEFINE_SPINLOCK(dcb_lock); 192 193 static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq, 194 u32 flags, struct nlmsghdr **nlhp) 195 { 196 struct sk_buff *skb; 197 struct dcbmsg *dcb; 198 struct nlmsghdr *nlh; 199 200 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 201 if (!skb) 202 return NULL; 203 204 nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags); 205 BUG_ON(!nlh); 206 207 dcb = nlmsg_data(nlh); 208 dcb->dcb_family = AF_UNSPEC; 209 dcb->cmd = cmd; 210 dcb->dcb_pad = 0; 211 212 if (nlhp) 213 *nlhp = nlh; 214 215 return skb; 216 } 217 218 static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh, 219 u32 seq, struct nlattr **tb, struct sk_buff *skb) 220 { 221 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ 222 if (!netdev->dcbnl_ops->getstate) 223 return -EOPNOTSUPP; 224 225 return nla_put_u8(skb, DCB_ATTR_STATE, 226 netdev->dcbnl_ops->getstate(netdev)); 227 } 228 229 static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, 230 u32 seq, struct nlattr **tb, struct sk_buff *skb) 231 { 232 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; 233 u8 value; 234 int ret; 235 int i; 236 int getall = 0; 237 238 if (!tb[DCB_ATTR_PFC_CFG]) 239 return -EINVAL; 240 241 if (!netdev->dcbnl_ops->getpfccfg) 242 return -EOPNOTSUPP; 243 244 ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX, 245 tb[DCB_ATTR_PFC_CFG], 246 dcbnl_pfc_up_nest, NULL); 247 if (ret) 248 return ret; 249 250 nest = nla_nest_start_noflag(skb, DCB_ATTR_PFC_CFG); 251 if (!nest) 252 return -EMSGSIZE; 253 254 if (data[DCB_PFC_UP_ATTR_ALL]) 255 getall = 1; 256 257 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 258 if (!getall && !data[i]) 259 continue; 260 261 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, 262 &value); 263 ret = nla_put_u8(skb, i, value); 264 if (ret) { 265 nla_nest_cancel(skb, nest); 266 return ret; 267 } 268 } 269 nla_nest_end(skb, nest); 270 271 return 0; 272 } 273 274 static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh, 275 u32 seq, struct nlattr **tb, struct sk_buff *skb) 276 { 277 u8 perm_addr[MAX_ADDR_LEN]; 278 279 if (!netdev->dcbnl_ops->getpermhwaddr) 280 return -EOPNOTSUPP; 281 282 memset(perm_addr, 0, sizeof(perm_addr)); 283 netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); 284 285 return nla_put(skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr); 286 } 287 288 static int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh, 289 u32 seq, struct nlattr **tb, struct sk_buff *skb) 290 { 291 struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; 292 u8 value; 293 int ret; 294 int i; 295 int getall = 0; 296 297 if (!tb[DCB_ATTR_CAP]) 298 return -EINVAL; 299 300 if (!netdev->dcbnl_ops->getcap) 301 return -EOPNOTSUPP; 302 303 ret = nla_parse_nested_deprecated(data, DCB_CAP_ATTR_MAX, 304 tb[DCB_ATTR_CAP], dcbnl_cap_nest, 305 NULL); 306 if (ret) 307 return ret; 308 309 nest = nla_nest_start_noflag(skb, DCB_ATTR_CAP); 310 if (!nest) 311 return -EMSGSIZE; 312 313 if (data[DCB_CAP_ATTR_ALL]) 314 getall = 1; 315 316 for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { 317 if (!getall && !data[i]) 318 continue; 319 320 if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { 321 ret = nla_put_u8(skb, i, value); 322 if (ret) { 323 nla_nest_cancel(skb, nest); 324 return ret; 325 } 326 } 327 } 328 nla_nest_end(skb, nest); 329 330 return 0; 331 } 332 333 static int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, 334 u32 seq, struct nlattr **tb, struct sk_buff *skb) 335 { 336 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; 337 u8 value; 338 int ret; 339 int i; 340 int getall = 0; 341 342 if (!tb[DCB_ATTR_NUMTCS]) 343 return -EINVAL; 344 345 if (!netdev->dcbnl_ops->getnumtcs) 346 return -EOPNOTSUPP; 347 348 ret = nla_parse_nested_deprecated(data, DCB_NUMTCS_ATTR_MAX, 349 tb[DCB_ATTR_NUMTCS], 350 dcbnl_numtcs_nest, NULL); 351 if (ret) 352 return ret; 353 354 nest = nla_nest_start_noflag(skb, DCB_ATTR_NUMTCS); 355 if (!nest) 356 return -EMSGSIZE; 357 358 if (data[DCB_NUMTCS_ATTR_ALL]) 359 getall = 1; 360 361 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 362 if (!getall && !data[i]) 363 continue; 364 365 ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); 366 if (!ret) { 367 ret = nla_put_u8(skb, i, value); 368 if (ret) { 369 nla_nest_cancel(skb, nest); 370 return ret; 371 } 372 } else 373 return -EINVAL; 374 } 375 nla_nest_end(skb, nest); 376 377 return 0; 378 } 379 380 static int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, 381 u32 seq, struct nlattr **tb, struct sk_buff *skb) 382 { 383 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; 384 int ret; 385 u8 value; 386 int i; 387 388 if (!tb[DCB_ATTR_NUMTCS]) 389 return -EINVAL; 390 391 if (!netdev->dcbnl_ops->setnumtcs) 392 return -EOPNOTSUPP; 393 394 ret = nla_parse_nested_deprecated(data, DCB_NUMTCS_ATTR_MAX, 395 tb[DCB_ATTR_NUMTCS], 396 dcbnl_numtcs_nest, NULL); 397 if (ret) 398 return ret; 399 400 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 401 if (data[i] == NULL) 402 continue; 403 404 value = nla_get_u8(data[i]); 405 406 ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); 407 if (ret) 408 break; 409 } 410 411 return nla_put_u8(skb, DCB_ATTR_NUMTCS, !!ret); 412 } 413 414 static int dcbnl_getpfcstate(struct net_device *netdev, struct nlmsghdr *nlh, 415 u32 seq, struct nlattr **tb, struct sk_buff *skb) 416 { 417 if (!netdev->dcbnl_ops->getpfcstate) 418 return -EOPNOTSUPP; 419 420 return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 421 netdev->dcbnl_ops->getpfcstate(netdev)); 422 } 423 424 static int dcbnl_setpfcstate(struct net_device *netdev, struct nlmsghdr *nlh, 425 u32 seq, struct nlattr **tb, struct sk_buff *skb) 426 { 427 u8 value; 428 429 if (!tb[DCB_ATTR_PFC_STATE]) 430 return -EINVAL; 431 432 if (!netdev->dcbnl_ops->setpfcstate) 433 return -EOPNOTSUPP; 434 435 value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); 436 437 netdev->dcbnl_ops->setpfcstate(netdev, value); 438 439 return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 0); 440 } 441 442 static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh, 443 u32 seq, struct nlattr **tb, struct sk_buff *skb) 444 { 445 struct nlattr *app_nest; 446 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 447 u16 id; 448 u8 up, idtype; 449 int ret; 450 451 if (!tb[DCB_ATTR_APP]) 452 return -EINVAL; 453 454 ret = nla_parse_nested_deprecated(app_tb, DCB_APP_ATTR_MAX, 455 tb[DCB_ATTR_APP], dcbnl_app_nest, 456 NULL); 457 if (ret) 458 return ret; 459 460 /* all must be non-null */ 461 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 462 (!app_tb[DCB_APP_ATTR_ID])) 463 return -EINVAL; 464 465 /* either by eth type or by socket number */ 466 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 467 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 468 (idtype != DCB_APP_IDTYPE_PORTNUM)) 469 return -EINVAL; 470 471 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 472 473 if (netdev->dcbnl_ops->getapp) { 474 ret = netdev->dcbnl_ops->getapp(netdev, idtype, id); 475 if (ret < 0) 476 return ret; 477 else 478 up = ret; 479 } else { 480 struct dcb_app app = { 481 .selector = idtype, 482 .protocol = id, 483 }; 484 up = dcb_getapp(netdev, &app); 485 } 486 487 app_nest = nla_nest_start_noflag(skb, DCB_ATTR_APP); 488 if (!app_nest) 489 return -EMSGSIZE; 490 491 ret = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, idtype); 492 if (ret) 493 goto out_cancel; 494 495 ret = nla_put_u16(skb, DCB_APP_ATTR_ID, id); 496 if (ret) 497 goto out_cancel; 498 499 ret = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, up); 500 if (ret) 501 goto out_cancel; 502 503 nla_nest_end(skb, app_nest); 504 505 return 0; 506 507 out_cancel: 508 nla_nest_cancel(skb, app_nest); 509 return ret; 510 } 511 512 static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh, 513 u32 seq, struct nlattr **tb, struct sk_buff *skb) 514 { 515 int ret; 516 u16 id; 517 u8 up, idtype; 518 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 519 520 if (!tb[DCB_ATTR_APP]) 521 return -EINVAL; 522 523 ret = nla_parse_nested_deprecated(app_tb, DCB_APP_ATTR_MAX, 524 tb[DCB_ATTR_APP], dcbnl_app_nest, 525 NULL); 526 if (ret) 527 return ret; 528 529 /* all must be non-null */ 530 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 531 (!app_tb[DCB_APP_ATTR_ID]) || 532 (!app_tb[DCB_APP_ATTR_PRIORITY])) 533 return -EINVAL; 534 535 /* either by eth type or by socket number */ 536 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 537 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 538 (idtype != DCB_APP_IDTYPE_PORTNUM)) 539 return -EINVAL; 540 541 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 542 up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); 543 544 if (netdev->dcbnl_ops->setapp) { 545 ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); 546 if (ret < 0) 547 return ret; 548 } else { 549 struct dcb_app app; 550 app.selector = idtype; 551 app.protocol = id; 552 app.priority = up; 553 ret = dcb_setapp(netdev, &app); 554 } 555 556 ret = nla_put_u8(skb, DCB_ATTR_APP, ret); 557 dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0); 558 559 return ret; 560 } 561 562 static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 563 struct nlattr **tb, struct sk_buff *skb, int dir) 564 { 565 struct nlattr *pg_nest, *param_nest, *data; 566 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 567 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 568 u8 prio, pgid, tc_pct, up_map; 569 int ret; 570 int getall = 0; 571 int i; 572 573 if (!tb[DCB_ATTR_PG_CFG]) 574 return -EINVAL; 575 576 if (!netdev->dcbnl_ops->getpgtccfgtx || 577 !netdev->dcbnl_ops->getpgtccfgrx || 578 !netdev->dcbnl_ops->getpgbwgcfgtx || 579 !netdev->dcbnl_ops->getpgbwgcfgrx) 580 return -EOPNOTSUPP; 581 582 ret = nla_parse_nested_deprecated(pg_tb, DCB_PG_ATTR_MAX, 583 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest, 584 NULL); 585 if (ret) 586 return ret; 587 588 pg_nest = nla_nest_start_noflag(skb, DCB_ATTR_PG_CFG); 589 if (!pg_nest) 590 return -EMSGSIZE; 591 592 if (pg_tb[DCB_PG_ATTR_TC_ALL]) 593 getall = 1; 594 595 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 596 if (!getall && !pg_tb[i]) 597 continue; 598 599 if (pg_tb[DCB_PG_ATTR_TC_ALL]) 600 data = pg_tb[DCB_PG_ATTR_TC_ALL]; 601 else 602 data = pg_tb[i]; 603 ret = nla_parse_nested_deprecated(param_tb, 604 DCB_TC_ATTR_PARAM_MAX, data, 605 dcbnl_tc_param_nest, NULL); 606 if (ret) 607 goto err_pg; 608 609 param_nest = nla_nest_start_noflag(skb, i); 610 if (!param_nest) 611 goto err_pg; 612 613 pgid = DCB_ATTR_VALUE_UNDEFINED; 614 prio = DCB_ATTR_VALUE_UNDEFINED; 615 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 616 up_map = DCB_ATTR_VALUE_UNDEFINED; 617 618 if (dir) { 619 /* Rx */ 620 netdev->dcbnl_ops->getpgtccfgrx(netdev, 621 i - DCB_PG_ATTR_TC_0, &prio, 622 &pgid, &tc_pct, &up_map); 623 } else { 624 /* Tx */ 625 netdev->dcbnl_ops->getpgtccfgtx(netdev, 626 i - DCB_PG_ATTR_TC_0, &prio, 627 &pgid, &tc_pct, &up_map); 628 } 629 630 if (param_tb[DCB_TC_ATTR_PARAM_PGID] || 631 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 632 ret = nla_put_u8(skb, 633 DCB_TC_ATTR_PARAM_PGID, pgid); 634 if (ret) 635 goto err_param; 636 } 637 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || 638 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 639 ret = nla_put_u8(skb, 640 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); 641 if (ret) 642 goto err_param; 643 } 644 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || 645 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 646 ret = nla_put_u8(skb, 647 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); 648 if (ret) 649 goto err_param; 650 } 651 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || 652 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 653 ret = nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, 654 tc_pct); 655 if (ret) 656 goto err_param; 657 } 658 nla_nest_end(skb, param_nest); 659 } 660 661 if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) 662 getall = 1; 663 else 664 getall = 0; 665 666 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 667 if (!getall && !pg_tb[i]) 668 continue; 669 670 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 671 672 if (dir) { 673 /* Rx */ 674 netdev->dcbnl_ops->getpgbwgcfgrx(netdev, 675 i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 676 } else { 677 /* Tx */ 678 netdev->dcbnl_ops->getpgbwgcfgtx(netdev, 679 i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 680 } 681 ret = nla_put_u8(skb, i, tc_pct); 682 if (ret) 683 goto err_pg; 684 } 685 686 nla_nest_end(skb, pg_nest); 687 688 return 0; 689 690 err_param: 691 nla_nest_cancel(skb, param_nest); 692 err_pg: 693 nla_nest_cancel(skb, pg_nest); 694 695 return -EMSGSIZE; 696 } 697 698 static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 699 u32 seq, struct nlattr **tb, struct sk_buff *skb) 700 { 701 return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 0); 702 } 703 704 static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 705 u32 seq, struct nlattr **tb, struct sk_buff *skb) 706 { 707 return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 1); 708 } 709 710 static int dcbnl_setstate(struct net_device *netdev, struct nlmsghdr *nlh, 711 u32 seq, struct nlattr **tb, struct sk_buff *skb) 712 { 713 u8 value; 714 715 if (!tb[DCB_ATTR_STATE]) 716 return -EINVAL; 717 718 if (!netdev->dcbnl_ops->setstate) 719 return -EOPNOTSUPP; 720 721 value = nla_get_u8(tb[DCB_ATTR_STATE]); 722 723 return nla_put_u8(skb, DCB_ATTR_STATE, 724 netdev->dcbnl_ops->setstate(netdev, value)); 725 } 726 727 static int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, 728 u32 seq, struct nlattr **tb, struct sk_buff *skb) 729 { 730 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; 731 int i; 732 int ret; 733 u8 value; 734 735 if (!tb[DCB_ATTR_PFC_CFG]) 736 return -EINVAL; 737 738 if (!netdev->dcbnl_ops->setpfccfg) 739 return -EOPNOTSUPP; 740 741 ret = nla_parse_nested_deprecated(data, DCB_PFC_UP_ATTR_MAX, 742 tb[DCB_ATTR_PFC_CFG], 743 dcbnl_pfc_up_nest, NULL); 744 if (ret) 745 return ret; 746 747 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 748 if (data[i] == NULL) 749 continue; 750 value = nla_get_u8(data[i]); 751 netdev->dcbnl_ops->setpfccfg(netdev, 752 data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); 753 } 754 755 return nla_put_u8(skb, DCB_ATTR_PFC_CFG, 0); 756 } 757 758 static int dcbnl_setall(struct net_device *netdev, struct nlmsghdr *nlh, 759 u32 seq, struct nlattr **tb, struct sk_buff *skb) 760 { 761 int ret; 762 763 if (!tb[DCB_ATTR_SET_ALL]) 764 return -EINVAL; 765 766 if (!netdev->dcbnl_ops->setall) 767 return -EOPNOTSUPP; 768 769 ret = nla_put_u8(skb, DCB_ATTR_SET_ALL, 770 netdev->dcbnl_ops->setall(netdev)); 771 dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0); 772 773 return ret; 774 } 775 776 static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 777 u32 seq, struct nlattr **tb, struct sk_buff *skb, 778 int dir) 779 { 780 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 781 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 782 int ret; 783 int i; 784 u8 pgid; 785 u8 up_map; 786 u8 prio; 787 u8 tc_pct; 788 789 if (!tb[DCB_ATTR_PG_CFG]) 790 return -EINVAL; 791 792 if (!netdev->dcbnl_ops->setpgtccfgtx || 793 !netdev->dcbnl_ops->setpgtccfgrx || 794 !netdev->dcbnl_ops->setpgbwgcfgtx || 795 !netdev->dcbnl_ops->setpgbwgcfgrx) 796 return -EOPNOTSUPP; 797 798 ret = nla_parse_nested_deprecated(pg_tb, DCB_PG_ATTR_MAX, 799 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest, 800 NULL); 801 if (ret) 802 return ret; 803 804 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 805 if (!pg_tb[i]) 806 continue; 807 808 ret = nla_parse_nested_deprecated(param_tb, 809 DCB_TC_ATTR_PARAM_MAX, 810 pg_tb[i], 811 dcbnl_tc_param_nest, NULL); 812 if (ret) 813 return ret; 814 815 pgid = DCB_ATTR_VALUE_UNDEFINED; 816 prio = DCB_ATTR_VALUE_UNDEFINED; 817 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 818 up_map = DCB_ATTR_VALUE_UNDEFINED; 819 820 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]) 821 prio = 822 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]); 823 824 if (param_tb[DCB_TC_ATTR_PARAM_PGID]) 825 pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]); 826 827 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT]) 828 tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]); 829 830 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]) 831 up_map = 832 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]); 833 834 /* dir: Tx = 0, Rx = 1 */ 835 if (dir) { 836 /* Rx */ 837 netdev->dcbnl_ops->setpgtccfgrx(netdev, 838 i - DCB_PG_ATTR_TC_0, 839 prio, pgid, tc_pct, up_map); 840 } else { 841 /* Tx */ 842 netdev->dcbnl_ops->setpgtccfgtx(netdev, 843 i - DCB_PG_ATTR_TC_0, 844 prio, pgid, tc_pct, up_map); 845 } 846 } 847 848 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 849 if (!pg_tb[i]) 850 continue; 851 852 tc_pct = nla_get_u8(pg_tb[i]); 853 854 /* dir: Tx = 0, Rx = 1 */ 855 if (dir) { 856 /* Rx */ 857 netdev->dcbnl_ops->setpgbwgcfgrx(netdev, 858 i - DCB_PG_ATTR_BW_ID_0, tc_pct); 859 } else { 860 /* Tx */ 861 netdev->dcbnl_ops->setpgbwgcfgtx(netdev, 862 i - DCB_PG_ATTR_BW_ID_0, tc_pct); 863 } 864 } 865 866 return nla_put_u8(skb, DCB_ATTR_PG_CFG, 0); 867 } 868 869 static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 870 u32 seq, struct nlattr **tb, struct sk_buff *skb) 871 { 872 return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 0); 873 } 874 875 static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 876 u32 seq, struct nlattr **tb, struct sk_buff *skb) 877 { 878 return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 1); 879 } 880 881 static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 882 u32 seq, struct nlattr **tb, struct sk_buff *skb) 883 { 884 struct nlattr *bcn_nest; 885 struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; 886 u8 value_byte; 887 u32 value_integer; 888 int ret; 889 bool getall = false; 890 int i; 891 892 if (!tb[DCB_ATTR_BCN]) 893 return -EINVAL; 894 895 if (!netdev->dcbnl_ops->getbcnrp || 896 !netdev->dcbnl_ops->getbcncfg) 897 return -EOPNOTSUPP; 898 899 ret = nla_parse_nested_deprecated(bcn_tb, DCB_BCN_ATTR_MAX, 900 tb[DCB_ATTR_BCN], dcbnl_bcn_nest, 901 NULL); 902 if (ret) 903 return ret; 904 905 bcn_nest = nla_nest_start_noflag(skb, DCB_ATTR_BCN); 906 if (!bcn_nest) 907 return -EMSGSIZE; 908 909 if (bcn_tb[DCB_BCN_ATTR_ALL]) 910 getall = true; 911 912 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 913 if (!getall && !bcn_tb[i]) 914 continue; 915 916 netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, 917 &value_byte); 918 ret = nla_put_u8(skb, i, value_byte); 919 if (ret) 920 goto err_bcn; 921 } 922 923 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 924 if (!getall && !bcn_tb[i]) 925 continue; 926 927 netdev->dcbnl_ops->getbcncfg(netdev, i, 928 &value_integer); 929 ret = nla_put_u32(skb, i, value_integer); 930 if (ret) 931 goto err_bcn; 932 } 933 934 nla_nest_end(skb, bcn_nest); 935 936 return 0; 937 938 err_bcn: 939 nla_nest_cancel(skb, bcn_nest); 940 return ret; 941 } 942 943 static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 944 u32 seq, struct nlattr **tb, struct sk_buff *skb) 945 { 946 struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; 947 int i; 948 int ret; 949 u8 value_byte; 950 u32 value_int; 951 952 if (!tb[DCB_ATTR_BCN]) 953 return -EINVAL; 954 955 if (!netdev->dcbnl_ops->setbcncfg || 956 !netdev->dcbnl_ops->setbcnrp) 957 return -EOPNOTSUPP; 958 959 ret = nla_parse_nested_deprecated(data, DCB_BCN_ATTR_MAX, 960 tb[DCB_ATTR_BCN], dcbnl_pfc_up_nest, 961 NULL); 962 if (ret) 963 return ret; 964 965 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 966 if (data[i] == NULL) 967 continue; 968 value_byte = nla_get_u8(data[i]); 969 netdev->dcbnl_ops->setbcnrp(netdev, 970 data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); 971 } 972 973 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 974 if (data[i] == NULL) 975 continue; 976 value_int = nla_get_u32(data[i]); 977 netdev->dcbnl_ops->setbcncfg(netdev, 978 i, value_int); 979 } 980 981 return nla_put_u8(skb, DCB_ATTR_BCN, 0); 982 } 983 984 static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, 985 int app_nested_type, int app_info_type, 986 int app_entry_type) 987 { 988 struct dcb_peer_app_info info; 989 struct dcb_app *table = NULL; 990 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 991 u16 app_count; 992 int err; 993 994 995 /** 996 * retrieve the peer app configuration form the driver. If the driver 997 * handlers fail exit without doing anything 998 */ 999 err = ops->peer_getappinfo(netdev, &info, &app_count); 1000 if (!err && app_count) { 1001 table = kmalloc_array(app_count, sizeof(struct dcb_app), 1002 GFP_KERNEL); 1003 if (!table) 1004 return -ENOMEM; 1005 1006 err = ops->peer_getapptable(netdev, table); 1007 } 1008 1009 if (!err) { 1010 u16 i; 1011 struct nlattr *app; 1012 1013 /** 1014 * build the message, from here on the only possible failure 1015 * is due to the skb size 1016 */ 1017 err = -EMSGSIZE; 1018 1019 app = nla_nest_start_noflag(skb, app_nested_type); 1020 if (!app) 1021 goto nla_put_failure; 1022 1023 if (app_info_type && 1024 nla_put(skb, app_info_type, sizeof(info), &info)) 1025 goto nla_put_failure; 1026 1027 for (i = 0; i < app_count; i++) { 1028 if (nla_put(skb, app_entry_type, sizeof(struct dcb_app), 1029 &table[i])) 1030 goto nla_put_failure; 1031 } 1032 nla_nest_end(skb, app); 1033 } 1034 err = 0; 1035 1036 nla_put_failure: 1037 kfree(table); 1038 return err; 1039 } 1040 1041 /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb GET commands. */ 1042 static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) 1043 { 1044 struct nlattr *ieee, *app; 1045 struct dcb_app_type *itr; 1046 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1047 int dcbx; 1048 int err; 1049 1050 if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 1051 return -EMSGSIZE; 1052 1053 ieee = nla_nest_start_noflag(skb, DCB_ATTR_IEEE); 1054 if (!ieee) 1055 return -EMSGSIZE; 1056 1057 if (ops->ieee_getets) { 1058 struct ieee_ets ets; 1059 memset(&ets, 0, sizeof(ets)); 1060 err = ops->ieee_getets(netdev, &ets); 1061 if (!err && 1062 nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets)) 1063 return -EMSGSIZE; 1064 } 1065 1066 if (ops->ieee_getmaxrate) { 1067 struct ieee_maxrate maxrate; 1068 memset(&maxrate, 0, sizeof(maxrate)); 1069 err = ops->ieee_getmaxrate(netdev, &maxrate); 1070 if (!err) { 1071 err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE, 1072 sizeof(maxrate), &maxrate); 1073 if (err) 1074 return -EMSGSIZE; 1075 } 1076 } 1077 1078 if (ops->ieee_getqcn) { 1079 struct ieee_qcn qcn; 1080 1081 memset(&qcn, 0, sizeof(qcn)); 1082 err = ops->ieee_getqcn(netdev, &qcn); 1083 if (!err) { 1084 err = nla_put(skb, DCB_ATTR_IEEE_QCN, 1085 sizeof(qcn), &qcn); 1086 if (err) 1087 return -EMSGSIZE; 1088 } 1089 } 1090 1091 if (ops->ieee_getqcnstats) { 1092 struct ieee_qcn_stats qcn_stats; 1093 1094 memset(&qcn_stats, 0, sizeof(qcn_stats)); 1095 err = ops->ieee_getqcnstats(netdev, &qcn_stats); 1096 if (!err) { 1097 err = nla_put(skb, DCB_ATTR_IEEE_QCN_STATS, 1098 sizeof(qcn_stats), &qcn_stats); 1099 if (err) 1100 return -EMSGSIZE; 1101 } 1102 } 1103 1104 if (ops->ieee_getpfc) { 1105 struct ieee_pfc pfc; 1106 memset(&pfc, 0, sizeof(pfc)); 1107 err = ops->ieee_getpfc(netdev, &pfc); 1108 if (!err && 1109 nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc)) 1110 return -EMSGSIZE; 1111 } 1112 1113 if (ops->dcbnl_getbuffer) { 1114 struct dcbnl_buffer buffer; 1115 1116 memset(&buffer, 0, sizeof(buffer)); 1117 err = ops->dcbnl_getbuffer(netdev, &buffer); 1118 if (!err && 1119 nla_put(skb, DCB_ATTR_DCB_BUFFER, sizeof(buffer), &buffer)) 1120 return -EMSGSIZE; 1121 } 1122 1123 app = nla_nest_start_noflag(skb, DCB_ATTR_IEEE_APP_TABLE); 1124 if (!app) 1125 return -EMSGSIZE; 1126 1127 spin_lock_bh(&dcb_lock); 1128 list_for_each_entry(itr, &dcb_app_list, list) { 1129 if (itr->ifindex == netdev->ifindex) { 1130 err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), 1131 &itr->app); 1132 if (err) { 1133 spin_unlock_bh(&dcb_lock); 1134 return -EMSGSIZE; 1135 } 1136 } 1137 } 1138 1139 if (netdev->dcbnl_ops->getdcbx) 1140 dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1141 else 1142 dcbx = -EOPNOTSUPP; 1143 1144 spin_unlock_bh(&dcb_lock); 1145 nla_nest_end(skb, app); 1146 1147 /* get peer info if available */ 1148 if (ops->ieee_peer_getets) { 1149 struct ieee_ets ets; 1150 memset(&ets, 0, sizeof(ets)); 1151 err = ops->ieee_peer_getets(netdev, &ets); 1152 if (!err && 1153 nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets)) 1154 return -EMSGSIZE; 1155 } 1156 1157 if (ops->ieee_peer_getpfc) { 1158 struct ieee_pfc pfc; 1159 memset(&pfc, 0, sizeof(pfc)); 1160 err = ops->ieee_peer_getpfc(netdev, &pfc); 1161 if (!err && 1162 nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc)) 1163 return -EMSGSIZE; 1164 } 1165 1166 if (ops->peer_getappinfo && ops->peer_getapptable) { 1167 err = dcbnl_build_peer_app(netdev, skb, 1168 DCB_ATTR_IEEE_PEER_APP, 1169 DCB_ATTR_IEEE_APP_UNSPEC, 1170 DCB_ATTR_IEEE_APP); 1171 if (err) 1172 return -EMSGSIZE; 1173 } 1174 1175 nla_nest_end(skb, ieee); 1176 if (dcbx >= 0) { 1177 err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1178 if (err) 1179 return -EMSGSIZE; 1180 } 1181 1182 return 0; 1183 } 1184 1185 static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, 1186 int dir) 1187 { 1188 u8 pgid, up_map, prio, tc_pct; 1189 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1190 int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG; 1191 struct nlattr *pg = nla_nest_start_noflag(skb, i); 1192 1193 if (!pg) 1194 return -EMSGSIZE; 1195 1196 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 1197 struct nlattr *tc_nest = nla_nest_start_noflag(skb, i); 1198 1199 if (!tc_nest) 1200 return -EMSGSIZE; 1201 1202 pgid = DCB_ATTR_VALUE_UNDEFINED; 1203 prio = DCB_ATTR_VALUE_UNDEFINED; 1204 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 1205 up_map = DCB_ATTR_VALUE_UNDEFINED; 1206 1207 if (!dir) 1208 ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0, 1209 &prio, &pgid, &tc_pct, &up_map); 1210 else 1211 ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, 1212 &prio, &pgid, &tc_pct, &up_map); 1213 1214 if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) || 1215 nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) || 1216 nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) || 1217 nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct)) 1218 return -EMSGSIZE; 1219 nla_nest_end(skb, tc_nest); 1220 } 1221 1222 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 1223 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 1224 1225 if (!dir) 1226 ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0, 1227 &tc_pct); 1228 else 1229 ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, 1230 &tc_pct); 1231 if (nla_put_u8(skb, i, tc_pct)) 1232 return -EMSGSIZE; 1233 } 1234 nla_nest_end(skb, pg); 1235 return 0; 1236 } 1237 1238 static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) 1239 { 1240 struct nlattr *cee, *app; 1241 struct dcb_app_type *itr; 1242 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1243 int dcbx, i, err = -EMSGSIZE; 1244 u8 value; 1245 1246 if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 1247 goto nla_put_failure; 1248 cee = nla_nest_start_noflag(skb, DCB_ATTR_CEE); 1249 if (!cee) 1250 goto nla_put_failure; 1251 1252 /* local pg */ 1253 if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) { 1254 err = dcbnl_cee_pg_fill(skb, netdev, 1); 1255 if (err) 1256 goto nla_put_failure; 1257 } 1258 1259 if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) { 1260 err = dcbnl_cee_pg_fill(skb, netdev, 0); 1261 if (err) 1262 goto nla_put_failure; 1263 } 1264 1265 /* local pfc */ 1266 if (ops->getpfccfg) { 1267 struct nlattr *pfc_nest = nla_nest_start_noflag(skb, 1268 DCB_ATTR_CEE_PFC); 1269 1270 if (!pfc_nest) 1271 goto nla_put_failure; 1272 1273 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 1274 ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); 1275 if (nla_put_u8(skb, i, value)) 1276 goto nla_put_failure; 1277 } 1278 nla_nest_end(skb, pfc_nest); 1279 } 1280 1281 /* local app */ 1282 spin_lock_bh(&dcb_lock); 1283 app = nla_nest_start_noflag(skb, DCB_ATTR_CEE_APP_TABLE); 1284 if (!app) 1285 goto dcb_unlock; 1286 1287 list_for_each_entry(itr, &dcb_app_list, list) { 1288 if (itr->ifindex == netdev->ifindex) { 1289 struct nlattr *app_nest = nla_nest_start_noflag(skb, 1290 DCB_ATTR_APP); 1291 if (!app_nest) 1292 goto dcb_unlock; 1293 1294 err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, 1295 itr->app.selector); 1296 if (err) 1297 goto dcb_unlock; 1298 1299 err = nla_put_u16(skb, DCB_APP_ATTR_ID, 1300 itr->app.protocol); 1301 if (err) 1302 goto dcb_unlock; 1303 1304 err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, 1305 itr->app.priority); 1306 if (err) 1307 goto dcb_unlock; 1308 1309 nla_nest_end(skb, app_nest); 1310 } 1311 } 1312 nla_nest_end(skb, app); 1313 1314 if (netdev->dcbnl_ops->getdcbx) 1315 dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1316 else 1317 dcbx = -EOPNOTSUPP; 1318 1319 spin_unlock_bh(&dcb_lock); 1320 1321 /* features flags */ 1322 if (ops->getfeatcfg) { 1323 struct nlattr *feat = nla_nest_start_noflag(skb, 1324 DCB_ATTR_CEE_FEAT); 1325 if (!feat) 1326 goto nla_put_failure; 1327 1328 for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; 1329 i++) 1330 if (!ops->getfeatcfg(netdev, i, &value) && 1331 nla_put_u8(skb, i, value)) 1332 goto nla_put_failure; 1333 1334 nla_nest_end(skb, feat); 1335 } 1336 1337 /* peer info if available */ 1338 if (ops->cee_peer_getpg) { 1339 struct cee_pg pg; 1340 memset(&pg, 0, sizeof(pg)); 1341 err = ops->cee_peer_getpg(netdev, &pg); 1342 if (!err && 1343 nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg)) 1344 goto nla_put_failure; 1345 } 1346 1347 if (ops->cee_peer_getpfc) { 1348 struct cee_pfc pfc; 1349 memset(&pfc, 0, sizeof(pfc)); 1350 err = ops->cee_peer_getpfc(netdev, &pfc); 1351 if (!err && 1352 nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc)) 1353 goto nla_put_failure; 1354 } 1355 1356 if (ops->peer_getappinfo && ops->peer_getapptable) { 1357 err = dcbnl_build_peer_app(netdev, skb, 1358 DCB_ATTR_CEE_PEER_APP_TABLE, 1359 DCB_ATTR_CEE_PEER_APP_INFO, 1360 DCB_ATTR_CEE_PEER_APP); 1361 if (err) 1362 goto nla_put_failure; 1363 } 1364 nla_nest_end(skb, cee); 1365 1366 /* DCBX state */ 1367 if (dcbx >= 0) { 1368 err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1369 if (err) 1370 goto nla_put_failure; 1371 } 1372 return 0; 1373 1374 dcb_unlock: 1375 spin_unlock_bh(&dcb_lock); 1376 nla_put_failure: 1377 err = -EMSGSIZE; 1378 return err; 1379 } 1380 1381 static int dcbnl_notify(struct net_device *dev, int event, int cmd, 1382 u32 seq, u32 portid, int dcbx_ver) 1383 { 1384 struct net *net = dev_net(dev); 1385 struct sk_buff *skb; 1386 struct nlmsghdr *nlh; 1387 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1388 int err; 1389 1390 if (!ops) 1391 return -EOPNOTSUPP; 1392 1393 skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh); 1394 if (!skb) 1395 return -ENOBUFS; 1396 1397 if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) 1398 err = dcbnl_ieee_fill(skb, dev); 1399 else 1400 err = dcbnl_cee_fill(skb, dev); 1401 1402 if (err < 0) { 1403 /* Report error to broadcast listeners */ 1404 nlmsg_free(skb); 1405 rtnl_set_sk_err(net, RTNLGRP_DCB, err); 1406 } else { 1407 /* End nlmsg and notify broadcast listeners */ 1408 nlmsg_end(skb, nlh); 1409 rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); 1410 } 1411 1412 return err; 1413 } 1414 1415 int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, 1416 u32 seq, u32 portid) 1417 { 1418 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE); 1419 } 1420 EXPORT_SYMBOL(dcbnl_ieee_notify); 1421 1422 int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, 1423 u32 seq, u32 portid) 1424 { 1425 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE); 1426 } 1427 EXPORT_SYMBOL(dcbnl_cee_notify); 1428 1429 /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb SET commands. 1430 * If any requested operation can not be completed 1431 * the entire msg is aborted and error value is returned. 1432 * No attempt is made to reconcile the case where only part of the 1433 * cmd can be completed. 1434 */ 1435 static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, 1436 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1437 { 1438 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1439 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1440 int err; 1441 1442 if (!ops) 1443 return -EOPNOTSUPP; 1444 1445 if (!tb[DCB_ATTR_IEEE]) 1446 return -EINVAL; 1447 1448 err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX, 1449 tb[DCB_ATTR_IEEE], 1450 dcbnl_ieee_policy, NULL); 1451 if (err) 1452 return err; 1453 1454 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { 1455 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); 1456 err = ops->ieee_setets(netdev, ets); 1457 if (err) 1458 goto err; 1459 } 1460 1461 if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) { 1462 struct ieee_maxrate *maxrate = 1463 nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]); 1464 err = ops->ieee_setmaxrate(netdev, maxrate); 1465 if (err) 1466 goto err; 1467 } 1468 1469 if (ieee[DCB_ATTR_IEEE_QCN] && ops->ieee_setqcn) { 1470 struct ieee_qcn *qcn = 1471 nla_data(ieee[DCB_ATTR_IEEE_QCN]); 1472 1473 err = ops->ieee_setqcn(netdev, qcn); 1474 if (err) 1475 goto err; 1476 } 1477 1478 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { 1479 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); 1480 err = ops->ieee_setpfc(netdev, pfc); 1481 if (err) 1482 goto err; 1483 } 1484 1485 if (ieee[DCB_ATTR_DCB_BUFFER] && ops->dcbnl_setbuffer) { 1486 struct dcbnl_buffer *buffer = 1487 nla_data(ieee[DCB_ATTR_DCB_BUFFER]); 1488 1489 err = ops->dcbnl_setbuffer(netdev, buffer); 1490 if (err) 1491 goto err; 1492 } 1493 1494 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1495 struct nlattr *attr; 1496 int rem; 1497 1498 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1499 struct dcb_app *app_data; 1500 1501 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1502 continue; 1503 1504 if (nla_len(attr) < sizeof(struct dcb_app)) { 1505 err = -ERANGE; 1506 goto err; 1507 } 1508 1509 app_data = nla_data(attr); 1510 if (ops->ieee_setapp) 1511 err = ops->ieee_setapp(netdev, app_data); 1512 else 1513 err = dcb_ieee_setapp(netdev, app_data); 1514 if (err) 1515 goto err; 1516 } 1517 } 1518 1519 err: 1520 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1521 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); 1522 return err; 1523 } 1524 1525 static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1526 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1527 { 1528 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1529 1530 if (!ops) 1531 return -EOPNOTSUPP; 1532 1533 return dcbnl_ieee_fill(skb, netdev); 1534 } 1535 1536 static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh, 1537 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1538 { 1539 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1540 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1541 int err; 1542 1543 if (!ops) 1544 return -EOPNOTSUPP; 1545 1546 if (!tb[DCB_ATTR_IEEE]) 1547 return -EINVAL; 1548 1549 err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX, 1550 tb[DCB_ATTR_IEEE], 1551 dcbnl_ieee_policy, NULL); 1552 if (err) 1553 return err; 1554 1555 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1556 struct nlattr *attr; 1557 int rem; 1558 1559 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1560 struct dcb_app *app_data; 1561 1562 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1563 continue; 1564 app_data = nla_data(attr); 1565 if (ops->ieee_delapp) 1566 err = ops->ieee_delapp(netdev, app_data); 1567 else 1568 err = dcb_ieee_delapp(netdev, app_data); 1569 if (err) 1570 goto err; 1571 } 1572 } 1573 1574 err: 1575 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1576 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); 1577 return err; 1578 } 1579 1580 1581 /* DCBX configuration */ 1582 static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1583 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1584 { 1585 if (!netdev->dcbnl_ops->getdcbx) 1586 return -EOPNOTSUPP; 1587 1588 return nla_put_u8(skb, DCB_ATTR_DCBX, 1589 netdev->dcbnl_ops->getdcbx(netdev)); 1590 } 1591 1592 static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1593 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1594 { 1595 u8 value; 1596 1597 if (!netdev->dcbnl_ops->setdcbx) 1598 return -EOPNOTSUPP; 1599 1600 if (!tb[DCB_ATTR_DCBX]) 1601 return -EINVAL; 1602 1603 value = nla_get_u8(tb[DCB_ATTR_DCBX]); 1604 1605 return nla_put_u8(skb, DCB_ATTR_DCBX, 1606 netdev->dcbnl_ops->setdcbx(netdev, value)); 1607 } 1608 1609 static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1610 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1611 { 1612 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; 1613 u8 value; 1614 int ret, i; 1615 int getall = 0; 1616 1617 if (!netdev->dcbnl_ops->getfeatcfg) 1618 return -EOPNOTSUPP; 1619 1620 if (!tb[DCB_ATTR_FEATCFG]) 1621 return -EINVAL; 1622 1623 ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX, 1624 tb[DCB_ATTR_FEATCFG], 1625 dcbnl_featcfg_nest, NULL); 1626 if (ret) 1627 return ret; 1628 1629 nest = nla_nest_start_noflag(skb, DCB_ATTR_FEATCFG); 1630 if (!nest) 1631 return -EMSGSIZE; 1632 1633 if (data[DCB_FEATCFG_ATTR_ALL]) 1634 getall = 1; 1635 1636 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1637 if (!getall && !data[i]) 1638 continue; 1639 1640 ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); 1641 if (!ret) 1642 ret = nla_put_u8(skb, i, value); 1643 1644 if (ret) { 1645 nla_nest_cancel(skb, nest); 1646 goto nla_put_failure; 1647 } 1648 } 1649 nla_nest_end(skb, nest); 1650 1651 nla_put_failure: 1652 return ret; 1653 } 1654 1655 static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1656 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1657 { 1658 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; 1659 int ret, i; 1660 u8 value; 1661 1662 if (!netdev->dcbnl_ops->setfeatcfg) 1663 return -ENOTSUPP; 1664 1665 if (!tb[DCB_ATTR_FEATCFG]) 1666 return -EINVAL; 1667 1668 ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX, 1669 tb[DCB_ATTR_FEATCFG], 1670 dcbnl_featcfg_nest, NULL); 1671 1672 if (ret) 1673 goto err; 1674 1675 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1676 if (data[i] == NULL) 1677 continue; 1678 1679 value = nla_get_u8(data[i]); 1680 1681 ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); 1682 1683 if (ret) 1684 goto err; 1685 } 1686 err: 1687 ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret); 1688 1689 return ret; 1690 } 1691 1692 /* Handle CEE DCBX GET commands. */ 1693 static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1694 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1695 { 1696 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1697 1698 if (!ops) 1699 return -EOPNOTSUPP; 1700 1701 return dcbnl_cee_fill(skb, netdev); 1702 } 1703 1704 struct reply_func { 1705 /* reply netlink message type */ 1706 int type; 1707 1708 /* function to fill message contents */ 1709 int (*cb)(struct net_device *, struct nlmsghdr *, u32, 1710 struct nlattr **, struct sk_buff *); 1711 }; 1712 1713 static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = { 1714 [DCB_CMD_GSTATE] = { RTM_GETDCB, dcbnl_getstate }, 1715 [DCB_CMD_SSTATE] = { RTM_SETDCB, dcbnl_setstate }, 1716 [DCB_CMD_PFC_GCFG] = { RTM_GETDCB, dcbnl_getpfccfg }, 1717 [DCB_CMD_PFC_SCFG] = { RTM_SETDCB, dcbnl_setpfccfg }, 1718 [DCB_CMD_GPERM_HWADDR] = { RTM_GETDCB, dcbnl_getperm_hwaddr }, 1719 [DCB_CMD_GCAP] = { RTM_GETDCB, dcbnl_getcap }, 1720 [DCB_CMD_GNUMTCS] = { RTM_GETDCB, dcbnl_getnumtcs }, 1721 [DCB_CMD_SNUMTCS] = { RTM_SETDCB, dcbnl_setnumtcs }, 1722 [DCB_CMD_PFC_GSTATE] = { RTM_GETDCB, dcbnl_getpfcstate }, 1723 [DCB_CMD_PFC_SSTATE] = { RTM_SETDCB, dcbnl_setpfcstate }, 1724 [DCB_CMD_GAPP] = { RTM_GETDCB, dcbnl_getapp }, 1725 [DCB_CMD_SAPP] = { RTM_SETDCB, dcbnl_setapp }, 1726 [DCB_CMD_PGTX_GCFG] = { RTM_GETDCB, dcbnl_pgtx_getcfg }, 1727 [DCB_CMD_PGTX_SCFG] = { RTM_SETDCB, dcbnl_pgtx_setcfg }, 1728 [DCB_CMD_PGRX_GCFG] = { RTM_GETDCB, dcbnl_pgrx_getcfg }, 1729 [DCB_CMD_PGRX_SCFG] = { RTM_SETDCB, dcbnl_pgrx_setcfg }, 1730 [DCB_CMD_SET_ALL] = { RTM_SETDCB, dcbnl_setall }, 1731 [DCB_CMD_BCN_GCFG] = { RTM_GETDCB, dcbnl_bcn_getcfg }, 1732 [DCB_CMD_BCN_SCFG] = { RTM_SETDCB, dcbnl_bcn_setcfg }, 1733 [DCB_CMD_IEEE_GET] = { RTM_GETDCB, dcbnl_ieee_get }, 1734 [DCB_CMD_IEEE_SET] = { RTM_SETDCB, dcbnl_ieee_set }, 1735 [DCB_CMD_IEEE_DEL] = { RTM_SETDCB, dcbnl_ieee_del }, 1736 [DCB_CMD_GDCBX] = { RTM_GETDCB, dcbnl_getdcbx }, 1737 [DCB_CMD_SDCBX] = { RTM_SETDCB, dcbnl_setdcbx }, 1738 [DCB_CMD_GFEATCFG] = { RTM_GETDCB, dcbnl_getfeatcfg }, 1739 [DCB_CMD_SFEATCFG] = { RTM_SETDCB, dcbnl_setfeatcfg }, 1740 [DCB_CMD_CEE_GET] = { RTM_GETDCB, dcbnl_cee_get }, 1741 }; 1742 1743 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 1744 struct netlink_ext_ack *extack) 1745 { 1746 struct net *net = sock_net(skb->sk); 1747 struct net_device *netdev; 1748 struct dcbmsg *dcb = nlmsg_data(nlh); 1749 struct nlattr *tb[DCB_ATTR_MAX + 1]; 1750 u32 portid = skb ? NETLINK_CB(skb).portid : 0; 1751 int ret = -EINVAL; 1752 struct sk_buff *reply_skb; 1753 struct nlmsghdr *reply_nlh = NULL; 1754 const struct reply_func *fn; 1755 1756 if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN)) 1757 return -EPERM; 1758 1759 ret = nlmsg_parse_deprecated(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 1760 dcbnl_rtnl_policy, extack); 1761 if (ret < 0) 1762 return ret; 1763 1764 if (dcb->cmd > DCB_CMD_MAX) 1765 return -EINVAL; 1766 1767 /* check if a reply function has been defined for the command */ 1768 fn = &reply_funcs[dcb->cmd]; 1769 if (!fn->cb) 1770 return -EOPNOTSUPP; 1771 1772 if (!tb[DCB_ATTR_IFNAME]) 1773 return -EINVAL; 1774 1775 netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); 1776 if (!netdev) 1777 return -ENODEV; 1778 1779 if (!netdev->dcbnl_ops) 1780 return -EOPNOTSUPP; 1781 1782 reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, 1783 nlh->nlmsg_flags, &reply_nlh); 1784 if (!reply_skb) 1785 return -ENOBUFS; 1786 1787 ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); 1788 if (ret < 0) { 1789 nlmsg_free(reply_skb); 1790 goto out; 1791 } 1792 1793 nlmsg_end(reply_skb, reply_nlh); 1794 1795 ret = rtnl_unicast(reply_skb, net, portid); 1796 out: 1797 return ret; 1798 } 1799 1800 static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app, 1801 int ifindex, int prio) 1802 { 1803 struct dcb_app_type *itr; 1804 1805 list_for_each_entry(itr, &dcb_app_list, list) { 1806 if (itr->app.selector == app->selector && 1807 itr->app.protocol == app->protocol && 1808 itr->ifindex == ifindex && 1809 ((prio == -1) || itr->app.priority == prio)) 1810 return itr; 1811 } 1812 1813 return NULL; 1814 } 1815 1816 static int dcb_app_add(const struct dcb_app *app, int ifindex) 1817 { 1818 struct dcb_app_type *entry; 1819 1820 entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 1821 if (!entry) 1822 return -ENOMEM; 1823 1824 memcpy(&entry->app, app, sizeof(*app)); 1825 entry->ifindex = ifindex; 1826 list_add(&entry->list, &dcb_app_list); 1827 1828 return 0; 1829 } 1830 1831 /** 1832 * dcb_getapp - retrieve the DCBX application user priority 1833 * 1834 * On success returns a non-zero 802.1p user priority bitmap 1835 * otherwise returns 0 as the invalid user priority bitmap to 1836 * indicate an error. 1837 */ 1838 u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) 1839 { 1840 struct dcb_app_type *itr; 1841 u8 prio = 0; 1842 1843 spin_lock_bh(&dcb_lock); 1844 itr = dcb_app_lookup(app, dev->ifindex, -1); 1845 if (itr) 1846 prio = itr->app.priority; 1847 spin_unlock_bh(&dcb_lock); 1848 1849 return prio; 1850 } 1851 EXPORT_SYMBOL(dcb_getapp); 1852 1853 /** 1854 * dcb_setapp - add CEE dcb application data to app list 1855 * 1856 * Priority 0 is an invalid priority in CEE spec. This routine 1857 * removes applications from the app list if the priority is 1858 * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap 1859 */ 1860 int dcb_setapp(struct net_device *dev, struct dcb_app *new) 1861 { 1862 struct dcb_app_type *itr; 1863 struct dcb_app_type event; 1864 int err = 0; 1865 1866 event.ifindex = dev->ifindex; 1867 memcpy(&event.app, new, sizeof(event.app)); 1868 if (dev->dcbnl_ops->getdcbx) 1869 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1870 1871 spin_lock_bh(&dcb_lock); 1872 /* Search for existing match and replace */ 1873 itr = dcb_app_lookup(new, dev->ifindex, -1); 1874 if (itr) { 1875 if (new->priority) 1876 itr->app.priority = new->priority; 1877 else { 1878 list_del(&itr->list); 1879 kfree(itr); 1880 } 1881 goto out; 1882 } 1883 /* App type does not exist add new application type */ 1884 if (new->priority) 1885 err = dcb_app_add(new, dev->ifindex); 1886 out: 1887 spin_unlock_bh(&dcb_lock); 1888 if (!err) 1889 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1890 return err; 1891 } 1892 EXPORT_SYMBOL(dcb_setapp); 1893 1894 /** 1895 * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority 1896 * 1897 * Helper routine which on success returns a non-zero 802.1Qaz user 1898 * priority bitmap otherwise returns 0 to indicate the dcb_app was 1899 * not found in APP list. 1900 */ 1901 u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) 1902 { 1903 struct dcb_app_type *itr; 1904 u8 prio = 0; 1905 1906 spin_lock_bh(&dcb_lock); 1907 itr = dcb_app_lookup(app, dev->ifindex, -1); 1908 if (itr) 1909 prio |= 1 << itr->app.priority; 1910 spin_unlock_bh(&dcb_lock); 1911 1912 return prio; 1913 } 1914 EXPORT_SYMBOL(dcb_ieee_getapp_mask); 1915 1916 /** 1917 * dcb_ieee_setapp - add IEEE dcb application data to app list 1918 * 1919 * This adds Application data to the list. Multiple application 1920 * entries may exists for the same selector and protocol as long 1921 * as the priorities are different. Priority is expected to be a 1922 * 3-bit unsigned integer 1923 */ 1924 int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) 1925 { 1926 struct dcb_app_type event; 1927 int err = 0; 1928 1929 event.ifindex = dev->ifindex; 1930 memcpy(&event.app, new, sizeof(event.app)); 1931 if (dev->dcbnl_ops->getdcbx) 1932 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1933 1934 spin_lock_bh(&dcb_lock); 1935 /* Search for existing match and abort if found */ 1936 if (dcb_app_lookup(new, dev->ifindex, new->priority)) { 1937 err = -EEXIST; 1938 goto out; 1939 } 1940 1941 err = dcb_app_add(new, dev->ifindex); 1942 out: 1943 spin_unlock_bh(&dcb_lock); 1944 if (!err) 1945 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1946 return err; 1947 } 1948 EXPORT_SYMBOL(dcb_ieee_setapp); 1949 1950 /** 1951 * dcb_ieee_delapp - delete IEEE dcb application data from list 1952 * 1953 * This removes a matching APP data from the APP list 1954 */ 1955 int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) 1956 { 1957 struct dcb_app_type *itr; 1958 struct dcb_app_type event; 1959 int err = -ENOENT; 1960 1961 event.ifindex = dev->ifindex; 1962 memcpy(&event.app, del, sizeof(event.app)); 1963 if (dev->dcbnl_ops->getdcbx) 1964 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1965 1966 spin_lock_bh(&dcb_lock); 1967 /* Search for existing match and remove it. */ 1968 if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) { 1969 list_del(&itr->list); 1970 kfree(itr); 1971 err = 0; 1972 } 1973 1974 spin_unlock_bh(&dcb_lock); 1975 if (!err) 1976 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1977 return err; 1978 } 1979 EXPORT_SYMBOL(dcb_ieee_delapp); 1980 1981 /** 1982 * dcb_ieee_getapp_prio_dscp_mask_map - For a given device, find mapping from 1983 * priorities to the DSCP values assigned to that priority. Initialize p_map 1984 * such that each map element holds a bit mask of DSCP values configured for 1985 * that priority by APP entries. 1986 */ 1987 void dcb_ieee_getapp_prio_dscp_mask_map(const struct net_device *dev, 1988 struct dcb_ieee_app_prio_map *p_map) 1989 { 1990 int ifindex = dev->ifindex; 1991 struct dcb_app_type *itr; 1992 u8 prio; 1993 1994 memset(p_map->map, 0, sizeof(p_map->map)); 1995 1996 spin_lock_bh(&dcb_lock); 1997 list_for_each_entry(itr, &dcb_app_list, list) { 1998 if (itr->ifindex == ifindex && 1999 itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP && 2000 itr->app.protocol < 64 && 2001 itr->app.priority < IEEE_8021QAZ_MAX_TCS) { 2002 prio = itr->app.priority; 2003 p_map->map[prio] |= 1ULL << itr->app.protocol; 2004 } 2005 } 2006 spin_unlock_bh(&dcb_lock); 2007 } 2008 EXPORT_SYMBOL(dcb_ieee_getapp_prio_dscp_mask_map); 2009 2010 /** 2011 * dcb_ieee_getapp_dscp_prio_mask_map - For a given device, find mapping from 2012 * DSCP values to the priorities assigned to that DSCP value. Initialize p_map 2013 * such that each map element holds a bit mask of priorities configured for a 2014 * given DSCP value by APP entries. 2015 */ 2016 void 2017 dcb_ieee_getapp_dscp_prio_mask_map(const struct net_device *dev, 2018 struct dcb_ieee_app_dscp_map *p_map) 2019 { 2020 int ifindex = dev->ifindex; 2021 struct dcb_app_type *itr; 2022 2023 memset(p_map->map, 0, sizeof(p_map->map)); 2024 2025 spin_lock_bh(&dcb_lock); 2026 list_for_each_entry(itr, &dcb_app_list, list) { 2027 if (itr->ifindex == ifindex && 2028 itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP && 2029 itr->app.protocol < 64 && 2030 itr->app.priority < IEEE_8021QAZ_MAX_TCS) 2031 p_map->map[itr->app.protocol] |= 1 << itr->app.priority; 2032 } 2033 spin_unlock_bh(&dcb_lock); 2034 } 2035 EXPORT_SYMBOL(dcb_ieee_getapp_dscp_prio_mask_map); 2036 2037 /** 2038 * Per 802.1Q-2014, the selector value of 1 is used for matching on Ethernet 2039 * type, with valid PID values >= 1536. A special meaning is then assigned to 2040 * protocol value of 0: "default priority. For use when priority is not 2041 * otherwise specified". 2042 * 2043 * dcb_ieee_getapp_default_prio_mask - For a given device, find all APP entries 2044 * of the form {$PRIO, ETHERTYPE, 0} and construct a bit mask of all default 2045 * priorities set by these entries. 2046 */ 2047 u8 dcb_ieee_getapp_default_prio_mask(const struct net_device *dev) 2048 { 2049 int ifindex = dev->ifindex; 2050 struct dcb_app_type *itr; 2051 u8 mask = 0; 2052 2053 spin_lock_bh(&dcb_lock); 2054 list_for_each_entry(itr, &dcb_app_list, list) { 2055 if (itr->ifindex == ifindex && 2056 itr->app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && 2057 itr->app.protocol == 0 && 2058 itr->app.priority < IEEE_8021QAZ_MAX_TCS) 2059 mask |= 1 << itr->app.priority; 2060 } 2061 spin_unlock_bh(&dcb_lock); 2062 2063 return mask; 2064 } 2065 EXPORT_SYMBOL(dcb_ieee_getapp_default_prio_mask); 2066 2067 static int __init dcbnl_init(void) 2068 { 2069 INIT_LIST_HEAD(&dcb_app_list); 2070 2071 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, 0); 2072 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, 0); 2073 2074 return 0; 2075 } 2076 device_initcall(dcbnl_init); 2077