tc_bindings.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /****************************************************************************
  3. * Driver for Solarflare network controllers and boards
  4. * Copyright 2022 Xilinx Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published
  8. * by the Free Software Foundation, incorporated herein by reference.
  9. */
  10. #include "tc_bindings.h"
  11. #include "tc.h"
  12. struct efx_tc_block_binding {
  13. struct list_head list;
  14. struct efx_nic *efx;
  15. struct efx_rep *efv;
  16. struct net_device *otherdev; /* may actually be us */
  17. struct flow_block *block;
  18. };
  19. static struct efx_tc_block_binding *efx_tc_find_binding(struct efx_nic *efx,
  20. struct net_device *otherdev)
  21. {
  22. struct efx_tc_block_binding *binding;
  23. ASSERT_RTNL();
  24. list_for_each_entry(binding, &efx->tc->block_list, list)
  25. if (binding->otherdev == otherdev)
  26. return binding;
  27. return NULL;
  28. }
  29. static int efx_tc_block_cb(enum tc_setup_type type, void *type_data,
  30. void *cb_priv)
  31. {
  32. struct efx_tc_block_binding *binding = cb_priv;
  33. struct flow_cls_offload *tcf = type_data;
  34. switch (type) {
  35. case TC_SETUP_CLSFLOWER:
  36. return efx_tc_flower(binding->efx, binding->otherdev,
  37. tcf, binding->efv);
  38. default:
  39. return -EOPNOTSUPP;
  40. }
  41. }
  42. void efx_tc_block_unbind(void *cb_priv)
  43. {
  44. struct efx_tc_block_binding *binding = cb_priv;
  45. list_del(&binding->list);
  46. kfree(binding);
  47. }
  48. static struct efx_tc_block_binding *efx_tc_create_binding(
  49. struct efx_nic *efx, struct efx_rep *efv,
  50. struct net_device *otherdev, struct flow_block *block)
  51. {
  52. struct efx_tc_block_binding *binding = kmalloc(sizeof(*binding), GFP_KERNEL);
  53. if (!binding)
  54. return ERR_PTR(-ENOMEM);
  55. binding->efx = efx;
  56. binding->efv = efv;
  57. binding->otherdev = otherdev;
  58. binding->block = block;
  59. list_add(&binding->list, &efx->tc->block_list);
  60. return binding;
  61. }
  62. int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,
  63. struct flow_block_offload *tcb, struct efx_rep *efv)
  64. {
  65. struct efx_tc_block_binding *binding;
  66. struct flow_block_cb *block_cb;
  67. int rc;
  68. if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
  69. return -EOPNOTSUPP;
  70. if (WARN_ON(!efx->tc))
  71. return -ENETDOWN;
  72. switch (tcb->command) {
  73. case FLOW_BLOCK_BIND:
  74. binding = efx_tc_create_binding(efx, efv, net_dev, tcb->block);
  75. if (IS_ERR(binding))
  76. return PTR_ERR(binding);
  77. block_cb = flow_block_cb_alloc(efx_tc_block_cb, binding,
  78. binding, efx_tc_block_unbind);
  79. rc = PTR_ERR_OR_ZERO(block_cb);
  80. netif_dbg(efx, drv, efx->net_dev,
  81. "bind %sdirect block for device %s, rc %d\n",
  82. net_dev == efx->net_dev ? "" :
  83. efv ? "semi" : "in",
  84. net_dev ? net_dev->name : NULL, rc);
  85. if (rc) {
  86. list_del(&binding->list);
  87. kfree(binding);
  88. } else {
  89. flow_block_cb_add(block_cb, tcb);
  90. }
  91. return rc;
  92. case FLOW_BLOCK_UNBIND:
  93. binding = efx_tc_find_binding(efx, net_dev);
  94. if (binding) {
  95. block_cb = flow_block_cb_lookup(tcb->block,
  96. efx_tc_block_cb,
  97. binding);
  98. if (block_cb) {
  99. flow_block_cb_remove(block_cb, tcb);
  100. netif_dbg(efx, drv, efx->net_dev,
  101. "unbound %sdirect block for device %s\n",
  102. net_dev == efx->net_dev ? "" :
  103. binding->efv ? "semi" : "in",
  104. net_dev ? net_dev->name : NULL);
  105. return 0;
  106. }
  107. }
  108. /* If we're in driver teardown, then we expect to have
  109. * already unbound all our blocks (we did it early while
  110. * we still had MCDI to remove the filters), so getting
  111. * unbind callbacks now isn't a problem.
  112. */
  113. netif_cond_dbg(efx, drv, efx->net_dev,
  114. !efx->tc->up, warn,
  115. "%sdirect block unbind for device %s, was never bound\n",
  116. net_dev == efx->net_dev ? "" : "in",
  117. net_dev ? net_dev->name : NULL);
  118. return -ENOENT;
  119. default:
  120. return -EOPNOTSUPP;
  121. }
  122. }
  123. int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch,
  124. void *cb_priv, enum tc_setup_type type,
  125. void *type_data, void *data,
  126. void (*cleanup)(struct flow_block_cb *block_cb))
  127. {
  128. struct flow_block_offload *tcb = type_data;
  129. struct efx_tc_block_binding *binding;
  130. struct flow_block_cb *block_cb;
  131. struct efx_nic *efx = cb_priv;
  132. bool is_ovs_int_port;
  133. int rc;
  134. if (!net_dev)
  135. return -EOPNOTSUPP;
  136. if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
  137. tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
  138. return -EOPNOTSUPP;
  139. is_ovs_int_port = netif_is_ovs_master(net_dev);
  140. if (tcb->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
  141. !is_ovs_int_port)
  142. return -EOPNOTSUPP;
  143. if (is_ovs_int_port)
  144. return -EOPNOTSUPP;
  145. switch (type) {
  146. case TC_SETUP_BLOCK:
  147. switch (tcb->command) {
  148. case FLOW_BLOCK_BIND:
  149. binding = efx_tc_create_binding(efx, NULL, net_dev, tcb->block);
  150. if (IS_ERR(binding))
  151. return PTR_ERR(binding);
  152. block_cb = flow_indr_block_cb_alloc(efx_tc_block_cb, binding,
  153. binding, efx_tc_block_unbind,
  154. tcb, net_dev, sch, data, binding,
  155. cleanup);
  156. rc = PTR_ERR_OR_ZERO(block_cb);
  157. netif_dbg(efx, drv, efx->net_dev,
  158. "bind indr block for device %s, rc %d\n",
  159. net_dev ? net_dev->name : NULL, rc);
  160. if (rc) {
  161. list_del(&binding->list);
  162. kfree(binding);
  163. } else {
  164. flow_block_cb_add(block_cb, tcb);
  165. }
  166. return rc;
  167. case FLOW_BLOCK_UNBIND:
  168. binding = efx_tc_find_binding(efx, net_dev);
  169. if (!binding)
  170. return -ENOENT;
  171. block_cb = flow_block_cb_lookup(tcb->block,
  172. efx_tc_block_cb,
  173. binding);
  174. if (!block_cb)
  175. return -ENOENT;
  176. flow_indr_block_cb_remove(block_cb, tcb);
  177. netif_dbg(efx, drv, efx->net_dev,
  178. "unbind indr block for device %s\n",
  179. net_dev ? net_dev->name : NULL);
  180. return 0;
  181. default:
  182. return -EOPNOTSUPP;
  183. }
  184. default:
  185. return -EOPNOTSUPP;
  186. }
  187. }
  188. /* .ndo_setup_tc implementation
  189. * Entry point for flower block and filter management.
  190. */
  191. int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type,
  192. void *type_data)
  193. {
  194. struct efx_nic *efx = efx_netdev_priv(net_dev);
  195. if (efx->type->is_vf)
  196. return -EOPNOTSUPP;
  197. if (!efx->tc)
  198. return -EOPNOTSUPP;
  199. if (type == TC_SETUP_CLSFLOWER)
  200. return efx_tc_flower(efx, net_dev, type_data, NULL);
  201. if (type == TC_SETUP_BLOCK)
  202. return efx_tc_setup_block(net_dev, efx, type_data, NULL);
  203. return -EOPNOTSUPP;
  204. }