xref: /linux/drivers/net/ethernet/mscc/ocelot_flower.c (revision e5a52fd2b8cdb700b3c07b030e050a49ef3156b9)
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