1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3 * Copyright (c) 2019 Microsemi Corporation
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
9 #include "ocelot_vcap.h"
11 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
12 struct ocelot_vcap_filter *filter)
14 const struct flow_action_entry *a;
18 if (!flow_action_basic_hw_stats_check(&f->rule->action,
22 flow_action_for_each(i, a, &f->rule->action) {
24 case FLOW_ACTION_DROP:
25 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
26 filter->action.port_mask = 0;
27 filter->action.police_ena = true;
28 filter->action.pol_ix = OCELOT_POLICER_DISCARD;
30 case FLOW_ACTION_TRAP:
31 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
32 filter->action.port_mask = 0;
33 filter->action.cpu_copy_ena = true;
34 filter->action.cpu_qu_num = 0;
36 case FLOW_ACTION_POLICE:
37 filter->action.police_ena = true;
38 rate = a->police.rate_bytes_ps;
39 filter->action.pol.rate = div_u64(rate, 1000) * 8;
40 filter->action.pol.burst = a->police.burst;
50 static int ocelot_flower_parse_key(struct flow_cls_offload *f,
51 struct ocelot_vcap_filter *filter)
53 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
54 struct flow_dissector *dissector = rule->match.dissector;
55 u16 proto = ntohs(f->common.protocol);
56 bool match_protocol = true;
58 if (dissector->used_keys &
59 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
60 BIT(FLOW_DISSECTOR_KEY_BASIC) |
61 BIT(FLOW_DISSECTOR_KEY_PORTS) |
62 BIT(FLOW_DISSECTOR_KEY_VLAN) |
63 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
64 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
65 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
69 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
70 struct flow_match_control match;
72 flow_rule_match_control(rule, &match);
75 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
76 struct flow_match_eth_addrs match;
78 /* The hw support mac matches only for MAC_ETYPE key,
79 * therefore if other matches(port, tcp flags, etc) are added
82 if ((dissector->used_keys &
83 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
84 BIT(FLOW_DISSECTOR_KEY_BASIC) |
85 BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
86 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
87 BIT(FLOW_DISSECTOR_KEY_BASIC) |
88 BIT(FLOW_DISSECTOR_KEY_CONTROL)))
91 flow_rule_match_eth_addrs(rule, &match);
92 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
93 ether_addr_copy(filter->key.etype.dmac.value,
95 ether_addr_copy(filter->key.etype.smac.value,
97 ether_addr_copy(filter->key.etype.dmac.mask,
99 ether_addr_copy(filter->key.etype.smac.mask,
101 goto finished_key_parsing;
104 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
105 struct flow_match_basic match;
107 flow_rule_match_basic(rule, &match);
108 if (ntohs(match.key->n_proto) == ETH_P_IP) {
109 filter->key_type = OCELOT_VCAP_KEY_IPV4;
110 filter->key.ipv4.proto.value[0] =
112 filter->key.ipv4.proto.mask[0] =
113 match.mask->ip_proto;
114 match_protocol = false;
116 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
117 filter->key_type = OCELOT_VCAP_KEY_IPV6;
118 filter->key.ipv6.proto.value[0] =
120 filter->key.ipv6.proto.mask[0] =
121 match.mask->ip_proto;
122 match_protocol = false;
126 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
128 struct flow_match_ipv4_addrs match;
131 flow_rule_match_ipv4_addrs(rule, &match);
132 tmp = &filter->key.ipv4.sip.value.addr[0];
133 memcpy(tmp, &match.key->src, 4);
135 tmp = &filter->key.ipv4.sip.mask.addr[0];
136 memcpy(tmp, &match.mask->src, 4);
138 tmp = &filter->key.ipv4.dip.value.addr[0];
139 memcpy(tmp, &match.key->dst, 4);
141 tmp = &filter->key.ipv4.dip.mask.addr[0];
142 memcpy(tmp, &match.mask->dst, 4);
143 match_protocol = false;
146 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
147 proto == ETH_P_IPV6) {
151 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
152 struct flow_match_ports match;
154 flow_rule_match_ports(rule, &match);
155 filter->key.ipv4.sport.value = ntohs(match.key->src);
156 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
157 filter->key.ipv4.dport.value = ntohs(match.key->dst);
158 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
159 match_protocol = false;
162 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
163 struct flow_match_vlan match;
165 flow_rule_match_vlan(rule, &match);
166 filter->key_type = OCELOT_VCAP_KEY_ANY;
167 filter->vlan.vid.value = match.key->vlan_id;
168 filter->vlan.vid.mask = match.mask->vlan_id;
169 filter->vlan.pcp.value[0] = match.key->vlan_priority;
170 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
171 match_protocol = false;
174 finished_key_parsing:
175 if (match_protocol && proto != ETH_P_ALL) {
176 /* TODO: support SNAP, LLC etc */
177 if (proto < ETH_P_802_3_MIN)
179 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
180 *(__be16 *)filter->key.etype.etype.value = htons(proto);
181 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
183 /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
188 static int ocelot_flower_parse(struct flow_cls_offload *f,
189 struct ocelot_vcap_filter *filter)
193 filter->prio = f->common.prio;
194 filter->id = f->cookie;
196 ret = ocelot_flower_parse_action(f, filter);
200 return ocelot_flower_parse_key(f, filter);
203 static struct ocelot_vcap_filter
204 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port,
205 struct flow_cls_offload *f)
207 struct ocelot_vcap_filter *filter;
209 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
213 filter->ingress_port_mask = BIT(port);
217 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
218 struct flow_cls_offload *f, bool ingress)
220 struct ocelot_vcap_filter *filter;
223 filter = ocelot_vcap_filter_create(ocelot, port, f);
227 ret = ocelot_flower_parse(f, filter);
233 return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
235 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
237 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
238 struct flow_cls_offload *f, bool ingress)
240 struct ocelot_vcap_block *block = &ocelot->block;
241 struct ocelot_vcap_filter *filter;
243 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
247 return ocelot_vcap_filter_del(ocelot, filter);
249 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
251 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
252 struct flow_cls_offload *f, bool ingress)
254 struct ocelot_vcap_block *block = &ocelot->block;
255 struct ocelot_vcap_filter *filter;
258 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
262 ret = ocelot_vcap_filter_stats_update(ocelot, filter);
266 flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
267 FLOW_ACTION_HW_STATS_IMMEDIATE);
270 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);