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 static int ocelot_flower_parse_action(struct flow_cls_offload *f, 12 struct ocelot_ace_rule *ace) 13 { 14 const struct flow_action_entry *a; 15 s64 burst; 16 u64 rate; 17 int i; 18 19 if (!flow_offload_has_one_action(&f->rule->action)) 20 return -EOPNOTSUPP; 21 22 if (!flow_action_basic_hw_stats_check(&f->rule->action, 23 f->common.extack)) 24 return -EOPNOTSUPP; 25 26 flow_action_for_each(i, a, &f->rule->action) { 27 switch (a->id) { 28 case FLOW_ACTION_DROP: 29 ace->action = OCELOT_ACL_ACTION_DROP; 30 break; 31 case FLOW_ACTION_TRAP: 32 ace->action = OCELOT_ACL_ACTION_TRAP; 33 break; 34 case FLOW_ACTION_POLICE: 35 ace->action = OCELOT_ACL_ACTION_POLICE; 36 rate = a->police.rate_bytes_ps; 37 ace->pol.rate = div_u64(rate, 1000) * 8; 38 burst = rate * PSCHED_NS2TICKS(a->police.burst); 39 ace->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC); 40 break; 41 default: 42 return -EOPNOTSUPP; 43 } 44 } 45 46 return 0; 47 } 48 49 static int ocelot_flower_parse(struct flow_cls_offload *f, 50 struct ocelot_ace_rule *ace) 51 { 52 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 53 struct flow_dissector *dissector = rule->match.dissector; 54 u16 proto = ntohs(f->common.protocol); 55 bool match_protocol = true; 56 57 if (dissector->used_keys & 58 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 59 BIT(FLOW_DISSECTOR_KEY_BASIC) | 60 BIT(FLOW_DISSECTOR_KEY_PORTS) | 61 BIT(FLOW_DISSECTOR_KEY_VLAN) | 62 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 63 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 64 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) { 65 return -EOPNOTSUPP; 66 } 67 68 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { 69 struct flow_match_control match; 70 71 flow_rule_match_control(rule, &match); 72 } 73 74 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 75 struct flow_match_eth_addrs match; 76 77 /* The hw support mac matches only for MAC_ETYPE key, 78 * therefore if other matches(port, tcp flags, etc) are added 79 * then just bail out 80 */ 81 if ((dissector->used_keys & 82 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 83 BIT(FLOW_DISSECTOR_KEY_BASIC) | 84 BIT(FLOW_DISSECTOR_KEY_CONTROL))) != 85 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 86 BIT(FLOW_DISSECTOR_KEY_BASIC) | 87 BIT(FLOW_DISSECTOR_KEY_CONTROL))) 88 return -EOPNOTSUPP; 89 90 flow_rule_match_eth_addrs(rule, &match); 91 ace->type = OCELOT_ACE_TYPE_ETYPE; 92 ether_addr_copy(ace->frame.etype.dmac.value, 93 match.key->dst); 94 ether_addr_copy(ace->frame.etype.smac.value, 95 match.key->src); 96 ether_addr_copy(ace->frame.etype.dmac.mask, 97 match.mask->dst); 98 ether_addr_copy(ace->frame.etype.smac.mask, 99 match.mask->src); 100 goto finished_key_parsing; 101 } 102 103 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { 104 struct flow_match_basic match; 105 106 flow_rule_match_basic(rule, &match); 107 if (ntohs(match.key->n_proto) == ETH_P_IP) { 108 ace->type = OCELOT_ACE_TYPE_IPV4; 109 ace->frame.ipv4.proto.value[0] = 110 match.key->ip_proto; 111 ace->frame.ipv4.proto.mask[0] = 112 match.mask->ip_proto; 113 match_protocol = false; 114 } 115 if (ntohs(match.key->n_proto) == ETH_P_IPV6) { 116 ace->type = OCELOT_ACE_TYPE_IPV6; 117 ace->frame.ipv6.proto.value[0] = 118 match.key->ip_proto; 119 ace->frame.ipv6.proto.mask[0] = 120 match.mask->ip_proto; 121 match_protocol = false; 122 } 123 } 124 125 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) && 126 proto == ETH_P_IP) { 127 struct flow_match_ipv4_addrs match; 128 u8 *tmp; 129 130 flow_rule_match_ipv4_addrs(rule, &match); 131 tmp = &ace->frame.ipv4.sip.value.addr[0]; 132 memcpy(tmp, &match.key->src, 4); 133 134 tmp = &ace->frame.ipv4.sip.mask.addr[0]; 135 memcpy(tmp, &match.mask->src, 4); 136 137 tmp = &ace->frame.ipv4.dip.value.addr[0]; 138 memcpy(tmp, &match.key->dst, 4); 139 140 tmp = &ace->frame.ipv4.dip.mask.addr[0]; 141 memcpy(tmp, &match.mask->dst, 4); 142 match_protocol = false; 143 } 144 145 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) && 146 proto == ETH_P_IPV6) { 147 return -EOPNOTSUPP; 148 } 149 150 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { 151 struct flow_match_ports match; 152 153 flow_rule_match_ports(rule, &match); 154 ace->frame.ipv4.sport.value = ntohs(match.key->src); 155 ace->frame.ipv4.sport.mask = ntohs(match.mask->src); 156 ace->frame.ipv4.dport.value = ntohs(match.key->dst); 157 ace->frame.ipv4.dport.mask = ntohs(match.mask->dst); 158 match_protocol = false; 159 } 160 161 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 162 struct flow_match_vlan match; 163 164 flow_rule_match_vlan(rule, &match); 165 ace->type = OCELOT_ACE_TYPE_ANY; 166 ace->vlan.vid.value = match.key->vlan_id; 167 ace->vlan.vid.mask = match.mask->vlan_id; 168 ace->vlan.pcp.value[0] = match.key->vlan_priority; 169 ace->vlan.pcp.mask[0] = match.mask->vlan_priority; 170 match_protocol = false; 171 } 172 173 finished_key_parsing: 174 if (match_protocol && proto != ETH_P_ALL) { 175 /* TODO: support SNAP, LLC etc */ 176 if (proto < ETH_P_802_3_MIN) 177 return -EOPNOTSUPP; 178 ace->type = OCELOT_ACE_TYPE_ETYPE; 179 *(u16 *)ace->frame.etype.etype.value = htons(proto); 180 *(u16 *)ace->frame.etype.etype.mask = 0xffff; 181 } 182 /* else, a rule of type OCELOT_ACE_TYPE_ANY is implicitly added */ 183 184 ace->prio = f->common.prio; 185 ace->id = f->cookie; 186 return ocelot_flower_parse_action(f, ace); 187 } 188 189 static 190 struct ocelot_ace_rule *ocelot_ace_rule_create(struct ocelot *ocelot, int port, 191 struct flow_cls_offload *f) 192 { 193 struct ocelot_ace_rule *ace; 194 195 ace = kzalloc(sizeof(*ace), GFP_KERNEL); 196 if (!ace) 197 return NULL; 198 199 ace->ingress_port_mask = BIT(port); 200 return ace; 201 } 202 203 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port, 204 struct flow_cls_offload *f, bool ingress) 205 { 206 struct ocelot_ace_rule *ace; 207 int ret; 208 209 ace = ocelot_ace_rule_create(ocelot, port, f); 210 if (!ace) 211 return -ENOMEM; 212 213 ret = ocelot_flower_parse(f, ace); 214 if (ret) { 215 kfree(ace); 216 return ret; 217 } 218 219 return ocelot_ace_rule_offload_add(ocelot, ace, f->common.extack); 220 } 221 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace); 222 223 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port, 224 struct flow_cls_offload *f, bool ingress) 225 { 226 struct ocelot_ace_rule ace; 227 228 ace.prio = f->common.prio; 229 ace.id = f->cookie; 230 231 return ocelot_ace_rule_offload_del(ocelot, &ace); 232 } 233 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy); 234 235 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port, 236 struct flow_cls_offload *f, bool ingress) 237 { 238 struct ocelot_ace_rule ace; 239 int ret; 240 241 ace.prio = f->common.prio; 242 ace.id = f->cookie; 243 ret = ocelot_ace_rule_stats_update(ocelot, &ace); 244 if (ret) 245 return ret; 246 247 flow_stats_update(&f->stats, 0x0, ace.stats.pkts, 0x0, 248 FLOW_ACTION_HW_STATS_IMMEDIATE); 249 return 0; 250 } 251 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats); 252 253 int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv, 254 struct flow_cls_offload *f, 255 bool ingress) 256 { 257 struct ocelot *ocelot = priv->port.ocelot; 258 int port = priv->chip_port; 259 260 if (!ingress) 261 return -EOPNOTSUPP; 262 263 switch (f->command) { 264 case FLOW_CLS_REPLACE: 265 return ocelot_cls_flower_replace(ocelot, port, f, ingress); 266 case FLOW_CLS_DESTROY: 267 return ocelot_cls_flower_destroy(ocelot, port, f, ingress); 268 case FLOW_CLS_STATS: 269 return ocelot_cls_flower_stats(ocelot, port, f, ingress); 270 default: 271 return -EOPNOTSUPP; 272 } 273 } 274