ksz9477_tc_flower.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
  3. #include "ksz9477.h"
  4. #include "ksz9477_reg.h"
  5. #include "ksz_common.h"
  6. #define ETHER_TYPE_FULL_MASK cpu_to_be16(~0)
  7. #define KSZ9477_MAX_TC 7
  8. /**
  9. * ksz9477_flower_parse_key_l2 - Parse Layer 2 key from flow rule and configure
  10. * ACL entries accordingly.
  11. * @dev: Pointer to the ksz_device.
  12. * @port: Port number.
  13. * @extack: Pointer to the netlink_ext_ack.
  14. * @rule: Pointer to the flow_rule.
  15. * @cookie: The cookie to associate with the entry.
  16. * @prio: The priority of the entry.
  17. *
  18. * This function parses the Layer 2 key from the flow rule and configures
  19. * the corresponding ACL entries. It checks for unsupported offloads and
  20. * available entries before proceeding with the configuration.
  21. *
  22. * Returns: 0 on success or a negative error code on failure.
  23. */
  24. static int ksz9477_flower_parse_key_l2(struct ksz_device *dev, int port,
  25. struct netlink_ext_ack *extack,
  26. struct flow_rule *rule,
  27. unsigned long cookie, u32 prio)
  28. {
  29. struct ksz9477_acl_priv *acl = dev->ports[port].acl_priv;
  30. struct flow_match_eth_addrs ematch;
  31. struct ksz9477_acl_entries *acles;
  32. int required_entries;
  33. u8 *src_mac = NULL;
  34. u8 *dst_mac = NULL;
  35. u16 ethtype = 0;
  36. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
  37. struct flow_match_basic match;
  38. flow_rule_match_basic(rule, &match);
  39. if (match.key->n_proto) {
  40. if (match.mask->n_proto != ETHER_TYPE_FULL_MASK) {
  41. NL_SET_ERR_MSG_MOD(extack,
  42. "ethernet type mask must be a full mask");
  43. return -EINVAL;
  44. }
  45. ethtype = be16_to_cpu(match.key->n_proto);
  46. }
  47. }
  48. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
  49. flow_rule_match_eth_addrs(rule, &ematch);
  50. if (!is_zero_ether_addr(ematch.key->src)) {
  51. if (!is_broadcast_ether_addr(ematch.mask->src))
  52. goto not_full_mask_err;
  53. src_mac = ematch.key->src;
  54. }
  55. if (!is_zero_ether_addr(ematch.key->dst)) {
  56. if (!is_broadcast_ether_addr(ematch.mask->dst))
  57. goto not_full_mask_err;
  58. dst_mac = ematch.key->dst;
  59. }
  60. }
  61. acles = &acl->acles;
  62. /* ACL supports only one MAC per entry */
  63. required_entries = src_mac && dst_mac ? 2 : 1;
  64. /* Check if there are enough available entries */
  65. if (acles->entries_count + required_entries > KSZ9477_ACL_MAX_ENTRIES) {
  66. NL_SET_ERR_MSG_MOD(extack, "ACL entry limit reached");
  67. return -EOPNOTSUPP;
  68. }
  69. ksz9477_acl_match_process_l2(dev, port, ethtype, src_mac, dst_mac,
  70. cookie, prio);
  71. return 0;
  72. not_full_mask_err:
  73. NL_SET_ERR_MSG_MOD(extack, "MAC address mask must be a full mask");
  74. return -EOPNOTSUPP;
  75. }
  76. /**
  77. * ksz9477_flower_parse_key - Parse flow rule keys for a specified port on a
  78. * ksz_device.
  79. * @dev: The ksz_device instance.
  80. * @port: The port number to parse the flow rule keys for.
  81. * @extack: The netlink extended ACK for reporting errors.
  82. * @rule: The flow_rule to parse.
  83. * @cookie: The cookie to associate with the entry.
  84. * @prio: The priority of the entry.
  85. *
  86. * This function checks if the used keys in the flow rule are supported by
  87. * the device and parses the L2 keys if they match. If unsupported keys are
  88. * used, an error message is set in the extended ACK.
  89. *
  90. * Returns: 0 on success or a negative error code on failure.
  91. */
  92. static int ksz9477_flower_parse_key(struct ksz_device *dev, int port,
  93. struct netlink_ext_ack *extack,
  94. struct flow_rule *rule,
  95. unsigned long cookie, u32 prio)
  96. {
  97. struct flow_dissector *dissector = rule->match.dissector;
  98. int ret;
  99. if (dissector->used_keys &
  100. ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
  101. BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
  102. BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL))) {
  103. NL_SET_ERR_MSG_MOD(extack,
  104. "Unsupported keys used");
  105. return -EOPNOTSUPP;
  106. }
  107. if (flow_rule_match_has_control_flags(rule, extack))
  108. return -EOPNOTSUPP;
  109. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC) ||
  110. flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
  111. ret = ksz9477_flower_parse_key_l2(dev, port, extack, rule,
  112. cookie, prio);
  113. if (ret)
  114. return ret;
  115. }
  116. return 0;
  117. }
  118. /**
  119. * ksz9477_flower_parse_action - Parse flow rule actions for a specified port
  120. * on a ksz_device.
  121. * @dev: The ksz_device instance.
  122. * @port: The port number to parse the flow rule actions for.
  123. * @extack: The netlink extended ACK for reporting errors.
  124. * @cls: The flow_cls_offload instance containing the flow rule.
  125. * @entry_idx: The index of the ACL entry to store the action.
  126. *
  127. * This function checks if the actions in the flow rule are supported by
  128. * the device. Currently, only actions that change priorities are supported.
  129. * If unsupported actions are encountered, an error message is set in the
  130. * extended ACK.
  131. *
  132. * Returns: 0 on success or a negative error code on failure.
  133. */
  134. static int ksz9477_flower_parse_action(struct ksz_device *dev, int port,
  135. struct netlink_ext_ack *extack,
  136. struct flow_cls_offload *cls,
  137. int entry_idx)
  138. {
  139. struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
  140. struct ksz9477_acl_priv *acl = dev->ports[port].acl_priv;
  141. const struct flow_action_entry *act;
  142. struct ksz9477_acl_entry *entry;
  143. bool prio_force = false;
  144. u8 prio_val = 0;
  145. int i;
  146. if (TC_H_MIN(cls->classid)) {
  147. NL_SET_ERR_MSG_MOD(extack, "hw_tc is not supported. Use: action skbedit prio");
  148. return -EOPNOTSUPP;
  149. }
  150. flow_action_for_each(i, act, &rule->action) {
  151. switch (act->id) {
  152. case FLOW_ACTION_PRIORITY:
  153. if (act->priority > KSZ9477_MAX_TC) {
  154. NL_SET_ERR_MSG_MOD(extack, "Priority value is too high");
  155. return -EOPNOTSUPP;
  156. }
  157. prio_force = true;
  158. prio_val = act->priority;
  159. break;
  160. default:
  161. NL_SET_ERR_MSG_MOD(extack, "action not supported");
  162. return -EOPNOTSUPP;
  163. }
  164. }
  165. /* pick entry to store action */
  166. entry = &acl->acles.entries[entry_idx];
  167. ksz9477_acl_action_rule_cfg(entry->entry, prio_force, prio_val);
  168. ksz9477_acl_processing_rule_set_action(entry->entry, entry_idx);
  169. return 0;
  170. }
  171. /**
  172. * ksz9477_cls_flower_add - Add a flow classification rule for a specified port
  173. * on a ksz_device.
  174. * @ds: The DSA switch instance.
  175. * @port: The port number to add the flow classification rule to.
  176. * @cls: The flow_cls_offload instance containing the flow rule.
  177. * @ingress: A flag indicating if the rule is applied on the ingress path.
  178. *
  179. * This function adds a flow classification rule for a specified port on a
  180. * ksz_device. It checks if the ACL offloading is supported and parses the flow
  181. * keys and actions. If the ACL is not supported, it returns an error. If there
  182. * are unprocessed entries, it parses the action for the rule.
  183. *
  184. * Returns: 0 on success or a negative error code on failure.
  185. */
  186. int ksz9477_cls_flower_add(struct dsa_switch *ds, int port,
  187. struct flow_cls_offload *cls, bool ingress)
  188. {
  189. struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
  190. struct netlink_ext_ack *extack = cls->common.extack;
  191. struct ksz_device *dev = ds->priv;
  192. struct ksz9477_acl_priv *acl;
  193. int action_entry_idx;
  194. int ret;
  195. acl = dev->ports[port].acl_priv;
  196. if (!acl) {
  197. NL_SET_ERR_MSG_MOD(extack, "ACL offloading is not supported");
  198. return -EOPNOTSUPP;
  199. }
  200. /* A complex rule set can take multiple entries. Use first entry
  201. * to store the action.
  202. */
  203. action_entry_idx = acl->acles.entries_count;
  204. ret = ksz9477_flower_parse_key(dev, port, extack, rule, cls->cookie,
  205. cls->common.prio);
  206. if (ret)
  207. return ret;
  208. ret = ksz9477_flower_parse_action(dev, port, extack, cls,
  209. action_entry_idx);
  210. if (ret)
  211. return ret;
  212. ret = ksz9477_sort_acl_entries(dev, port);
  213. if (ret)
  214. return ret;
  215. return ksz9477_acl_write_list(dev, port);
  216. }
  217. /**
  218. * ksz9477_cls_flower_del - Remove a flow classification rule for a specified
  219. * port on a ksz_device.
  220. * @ds: The DSA switch instance.
  221. * @port: The port number to remove the flow classification rule from.
  222. * @cls: The flow_cls_offload instance containing the flow rule.
  223. * @ingress: A flag indicating if the rule is applied on the ingress path.
  224. *
  225. * This function removes a flow classification rule for a specified port on a
  226. * ksz_device. It checks if the ACL is initialized, and if not, returns an
  227. * error. If the ACL is initialized, it removes entries with the specified
  228. * cookie and rewrites the ACL list.
  229. *
  230. * Returns: 0 on success or a negative error code on failure.
  231. */
  232. int ksz9477_cls_flower_del(struct dsa_switch *ds, int port,
  233. struct flow_cls_offload *cls, bool ingress)
  234. {
  235. unsigned long cookie = cls->cookie;
  236. struct ksz_device *dev = ds->priv;
  237. struct ksz9477_acl_priv *acl;
  238. acl = dev->ports[port].acl_priv;
  239. if (!acl)
  240. return -EOPNOTSUPP;
  241. ksz9477_acl_remove_entries(dev, port, &acl->acles, cookie);
  242. return ksz9477_acl_write_list(dev, port);
  243. }