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