00b02b76164e59913780f2c5a6e39f7d6b363ccc
[linux-2.6-microblaze.git] / drivers / net / ethernet / mscc / ocelot_flower.c
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_action_basic_hw_stats_check(&f->rule->action,
19                                               f->common.extack))
20                 return -EOPNOTSUPP;
21
22         flow_action_for_each(i, a, &f->rule->action) {
23                 switch (a->id) {
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;
29                         break;
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;
35                         break;
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;
41                         break;
42                 default:
43                         return -EOPNOTSUPP;
44                 }
45         }
46
47         return 0;
48 }
49
50 static int ocelot_flower_parse_key(struct flow_cls_offload *f,
51                                    struct ocelot_vcap_filter *filter)
52 {
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;
57
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))) {
66                 return -EOPNOTSUPP;
67         }
68
69         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
70                 struct flow_match_control match;
71
72                 flow_rule_match_control(rule, &match);
73         }
74
75         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
76                 struct flow_match_eth_addrs match;
77
78                 /* The hw support mac matches only for MAC_ETYPE key,
79                  * therefore if other matches(port, tcp flags, etc) are added
80                  * then just bail out
81                  */
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)))
89                         return -EOPNOTSUPP;
90
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,
94                                 match.key->dst);
95                 ether_addr_copy(filter->key.etype.smac.value,
96                                 match.key->src);
97                 ether_addr_copy(filter->key.etype.dmac.mask,
98                                 match.mask->dst);
99                 ether_addr_copy(filter->key.etype.smac.mask,
100                                 match.mask->src);
101                 goto finished_key_parsing;
102         }
103
104         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
105                 struct flow_match_basic match;
106
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] =
111                                 match.key->ip_proto;
112                         filter->key.ipv4.proto.mask[0] =
113                                 match.mask->ip_proto;
114                         match_protocol = false;
115                 }
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] =
119                                 match.key->ip_proto;
120                         filter->key.ipv6.proto.mask[0] =
121                                 match.mask->ip_proto;
122                         match_protocol = false;
123                 }
124         }
125
126         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
127             proto == ETH_P_IP) {
128                 struct flow_match_ipv4_addrs match;
129                 u8 *tmp;
130
131                 flow_rule_match_ipv4_addrs(rule, &match);
132                 tmp = &filter->key.ipv4.sip.value.addr[0];
133                 memcpy(tmp, &match.key->src, 4);
134
135                 tmp = &filter->key.ipv4.sip.mask.addr[0];
136                 memcpy(tmp, &match.mask->src, 4);
137
138                 tmp = &filter->key.ipv4.dip.value.addr[0];
139                 memcpy(tmp, &match.key->dst, 4);
140
141                 tmp = &filter->key.ipv4.dip.mask.addr[0];
142                 memcpy(tmp, &match.mask->dst, 4);
143                 match_protocol = false;
144         }
145
146         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
147             proto == ETH_P_IPV6) {
148                 return -EOPNOTSUPP;
149         }
150
151         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
152                 struct flow_match_ports match;
153
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;
160         }
161
162         if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
163                 struct flow_match_vlan match;
164
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;
172         }
173
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)
178                         return -EOPNOTSUPP;
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);
182         }
183         /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
184
185         return 0;
186 }
187
188 static int ocelot_flower_parse(struct flow_cls_offload *f,
189                                struct ocelot_vcap_filter *filter)
190 {
191         int ret;
192
193         filter->prio = f->common.prio;
194         filter->id = f->cookie;
195
196         ret = ocelot_flower_parse_action(f, filter);
197         if (ret)
198                 return ret;
199
200         return ocelot_flower_parse_key(f, filter);
201 }
202
203 static struct ocelot_vcap_filter
204 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port,
205                          struct flow_cls_offload *f)
206 {
207         struct ocelot_vcap_filter *filter;
208
209         filter = kzalloc(sizeof(*filter), GFP_KERNEL);
210         if (!filter)
211                 return NULL;
212
213         filter->ingress_port_mask = BIT(port);
214         return filter;
215 }
216
217 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
218                               struct flow_cls_offload *f, bool ingress)
219 {
220         struct ocelot_vcap_filter *filter;
221         int ret;
222
223         filter = ocelot_vcap_filter_create(ocelot, port, f);
224         if (!filter)
225                 return -ENOMEM;
226
227         ret = ocelot_flower_parse(f, filter);
228         if (ret) {
229                 kfree(filter);
230                 return ret;
231         }
232
233         return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
234 }
235 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
236
237 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
238                               struct flow_cls_offload *f, bool ingress)
239 {
240         struct ocelot_vcap_block *block = &ocelot->block;
241         struct ocelot_vcap_filter *filter;
242
243         filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
244         if (!filter)
245                 return 0;
246
247         return ocelot_vcap_filter_del(ocelot, filter);
248 }
249 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
250
251 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
252                             struct flow_cls_offload *f, bool ingress)
253 {
254         struct ocelot_vcap_block *block = &ocelot->block;
255         struct ocelot_vcap_filter *filter;
256         int ret;
257
258         filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
259         if (!filter)
260                 return 0;
261
262         ret = ocelot_vcap_filter_stats_update(ocelot, filter);
263         if (ret)
264                 return ret;
265
266         flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
267                           FLOW_ACTION_HW_STATS_IMMEDIATE);
268         return 0;
269 }
270 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);