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