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