ocelot_flower.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /* Microsemi Ocelot Switch driver
  3. * Copyright (c) 2019 Microsemi Corporation
  4. */
  5. #include <net/pkt_cls.h>
  6. #include <net/tc_act/tc_gact.h>
  7. #include "ocelot_ace.h"
  8. struct ocelot_port_block {
  9. struct ocelot_acl_block *block;
  10. struct ocelot_port *port;
  11. };
  12. static int ocelot_flower_parse_action(struct flow_cls_offload *f,
  13. struct ocelot_ace_rule *rule)
  14. {
  15. const struct flow_action_entry *a;
  16. int i;
  17. if (f->rule->action.num_entries != 1)
  18. return -EOPNOTSUPP;
  19. flow_action_for_each(i, a, &f->rule->action) {
  20. switch (a->id) {
  21. case FLOW_ACTION_DROP:
  22. rule->action = OCELOT_ACL_ACTION_DROP;
  23. break;
  24. case FLOW_ACTION_TRAP:
  25. rule->action = OCELOT_ACL_ACTION_TRAP;
  26. break;
  27. default:
  28. return -EOPNOTSUPP;
  29. }
  30. }
  31. return 0;
  32. }
  33. static int ocelot_flower_parse(struct flow_cls_offload *f,
  34. struct ocelot_ace_rule *ocelot_rule)
  35. {
  36. struct flow_rule *rule = flow_cls_offload_flow_rule(f);
  37. struct flow_dissector *dissector = rule->match.dissector;
  38. if (dissector->used_keys &
  39. ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
  40. BIT(FLOW_DISSECTOR_KEY_BASIC) |
  41. BIT(FLOW_DISSECTOR_KEY_PORTS) |
  42. BIT(FLOW_DISSECTOR_KEY_VLAN) |
  43. BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
  44. BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
  45. BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
  46. return -EOPNOTSUPP;
  47. }
  48. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
  49. struct flow_match_control match;
  50. flow_rule_match_control(rule, &match);
  51. }
  52. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
  53. struct flow_match_eth_addrs match;
  54. u16 proto = ntohs(f->common.protocol);
  55. /* The hw support mac matches only for MAC_ETYPE key,
  56. * therefore if other matches(port, tcp flags, etc) are added
  57. * then just bail out
  58. */
  59. if ((dissector->used_keys &
  60. (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
  61. BIT(FLOW_DISSECTOR_KEY_BASIC) |
  62. BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
  63. (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
  64. BIT(FLOW_DISSECTOR_KEY_BASIC) |
  65. BIT(FLOW_DISSECTOR_KEY_CONTROL)))
  66. return -EOPNOTSUPP;
  67. if (proto == ETH_P_IP ||
  68. proto == ETH_P_IPV6 ||
  69. proto == ETH_P_ARP)
  70. return -EOPNOTSUPP;
  71. flow_rule_match_eth_addrs(rule, &match);
  72. ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
  73. ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
  74. match.key->dst);
  75. ether_addr_copy(ocelot_rule->frame.etype.smac.value,
  76. match.key->src);
  77. ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
  78. match.mask->dst);
  79. ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
  80. match.mask->src);
  81. goto finished_key_parsing;
  82. }
  83. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
  84. struct flow_match_basic match;
  85. flow_rule_match_basic(rule, &match);
  86. if (ntohs(match.key->n_proto) == ETH_P_IP) {
  87. ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
  88. ocelot_rule->frame.ipv4.proto.value[0] =
  89. match.key->ip_proto;
  90. ocelot_rule->frame.ipv4.proto.mask[0] =
  91. match.mask->ip_proto;
  92. }
  93. if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
  94. ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
  95. ocelot_rule->frame.ipv6.proto.value[0] =
  96. match.key->ip_proto;
  97. ocelot_rule->frame.ipv6.proto.mask[0] =
  98. match.mask->ip_proto;
  99. }
  100. }
  101. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
  102. ntohs(f->common.protocol) == ETH_P_IP) {
  103. struct flow_match_ipv4_addrs match;
  104. u8 *tmp;
  105. flow_rule_match_ipv4_addrs(rule, &match);
  106. tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
  107. memcpy(tmp, &match.key->src, 4);
  108. tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
  109. memcpy(tmp, &match.mask->src, 4);
  110. tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
  111. memcpy(tmp, &match.key->dst, 4);
  112. tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
  113. memcpy(tmp, &match.mask->dst, 4);
  114. }
  115. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
  116. ntohs(f->common.protocol) == ETH_P_IPV6) {
  117. return -EOPNOTSUPP;
  118. }
  119. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
  120. struct flow_match_ports match;
  121. flow_rule_match_ports(rule, &match);
  122. ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
  123. ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
  124. ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
  125. ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
  126. }
  127. if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
  128. struct flow_match_vlan match;
  129. flow_rule_match_vlan(rule, &match);
  130. ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
  131. ocelot_rule->vlan.vid.value = match.key->vlan_id;
  132. ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
  133. ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
  134. ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
  135. }
  136. finished_key_parsing:
  137. ocelot_rule->prio = f->common.prio;
  138. ocelot_rule->id = f->cookie;
  139. return ocelot_flower_parse_action(f, ocelot_rule);
  140. }
  141. static
  142. struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
  143. struct ocelot_port_block *block)
  144. {
  145. struct ocelot_ace_rule *rule;
  146. rule = kzalloc(sizeof(*rule), GFP_KERNEL);
  147. if (!rule)
  148. return NULL;
  149. rule->port = block->port;
  150. rule->chip_port = block->port->chip_port;
  151. return rule;
  152. }
  153. static int ocelot_flower_replace(struct flow_cls_offload *f,
  154. struct ocelot_port_block *port_block)
  155. {
  156. struct ocelot_ace_rule *rule;
  157. int ret;
  158. rule = ocelot_ace_rule_create(f, port_block);
  159. if (!rule)
  160. return -ENOMEM;
  161. ret = ocelot_flower_parse(f, rule);
  162. if (ret) {
  163. kfree(rule);
  164. return ret;
  165. }
  166. ret = ocelot_ace_rule_offload_add(rule);
  167. if (ret)
  168. return ret;
  169. port_block->port->tc.offload_cnt++;
  170. return 0;
  171. }
  172. static int ocelot_flower_destroy(struct flow_cls_offload *f,
  173. struct ocelot_port_block *port_block)
  174. {
  175. struct ocelot_ace_rule rule;
  176. int ret;
  177. rule.prio = f->common.prio;
  178. rule.port = port_block->port;
  179. rule.id = f->cookie;
  180. ret = ocelot_ace_rule_offload_del(&rule);
  181. if (ret)
  182. return ret;
  183. port_block->port->tc.offload_cnt--;
  184. return 0;
  185. }
  186. static int ocelot_flower_stats_update(struct flow_cls_offload *f,
  187. struct ocelot_port_block *port_block)
  188. {
  189. struct ocelot_ace_rule rule;
  190. int ret;
  191. rule.prio = f->common.prio;
  192. rule.port = port_block->port;
  193. rule.id = f->cookie;
  194. ret = ocelot_ace_rule_stats_update(&rule);
  195. if (ret)
  196. return ret;
  197. flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
  198. return 0;
  199. }
  200. static int ocelot_setup_tc_cls_flower(struct flow_cls_offload *f,
  201. struct ocelot_port_block *port_block)
  202. {
  203. switch (f->command) {
  204. case FLOW_CLS_REPLACE:
  205. return ocelot_flower_replace(f, port_block);
  206. case FLOW_CLS_DESTROY:
  207. return ocelot_flower_destroy(f, port_block);
  208. case FLOW_CLS_STATS:
  209. return ocelot_flower_stats_update(f, port_block);
  210. default:
  211. return -EOPNOTSUPP;
  212. }
  213. }
  214. static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
  215. void *type_data, void *cb_priv)
  216. {
  217. struct ocelot_port_block *port_block = cb_priv;
  218. if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data))
  219. return -EOPNOTSUPP;
  220. switch (type) {
  221. case TC_SETUP_CLSFLOWER:
  222. return ocelot_setup_tc_cls_flower(type_data, cb_priv);
  223. case TC_SETUP_CLSMATCHALL:
  224. return 0;
  225. default:
  226. return -EOPNOTSUPP;
  227. }
  228. }
  229. static struct ocelot_port_block*
  230. ocelot_port_block_create(struct ocelot_port *port)
  231. {
  232. struct ocelot_port_block *port_block;
  233. port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
  234. if (!port_block)
  235. return NULL;
  236. port_block->port = port;
  237. return port_block;
  238. }
  239. static void ocelot_port_block_destroy(struct ocelot_port_block *block)
  240. {
  241. kfree(block);
  242. }
  243. static void ocelot_tc_block_unbind(void *cb_priv)
  244. {
  245. struct ocelot_port_block *port_block = cb_priv;
  246. ocelot_port_block_destroy(port_block);
  247. }
  248. int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
  249. struct flow_block_offload *f)
  250. {
  251. struct ocelot_port_block *port_block;
  252. struct flow_block_cb *block_cb;
  253. int ret;
  254. if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
  255. return -EOPNOTSUPP;
  256. block_cb = flow_block_cb_lookup(f->block,
  257. ocelot_setup_tc_block_cb_flower, port);
  258. if (!block_cb) {
  259. port_block = ocelot_port_block_create(port);
  260. if (!port_block)
  261. return -ENOMEM;
  262. block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
  263. port, port_block,
  264. ocelot_tc_block_unbind);
  265. if (IS_ERR(block_cb)) {
  266. ret = PTR_ERR(block_cb);
  267. goto err_cb_register;
  268. }
  269. flow_block_cb_add(block_cb, f);
  270. list_add_tail(&block_cb->driver_list, f->driver_block_list);
  271. } else {
  272. port_block = flow_block_cb_priv(block_cb);
  273. }
  274. flow_block_cb_incref(block_cb);
  275. return 0;
  276. err_cb_register:
  277. ocelot_port_block_destroy(port_block);
  278. return ret;
  279. }
  280. void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
  281. struct flow_block_offload *f)
  282. {
  283. struct flow_block_cb *block_cb;
  284. block_cb = flow_block_cb_lookup(f->block,
  285. ocelot_setup_tc_block_cb_flower, port);
  286. if (!block_cb)
  287. return;
  288. if (!flow_block_cb_decref(block_cb)) {
  289. flow_block_cb_remove(block_cb, f);
  290. list_del(&block_cb->driver_list);
  291. }
  292. }