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