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