sb.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
  4. * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
  5. */
  6. #include "devl_internal.h"
  7. struct devlink_sb {
  8. struct list_head list;
  9. unsigned int index;
  10. u32 size;
  11. u16 ingress_pools_count;
  12. u16 egress_pools_count;
  13. u16 ingress_tc_count;
  14. u16 egress_tc_count;
  15. };
  16. static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
  17. {
  18. return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
  19. }
  20. static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
  21. unsigned int sb_index)
  22. {
  23. struct devlink_sb *devlink_sb;
  24. list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
  25. if (devlink_sb->index == sb_index)
  26. return devlink_sb;
  27. }
  28. return NULL;
  29. }
  30. static bool devlink_sb_index_exists(struct devlink *devlink,
  31. unsigned int sb_index)
  32. {
  33. return devlink_sb_get_by_index(devlink, sb_index);
  34. }
  35. static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
  36. struct nlattr **attrs)
  37. {
  38. if (attrs[DEVLINK_ATTR_SB_INDEX]) {
  39. u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
  40. struct devlink_sb *devlink_sb;
  41. devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
  42. if (!devlink_sb)
  43. return ERR_PTR(-ENODEV);
  44. return devlink_sb;
  45. }
  46. return ERR_PTR(-EINVAL);
  47. }
  48. static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
  49. struct genl_info *info)
  50. {
  51. return devlink_sb_get_from_attrs(devlink, info->attrs);
  52. }
  53. static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
  54. struct nlattr **attrs,
  55. u16 *p_pool_index)
  56. {
  57. u16 val;
  58. if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
  59. return -EINVAL;
  60. val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
  61. if (val >= devlink_sb_pool_count(devlink_sb))
  62. return -EINVAL;
  63. *p_pool_index = val;
  64. return 0;
  65. }
  66. static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
  67. struct genl_info *info,
  68. u16 *p_pool_index)
  69. {
  70. return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
  71. p_pool_index);
  72. }
  73. static int
  74. devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
  75. enum devlink_sb_pool_type *p_pool_type)
  76. {
  77. u8 val;
  78. if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
  79. return -EINVAL;
  80. val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
  81. if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
  82. val != DEVLINK_SB_POOL_TYPE_EGRESS)
  83. return -EINVAL;
  84. *p_pool_type = val;
  85. return 0;
  86. }
  87. static int
  88. devlink_sb_pool_type_get_from_info(struct genl_info *info,
  89. enum devlink_sb_pool_type *p_pool_type)
  90. {
  91. return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
  92. }
  93. static int
  94. devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
  95. enum devlink_sb_threshold_type *p_th_type)
  96. {
  97. u8 val;
  98. if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
  99. return -EINVAL;
  100. val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
  101. if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
  102. val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
  103. return -EINVAL;
  104. *p_th_type = val;
  105. return 0;
  106. }
  107. static int
  108. devlink_sb_th_type_get_from_info(struct genl_info *info,
  109. enum devlink_sb_threshold_type *p_th_type)
  110. {
  111. return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
  112. }
  113. static int
  114. devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
  115. struct nlattr **attrs,
  116. enum devlink_sb_pool_type pool_type,
  117. u16 *p_tc_index)
  118. {
  119. u16 val;
  120. if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
  121. return -EINVAL;
  122. val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
  123. if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
  124. val >= devlink_sb->ingress_tc_count)
  125. return -EINVAL;
  126. if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
  127. val >= devlink_sb->egress_tc_count)
  128. return -EINVAL;
  129. *p_tc_index = val;
  130. return 0;
  131. }
  132. static int
  133. devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
  134. struct genl_info *info,
  135. enum devlink_sb_pool_type pool_type,
  136. u16 *p_tc_index)
  137. {
  138. return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
  139. pool_type, p_tc_index);
  140. }
  141. static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
  142. struct devlink_sb *devlink_sb,
  143. enum devlink_command cmd, u32 portid,
  144. u32 seq, int flags)
  145. {
  146. void *hdr;
  147. hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
  148. if (!hdr)
  149. return -EMSGSIZE;
  150. if (devlink_nl_put_handle(msg, devlink))
  151. goto nla_put_failure;
  152. if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
  153. goto nla_put_failure;
  154. if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
  155. goto nla_put_failure;
  156. if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
  157. devlink_sb->ingress_pools_count))
  158. goto nla_put_failure;
  159. if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
  160. devlink_sb->egress_pools_count))
  161. goto nla_put_failure;
  162. if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
  163. devlink_sb->ingress_tc_count))
  164. goto nla_put_failure;
  165. if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
  166. devlink_sb->egress_tc_count))
  167. goto nla_put_failure;
  168. genlmsg_end(msg, hdr);
  169. return 0;
  170. nla_put_failure:
  171. genlmsg_cancel(msg, hdr);
  172. return -EMSGSIZE;
  173. }
  174. int devlink_nl_sb_get_doit(struct sk_buff *skb, struct genl_info *info)
  175. {
  176. struct devlink *devlink = info->user_ptr[0];
  177. struct devlink_sb *devlink_sb;
  178. struct sk_buff *msg;
  179. int err;
  180. devlink_sb = devlink_sb_get_from_info(devlink, info);
  181. if (IS_ERR(devlink_sb))
  182. return PTR_ERR(devlink_sb);
  183. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  184. if (!msg)
  185. return -ENOMEM;
  186. err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
  187. DEVLINK_CMD_SB_NEW,
  188. info->snd_portid, info->snd_seq, 0);
  189. if (err) {
  190. nlmsg_free(msg);
  191. return err;
  192. }
  193. return genlmsg_reply(msg, info);
  194. }
  195. static int
  196. devlink_nl_sb_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
  197. struct netlink_callback *cb, int flags)
  198. {
  199. struct devlink_nl_dump_state *state = devlink_dump_state(cb);
  200. struct devlink_sb *devlink_sb;
  201. int idx = 0;
  202. int err = 0;
  203. list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
  204. if (idx < state->idx) {
  205. idx++;
  206. continue;
  207. }
  208. err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
  209. DEVLINK_CMD_SB_NEW,
  210. NETLINK_CB(cb->skb).portid,
  211. cb->nlh->nlmsg_seq, flags);
  212. if (err) {
  213. state->idx = idx;
  214. break;
  215. }
  216. idx++;
  217. }
  218. return err;
  219. }
  220. int devlink_nl_sb_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
  221. {
  222. return devlink_nl_dumpit(skb, cb, devlink_nl_sb_get_dump_one);
  223. }
  224. static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
  225. struct devlink_sb *devlink_sb,
  226. u16 pool_index, enum devlink_command cmd,
  227. u32 portid, u32 seq, int flags)
  228. {
  229. struct devlink_sb_pool_info pool_info;
  230. void *hdr;
  231. int err;
  232. err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
  233. pool_index, &pool_info);
  234. if (err)
  235. return err;
  236. hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
  237. if (!hdr)
  238. return -EMSGSIZE;
  239. if (devlink_nl_put_handle(msg, devlink))
  240. goto nla_put_failure;
  241. if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
  242. goto nla_put_failure;
  243. if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
  244. goto nla_put_failure;
  245. if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
  246. goto nla_put_failure;
  247. if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
  248. goto nla_put_failure;
  249. if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
  250. pool_info.threshold_type))
  251. goto nla_put_failure;
  252. if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
  253. pool_info.cell_size))
  254. goto nla_put_failure;
  255. genlmsg_end(msg, hdr);
  256. return 0;
  257. nla_put_failure:
  258. genlmsg_cancel(msg, hdr);
  259. return -EMSGSIZE;
  260. }
  261. int devlink_nl_sb_pool_get_doit(struct sk_buff *skb, struct genl_info *info)
  262. {
  263. struct devlink *devlink = info->user_ptr[0];
  264. struct devlink_sb *devlink_sb;
  265. struct sk_buff *msg;
  266. u16 pool_index;
  267. int err;
  268. devlink_sb = devlink_sb_get_from_info(devlink, info);
  269. if (IS_ERR(devlink_sb))
  270. return PTR_ERR(devlink_sb);
  271. err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
  272. &pool_index);
  273. if (err)
  274. return err;
  275. if (!devlink->ops->sb_pool_get)
  276. return -EOPNOTSUPP;
  277. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  278. if (!msg)
  279. return -ENOMEM;
  280. err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
  281. DEVLINK_CMD_SB_POOL_NEW,
  282. info->snd_portid, info->snd_seq, 0);
  283. if (err) {
  284. nlmsg_free(msg);
  285. return err;
  286. }
  287. return genlmsg_reply(msg, info);
  288. }
  289. static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
  290. struct devlink *devlink,
  291. struct devlink_sb *devlink_sb,
  292. u32 portid, u32 seq, int flags)
  293. {
  294. u16 pool_count = devlink_sb_pool_count(devlink_sb);
  295. u16 pool_index;
  296. int err;
  297. for (pool_index = 0; pool_index < pool_count; pool_index++) {
  298. if (*p_idx < start) {
  299. (*p_idx)++;
  300. continue;
  301. }
  302. err = devlink_nl_sb_pool_fill(msg, devlink,
  303. devlink_sb,
  304. pool_index,
  305. DEVLINK_CMD_SB_POOL_NEW,
  306. portid, seq, flags);
  307. if (err)
  308. return err;
  309. (*p_idx)++;
  310. }
  311. return 0;
  312. }
  313. static int
  314. devlink_nl_sb_pool_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
  315. struct netlink_callback *cb, int flags)
  316. {
  317. struct devlink_nl_dump_state *state = devlink_dump_state(cb);
  318. struct devlink_sb *devlink_sb;
  319. int err = 0;
  320. int idx = 0;
  321. if (!devlink->ops->sb_pool_get)
  322. return 0;
  323. list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
  324. err = __sb_pool_get_dumpit(msg, state->idx, &idx,
  325. devlink, devlink_sb,
  326. NETLINK_CB(cb->skb).portid,
  327. cb->nlh->nlmsg_seq, flags);
  328. if (err == -EOPNOTSUPP) {
  329. err = 0;
  330. } else if (err) {
  331. state->idx = idx;
  332. break;
  333. }
  334. }
  335. return err;
  336. }
  337. int devlink_nl_sb_pool_get_dumpit(struct sk_buff *skb,
  338. struct netlink_callback *cb)
  339. {
  340. return devlink_nl_dumpit(skb, cb, devlink_nl_sb_pool_get_dump_one);
  341. }
  342. static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
  343. u16 pool_index, u32 size,
  344. enum devlink_sb_threshold_type threshold_type,
  345. struct netlink_ext_ack *extack)
  346. {
  347. const struct devlink_ops *ops = devlink->ops;
  348. if (ops->sb_pool_set)
  349. return ops->sb_pool_set(devlink, sb_index, pool_index,
  350. size, threshold_type, extack);
  351. return -EOPNOTSUPP;
  352. }
  353. int devlink_nl_sb_pool_set_doit(struct sk_buff *skb, struct genl_info *info)
  354. {
  355. struct devlink *devlink = info->user_ptr[0];
  356. enum devlink_sb_threshold_type threshold_type;
  357. struct devlink_sb *devlink_sb;
  358. u16 pool_index;
  359. u32 size;
  360. int err;
  361. devlink_sb = devlink_sb_get_from_info(devlink, info);
  362. if (IS_ERR(devlink_sb))
  363. return PTR_ERR(devlink_sb);
  364. err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
  365. &pool_index);
  366. if (err)
  367. return err;
  368. err = devlink_sb_th_type_get_from_info(info, &threshold_type);
  369. if (err)
  370. return err;
  371. if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_POOL_SIZE))
  372. return -EINVAL;
  373. size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
  374. return devlink_sb_pool_set(devlink, devlink_sb->index,
  375. pool_index, size, threshold_type,
  376. info->extack);
  377. }
  378. static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
  379. struct devlink *devlink,
  380. struct devlink_port *devlink_port,
  381. struct devlink_sb *devlink_sb,
  382. u16 pool_index,
  383. enum devlink_command cmd,
  384. u32 portid, u32 seq, int flags)
  385. {
  386. const struct devlink_ops *ops = devlink->ops;
  387. u32 threshold;
  388. void *hdr;
  389. int err;
  390. err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
  391. pool_index, &threshold);
  392. if (err)
  393. return err;
  394. hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
  395. if (!hdr)
  396. return -EMSGSIZE;
  397. if (devlink_nl_put_handle(msg, devlink))
  398. goto nla_put_failure;
  399. if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
  400. goto nla_put_failure;
  401. if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
  402. goto nla_put_failure;
  403. if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
  404. goto nla_put_failure;
  405. if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
  406. goto nla_put_failure;
  407. if (ops->sb_occ_port_pool_get) {
  408. u32 cur;
  409. u32 max;
  410. err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
  411. pool_index, &cur, &max);
  412. if (err && err != -EOPNOTSUPP)
  413. goto sb_occ_get_failure;
  414. if (!err) {
  415. if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
  416. goto nla_put_failure;
  417. if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
  418. goto nla_put_failure;
  419. }
  420. }
  421. genlmsg_end(msg, hdr);
  422. return 0;
  423. nla_put_failure:
  424. err = -EMSGSIZE;
  425. sb_occ_get_failure:
  426. genlmsg_cancel(msg, hdr);
  427. return err;
  428. }
  429. int devlink_nl_sb_port_pool_get_doit(struct sk_buff *skb,
  430. struct genl_info *info)
  431. {
  432. struct devlink_port *devlink_port = info->user_ptr[1];
  433. struct devlink *devlink = devlink_port->devlink;
  434. struct devlink_sb *devlink_sb;
  435. struct sk_buff *msg;
  436. u16 pool_index;
  437. int err;
  438. devlink_sb = devlink_sb_get_from_info(devlink, info);
  439. if (IS_ERR(devlink_sb))
  440. return PTR_ERR(devlink_sb);
  441. err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
  442. &pool_index);
  443. if (err)
  444. return err;
  445. if (!devlink->ops->sb_port_pool_get)
  446. return -EOPNOTSUPP;
  447. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  448. if (!msg)
  449. return -ENOMEM;
  450. err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
  451. devlink_sb, pool_index,
  452. DEVLINK_CMD_SB_PORT_POOL_NEW,
  453. info->snd_portid, info->snd_seq, 0);
  454. if (err) {
  455. nlmsg_free(msg);
  456. return err;
  457. }
  458. return genlmsg_reply(msg, info);
  459. }
  460. static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
  461. struct devlink *devlink,
  462. struct devlink_sb *devlink_sb,
  463. u32 portid, u32 seq, int flags)
  464. {
  465. struct devlink_port *devlink_port;
  466. u16 pool_count = devlink_sb_pool_count(devlink_sb);
  467. unsigned long port_index;
  468. u16 pool_index;
  469. int err;
  470. xa_for_each(&devlink->ports, port_index, devlink_port) {
  471. for (pool_index = 0; pool_index < pool_count; pool_index++) {
  472. if (*p_idx < start) {
  473. (*p_idx)++;
  474. continue;
  475. }
  476. err = devlink_nl_sb_port_pool_fill(msg, devlink,
  477. devlink_port,
  478. devlink_sb,
  479. pool_index,
  480. DEVLINK_CMD_SB_PORT_POOL_NEW,
  481. portid, seq, flags);
  482. if (err)
  483. return err;
  484. (*p_idx)++;
  485. }
  486. }
  487. return 0;
  488. }
  489. static int
  490. devlink_nl_sb_port_pool_get_dump_one(struct sk_buff *msg,
  491. struct devlink *devlink,
  492. struct netlink_callback *cb, int flags)
  493. {
  494. struct devlink_nl_dump_state *state = devlink_dump_state(cb);
  495. struct devlink_sb *devlink_sb;
  496. int idx = 0;
  497. int err = 0;
  498. if (!devlink->ops->sb_port_pool_get)
  499. return 0;
  500. list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
  501. err = __sb_port_pool_get_dumpit(msg, state->idx, &idx,
  502. devlink, devlink_sb,
  503. NETLINK_CB(cb->skb).portid,
  504. cb->nlh->nlmsg_seq, flags);
  505. if (err == -EOPNOTSUPP) {
  506. err = 0;
  507. } else if (err) {
  508. state->idx = idx;
  509. break;
  510. }
  511. }
  512. return err;
  513. }
  514. int devlink_nl_sb_port_pool_get_dumpit(struct sk_buff *skb,
  515. struct netlink_callback *cb)
  516. {
  517. return devlink_nl_dumpit(skb, cb, devlink_nl_sb_port_pool_get_dump_one);
  518. }
  519. static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
  520. unsigned int sb_index, u16 pool_index,
  521. u32 threshold,
  522. struct netlink_ext_ack *extack)
  523. {
  524. const struct devlink_ops *ops = devlink_port->devlink->ops;
  525. if (ops->sb_port_pool_set)
  526. return ops->sb_port_pool_set(devlink_port, sb_index,
  527. pool_index, threshold, extack);
  528. return -EOPNOTSUPP;
  529. }
  530. int devlink_nl_sb_port_pool_set_doit(struct sk_buff *skb,
  531. struct genl_info *info)
  532. {
  533. struct devlink_port *devlink_port = info->user_ptr[1];
  534. struct devlink *devlink = info->user_ptr[0];
  535. struct devlink_sb *devlink_sb;
  536. u16 pool_index;
  537. u32 threshold;
  538. int err;
  539. devlink_sb = devlink_sb_get_from_info(devlink, info);
  540. if (IS_ERR(devlink_sb))
  541. return PTR_ERR(devlink_sb);
  542. err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
  543. &pool_index);
  544. if (err)
  545. return err;
  546. if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_THRESHOLD))
  547. return -EINVAL;
  548. threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
  549. return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
  550. pool_index, threshold, info->extack);
  551. }
  552. static int
  553. devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
  554. struct devlink_port *devlink_port,
  555. struct devlink_sb *devlink_sb, u16 tc_index,
  556. enum devlink_sb_pool_type pool_type,
  557. enum devlink_command cmd,
  558. u32 portid, u32 seq, int flags)
  559. {
  560. const struct devlink_ops *ops = devlink->ops;
  561. u16 pool_index;
  562. u32 threshold;
  563. void *hdr;
  564. int err;
  565. err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
  566. tc_index, pool_type,
  567. &pool_index, &threshold);
  568. if (err)
  569. return err;
  570. hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
  571. if (!hdr)
  572. return -EMSGSIZE;
  573. if (devlink_nl_put_handle(msg, devlink))
  574. goto nla_put_failure;
  575. if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
  576. goto nla_put_failure;
  577. if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
  578. goto nla_put_failure;
  579. if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
  580. goto nla_put_failure;
  581. if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
  582. goto nla_put_failure;
  583. if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
  584. goto nla_put_failure;
  585. if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
  586. goto nla_put_failure;
  587. if (ops->sb_occ_tc_port_bind_get) {
  588. u32 cur;
  589. u32 max;
  590. err = ops->sb_occ_tc_port_bind_get(devlink_port,
  591. devlink_sb->index,
  592. tc_index, pool_type,
  593. &cur, &max);
  594. if (err && err != -EOPNOTSUPP)
  595. return err;
  596. if (!err) {
  597. if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
  598. goto nla_put_failure;
  599. if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
  600. goto nla_put_failure;
  601. }
  602. }
  603. genlmsg_end(msg, hdr);
  604. return 0;
  605. nla_put_failure:
  606. genlmsg_cancel(msg, hdr);
  607. return -EMSGSIZE;
  608. }
  609. int devlink_nl_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
  610. struct genl_info *info)
  611. {
  612. struct devlink_port *devlink_port = info->user_ptr[1];
  613. struct devlink *devlink = devlink_port->devlink;
  614. struct devlink_sb *devlink_sb;
  615. struct sk_buff *msg;
  616. enum devlink_sb_pool_type pool_type;
  617. u16 tc_index;
  618. int err;
  619. devlink_sb = devlink_sb_get_from_info(devlink, info);
  620. if (IS_ERR(devlink_sb))
  621. return PTR_ERR(devlink_sb);
  622. err = devlink_sb_pool_type_get_from_info(info, &pool_type);
  623. if (err)
  624. return err;
  625. err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
  626. pool_type, &tc_index);
  627. if (err)
  628. return err;
  629. if (!devlink->ops->sb_tc_pool_bind_get)
  630. return -EOPNOTSUPP;
  631. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  632. if (!msg)
  633. return -ENOMEM;
  634. err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
  635. devlink_sb, tc_index, pool_type,
  636. DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
  637. info->snd_portid,
  638. info->snd_seq, 0);
  639. if (err) {
  640. nlmsg_free(msg);
  641. return err;
  642. }
  643. return genlmsg_reply(msg, info);
  644. }
  645. static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
  646. int start, int *p_idx,
  647. struct devlink *devlink,
  648. struct devlink_sb *devlink_sb,
  649. u32 portid, u32 seq, int flags)
  650. {
  651. struct devlink_port *devlink_port;
  652. unsigned long port_index;
  653. u16 tc_index;
  654. int err;
  655. xa_for_each(&devlink->ports, port_index, devlink_port) {
  656. for (tc_index = 0;
  657. tc_index < devlink_sb->ingress_tc_count; tc_index++) {
  658. if (*p_idx < start) {
  659. (*p_idx)++;
  660. continue;
  661. }
  662. err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
  663. devlink_port,
  664. devlink_sb,
  665. tc_index,
  666. DEVLINK_SB_POOL_TYPE_INGRESS,
  667. DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
  668. portid, seq,
  669. flags);
  670. if (err)
  671. return err;
  672. (*p_idx)++;
  673. }
  674. for (tc_index = 0;
  675. tc_index < devlink_sb->egress_tc_count; tc_index++) {
  676. if (*p_idx < start) {
  677. (*p_idx)++;
  678. continue;
  679. }
  680. err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
  681. devlink_port,
  682. devlink_sb,
  683. tc_index,
  684. DEVLINK_SB_POOL_TYPE_EGRESS,
  685. DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
  686. portid, seq,
  687. flags);
  688. if (err)
  689. return err;
  690. (*p_idx)++;
  691. }
  692. }
  693. return 0;
  694. }
  695. static int devlink_nl_sb_tc_pool_bind_get_dump_one(struct sk_buff *msg,
  696. struct devlink *devlink,
  697. struct netlink_callback *cb,
  698. int flags)
  699. {
  700. struct devlink_nl_dump_state *state = devlink_dump_state(cb);
  701. struct devlink_sb *devlink_sb;
  702. int idx = 0;
  703. int err = 0;
  704. if (!devlink->ops->sb_tc_pool_bind_get)
  705. return 0;
  706. list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
  707. err = __sb_tc_pool_bind_get_dumpit(msg, state->idx, &idx,
  708. devlink, devlink_sb,
  709. NETLINK_CB(cb->skb).portid,
  710. cb->nlh->nlmsg_seq, flags);
  711. if (err == -EOPNOTSUPP) {
  712. err = 0;
  713. } else if (err) {
  714. state->idx = idx;
  715. break;
  716. }
  717. }
  718. return err;
  719. }
  720. int devlink_nl_sb_tc_pool_bind_get_dumpit(struct sk_buff *skb,
  721. struct netlink_callback *cb)
  722. {
  723. return devlink_nl_dumpit(skb, cb,
  724. devlink_nl_sb_tc_pool_bind_get_dump_one);
  725. }
  726. static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
  727. unsigned int sb_index, u16 tc_index,
  728. enum devlink_sb_pool_type pool_type,
  729. u16 pool_index, u32 threshold,
  730. struct netlink_ext_ack *extack)
  731. {
  732. const struct devlink_ops *ops = devlink_port->devlink->ops;
  733. if (ops->sb_tc_pool_bind_set)
  734. return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
  735. tc_index, pool_type,
  736. pool_index, threshold, extack);
  737. return -EOPNOTSUPP;
  738. }
  739. int devlink_nl_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
  740. struct genl_info *info)
  741. {
  742. struct devlink_port *devlink_port = info->user_ptr[1];
  743. struct devlink *devlink = info->user_ptr[0];
  744. enum devlink_sb_pool_type pool_type;
  745. struct devlink_sb *devlink_sb;
  746. u16 tc_index;
  747. u16 pool_index;
  748. u32 threshold;
  749. int err;
  750. devlink_sb = devlink_sb_get_from_info(devlink, info);
  751. if (IS_ERR(devlink_sb))
  752. return PTR_ERR(devlink_sb);
  753. err = devlink_sb_pool_type_get_from_info(info, &pool_type);
  754. if (err)
  755. return err;
  756. err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
  757. pool_type, &tc_index);
  758. if (err)
  759. return err;
  760. err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
  761. &pool_index);
  762. if (err)
  763. return err;
  764. if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_THRESHOLD))
  765. return -EINVAL;
  766. threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
  767. return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
  768. tc_index, pool_type,
  769. pool_index, threshold, info->extack);
  770. }
  771. int devlink_nl_sb_occ_snapshot_doit(struct sk_buff *skb, struct genl_info *info)
  772. {
  773. struct devlink *devlink = info->user_ptr[0];
  774. const struct devlink_ops *ops = devlink->ops;
  775. struct devlink_sb *devlink_sb;
  776. devlink_sb = devlink_sb_get_from_info(devlink, info);
  777. if (IS_ERR(devlink_sb))
  778. return PTR_ERR(devlink_sb);
  779. if (ops->sb_occ_snapshot)
  780. return ops->sb_occ_snapshot(devlink, devlink_sb->index);
  781. return -EOPNOTSUPP;
  782. }
  783. int devlink_nl_sb_occ_max_clear_doit(struct sk_buff *skb,
  784. struct genl_info *info)
  785. {
  786. struct devlink *devlink = info->user_ptr[0];
  787. const struct devlink_ops *ops = devlink->ops;
  788. struct devlink_sb *devlink_sb;
  789. devlink_sb = devlink_sb_get_from_info(devlink, info);
  790. if (IS_ERR(devlink_sb))
  791. return PTR_ERR(devlink_sb);
  792. if (ops->sb_occ_max_clear)
  793. return ops->sb_occ_max_clear(devlink, devlink_sb->index);
  794. return -EOPNOTSUPP;
  795. }
  796. int devl_sb_register(struct devlink *devlink, unsigned int sb_index,
  797. u32 size, u16 ingress_pools_count,
  798. u16 egress_pools_count, u16 ingress_tc_count,
  799. u16 egress_tc_count)
  800. {
  801. struct devlink_sb *devlink_sb;
  802. lockdep_assert_held(&devlink->lock);
  803. if (devlink_sb_index_exists(devlink, sb_index))
  804. return -EEXIST;
  805. devlink_sb = kzalloc_obj(*devlink_sb);
  806. if (!devlink_sb)
  807. return -ENOMEM;
  808. devlink_sb->index = sb_index;
  809. devlink_sb->size = size;
  810. devlink_sb->ingress_pools_count = ingress_pools_count;
  811. devlink_sb->egress_pools_count = egress_pools_count;
  812. devlink_sb->ingress_tc_count = ingress_tc_count;
  813. devlink_sb->egress_tc_count = egress_tc_count;
  814. list_add_tail(&devlink_sb->list, &devlink->sb_list);
  815. return 0;
  816. }
  817. EXPORT_SYMBOL_GPL(devl_sb_register);
  818. int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
  819. u32 size, u16 ingress_pools_count,
  820. u16 egress_pools_count, u16 ingress_tc_count,
  821. u16 egress_tc_count)
  822. {
  823. int err;
  824. devl_lock(devlink);
  825. err = devl_sb_register(devlink, sb_index, size, ingress_pools_count,
  826. egress_pools_count, ingress_tc_count,
  827. egress_tc_count);
  828. devl_unlock(devlink);
  829. return err;
  830. }
  831. EXPORT_SYMBOL_GPL(devlink_sb_register);
  832. void devl_sb_unregister(struct devlink *devlink, unsigned int sb_index)
  833. {
  834. struct devlink_sb *devlink_sb;
  835. lockdep_assert_held(&devlink->lock);
  836. devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
  837. WARN_ON(!devlink_sb);
  838. list_del(&devlink_sb->list);
  839. kfree(devlink_sb);
  840. }
  841. EXPORT_SYMBOL_GPL(devl_sb_unregister);
  842. void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
  843. {
  844. devl_lock(devlink);
  845. devl_sb_unregister(devlink, sb_index);
  846. devl_unlock(devlink);
  847. }
  848. EXPORT_SYMBOL_GPL(devlink_sb_unregister);