tc_bindings.c 6.4 KB

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