GNU Linux-libre 4.14.265-gnu1
[releases.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_flower.c
1 /*
2  * drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
3  * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the names of the copyright holders nor the names of its
15  *    contributors may be used to endorse or promote products derived from
16  *    this software without specific prior written permission.
17  *
18  * Alternatively, this software may be distributed under the terms of the
19  * GNU General Public License ("GPL") version 2 as published by the Free
20  * Software Foundation.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <linux/kernel.h>
36 #include <linux/errno.h>
37 #include <linux/netdevice.h>
38 #include <net/flow_dissector.h>
39 #include <net/pkt_cls.h>
40 #include <net/tc_act/tc_gact.h>
41 #include <net/tc_act/tc_mirred.h>
42 #include <net/tc_act/tc_vlan.h>
43
44 #include "spectrum.h"
45 #include "core_acl_flex_keys.h"
46
47 static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
48                                          struct net_device *dev, bool ingress,
49                                          struct mlxsw_sp_acl_rule_info *rulei,
50                                          struct tcf_exts *exts)
51 {
52         const struct tc_action *a;
53         LIST_HEAD(actions);
54         int err;
55
56         if (!tcf_exts_has_actions(exts))
57                 return 0;
58
59         /* Count action is inserted first */
60         err = mlxsw_sp_acl_rulei_act_count(mlxsw_sp, rulei);
61         if (err)
62                 return err;
63
64         tcf_exts_to_list(exts, &actions);
65         list_for_each_entry(a, &actions, list) {
66                 if (is_tcf_gact_shot(a)) {
67                         err = mlxsw_sp_acl_rulei_act_drop(rulei);
68                         if (err)
69                                 return err;
70                 } else if (is_tcf_gact_trap(a)) {
71                         err = mlxsw_sp_acl_rulei_act_trap(rulei);
72                         if (err)
73                                 return err;
74                 } else if (is_tcf_gact_goto_chain(a)) {
75                         u32 chain_index = tcf_gact_goto_chain_index(a);
76                         struct mlxsw_sp_acl_ruleset *ruleset;
77                         u16 group_id;
78
79                         ruleset = mlxsw_sp_acl_ruleset_lookup(mlxsw_sp, dev,
80                                                               ingress,
81                                                               chain_index,
82                                                               MLXSW_SP_ACL_PROFILE_FLOWER);
83                         if (IS_ERR(ruleset))
84                                 return PTR_ERR(ruleset);
85
86                         group_id = mlxsw_sp_acl_ruleset_group_id(ruleset);
87                         mlxsw_sp_acl_rulei_act_jump(rulei, group_id);
88                 } else if (is_tcf_mirred_egress_redirect(a)) {
89                         int ifindex = tcf_mirred_ifindex(a);
90                         struct net_device *out_dev;
91                         struct mlxsw_sp_fid *fid;
92                         u16 fid_index;
93
94                         fid = mlxsw_sp_acl_dummy_fid(mlxsw_sp);
95                         fid_index = mlxsw_sp_fid_index(fid);
96                         err = mlxsw_sp_acl_rulei_act_fid_set(mlxsw_sp, rulei,
97                                                              fid_index);
98                         if (err)
99                                 return err;
100
101                         out_dev = __dev_get_by_index(dev_net(dev), ifindex);
102                         if (out_dev == dev)
103                                 out_dev = NULL;
104
105                         err = mlxsw_sp_acl_rulei_act_fwd(mlxsw_sp, rulei,
106                                                          out_dev);
107                         if (err)
108                                 return err;
109                 } else if (is_tcf_vlan(a)) {
110                         u16 proto = be16_to_cpu(tcf_vlan_push_proto(a));
111                         u32 action = tcf_vlan_action(a);
112                         u8 prio = tcf_vlan_push_prio(a);
113                         u16 vid = tcf_vlan_push_vid(a);
114
115                         err = mlxsw_sp_acl_rulei_act_vlan(mlxsw_sp, rulei,
116                                                           action, vid,
117                                                           proto, prio);
118                         if (err)
119                                 return err;
120                 } else {
121                         dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n");
122                         return -EOPNOTSUPP;
123                 }
124         }
125         return 0;
126 }
127
128 static void mlxsw_sp_flower_parse_ipv4(struct mlxsw_sp_acl_rule_info *rulei,
129                                        struct tc_cls_flower_offload *f)
130 {
131         struct flow_dissector_key_ipv4_addrs *key =
132                 skb_flow_dissector_target(f->dissector,
133                                           FLOW_DISSECTOR_KEY_IPV4_ADDRS,
134                                           f->key);
135         struct flow_dissector_key_ipv4_addrs *mask =
136                 skb_flow_dissector_target(f->dissector,
137                                           FLOW_DISSECTOR_KEY_IPV4_ADDRS,
138                                           f->mask);
139
140         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_SRC_IP4,
141                                        ntohl(key->src), ntohl(mask->src));
142         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_DST_IP4,
143                                        ntohl(key->dst), ntohl(mask->dst));
144 }
145
146 static void mlxsw_sp_flower_parse_ipv6(struct mlxsw_sp_acl_rule_info *rulei,
147                                        struct tc_cls_flower_offload *f)
148 {
149         struct flow_dissector_key_ipv6_addrs *key =
150                 skb_flow_dissector_target(f->dissector,
151                                           FLOW_DISSECTOR_KEY_IPV6_ADDRS,
152                                           f->key);
153         struct flow_dissector_key_ipv6_addrs *mask =
154                 skb_flow_dissector_target(f->dissector,
155                                           FLOW_DISSECTOR_KEY_IPV6_ADDRS,
156                                           f->mask);
157         size_t addr_half_size = sizeof(key->src) / 2;
158
159         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP6_HI,
160                                        &key->src.s6_addr[0],
161                                        &mask->src.s6_addr[0],
162                                        addr_half_size);
163         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP6_LO,
164                                        &key->src.s6_addr[addr_half_size],
165                                        &mask->src.s6_addr[addr_half_size],
166                                        addr_half_size);
167         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP6_HI,
168                                        &key->dst.s6_addr[0],
169                                        &mask->dst.s6_addr[0],
170                                        addr_half_size);
171         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP6_LO,
172                                        &key->dst.s6_addr[addr_half_size],
173                                        &mask->dst.s6_addr[addr_half_size],
174                                        addr_half_size);
175 }
176
177 static int mlxsw_sp_flower_parse_ports(struct mlxsw_sp *mlxsw_sp,
178                                        struct mlxsw_sp_acl_rule_info *rulei,
179                                        struct tc_cls_flower_offload *f,
180                                        u8 ip_proto)
181 {
182         struct flow_dissector_key_ports *key, *mask;
183
184         if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS))
185                 return 0;
186
187         if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
188                 dev_err(mlxsw_sp->bus_info->dev, "Only UDP and TCP keys are supported\n");
189                 return -EINVAL;
190         }
191
192         key = skb_flow_dissector_target(f->dissector,
193                                         FLOW_DISSECTOR_KEY_PORTS,
194                                         f->key);
195         mask = skb_flow_dissector_target(f->dissector,
196                                          FLOW_DISSECTOR_KEY_PORTS,
197                                          f->mask);
198         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_DST_L4_PORT,
199                                        ntohs(key->dst), ntohs(mask->dst));
200         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_SRC_L4_PORT,
201                                        ntohs(key->src), ntohs(mask->src));
202         return 0;
203 }
204
205 static int mlxsw_sp_flower_parse_tcp(struct mlxsw_sp *mlxsw_sp,
206                                      struct mlxsw_sp_acl_rule_info *rulei,
207                                      struct tc_cls_flower_offload *f,
208                                      u8 ip_proto)
209 {
210         struct flow_dissector_key_tcp *key, *mask;
211
212         if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP))
213                 return 0;
214
215         if (ip_proto != IPPROTO_TCP) {
216                 dev_err(mlxsw_sp->bus_info->dev, "TCP keys supported only for TCP\n");
217                 return -EINVAL;
218         }
219
220         key = skb_flow_dissector_target(f->dissector,
221                                         FLOW_DISSECTOR_KEY_TCP,
222                                         f->key);
223         mask = skb_flow_dissector_target(f->dissector,
224                                          FLOW_DISSECTOR_KEY_TCP,
225                                          f->mask);
226         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_TCP_FLAGS,
227                                        ntohs(key->flags), ntohs(mask->flags));
228         return 0;
229 }
230
231 static int mlxsw_sp_flower_parse_ip(struct mlxsw_sp *mlxsw_sp,
232                                     struct mlxsw_sp_acl_rule_info *rulei,
233                                     struct tc_cls_flower_offload *f,
234                                     u16 n_proto)
235 {
236         struct flow_dissector_key_ip *key, *mask;
237
238         if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IP))
239                 return 0;
240
241         if (n_proto != ETH_P_IP && n_proto != ETH_P_IPV6) {
242                 dev_err(mlxsw_sp->bus_info->dev, "IP keys supported only for IPv4/6\n");
243                 return -EINVAL;
244         }
245
246         key = skb_flow_dissector_target(f->dissector,
247                                         FLOW_DISSECTOR_KEY_IP,
248                                         f->key);
249         mask = skb_flow_dissector_target(f->dissector,
250                                          FLOW_DISSECTOR_KEY_IP,
251                                          f->mask);
252         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_IP_TTL_,
253                                        key->ttl, mask->ttl);
254
255         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_IP_ECN,
256                                        key->tos & 0x3, mask->tos & 0x3);
257
258         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_IP_DSCP,
259                                        key->tos >> 6, mask->tos >> 6);
260
261         return 0;
262 }
263
264 static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
265                                  struct net_device *dev, bool ingress,
266                                  struct mlxsw_sp_acl_rule_info *rulei,
267                                  struct tc_cls_flower_offload *f)
268 {
269         u16 n_proto_mask = 0;
270         u16 n_proto_key = 0;
271         u16 addr_type = 0;
272         u8 ip_proto = 0;
273         int err;
274
275         if (f->dissector->used_keys &
276             ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
277               BIT(FLOW_DISSECTOR_KEY_BASIC) |
278               BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
279               BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
280               BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
281               BIT(FLOW_DISSECTOR_KEY_PORTS) |
282               BIT(FLOW_DISSECTOR_KEY_TCP) |
283               BIT(FLOW_DISSECTOR_KEY_IP) |
284               BIT(FLOW_DISSECTOR_KEY_VLAN))) {
285                 dev_err(mlxsw_sp->bus_info->dev, "Unsupported key\n");
286                 return -EOPNOTSUPP;
287         }
288
289         mlxsw_sp_acl_rulei_priority(rulei, f->common.prio);
290
291         if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
292                 struct flow_dissector_key_control *key =
293                         skb_flow_dissector_target(f->dissector,
294                                                   FLOW_DISSECTOR_KEY_CONTROL,
295                                                   f->key);
296                 addr_type = key->addr_type;
297         }
298
299         if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
300                 struct flow_dissector_key_basic *key =
301                         skb_flow_dissector_target(f->dissector,
302                                                   FLOW_DISSECTOR_KEY_BASIC,
303                                                   f->key);
304                 struct flow_dissector_key_basic *mask =
305                         skb_flow_dissector_target(f->dissector,
306                                                   FLOW_DISSECTOR_KEY_BASIC,
307                                                   f->mask);
308                 n_proto_key = ntohs(key->n_proto);
309                 n_proto_mask = ntohs(mask->n_proto);
310
311                 if (n_proto_key == ETH_P_ALL) {
312                         n_proto_key = 0;
313                         n_proto_mask = 0;
314                 }
315                 mlxsw_sp_acl_rulei_keymask_u32(rulei,
316                                                MLXSW_AFK_ELEMENT_ETHERTYPE,
317                                                n_proto_key, n_proto_mask);
318
319                 ip_proto = key->ip_proto;
320                 mlxsw_sp_acl_rulei_keymask_u32(rulei,
321                                                MLXSW_AFK_ELEMENT_IP_PROTO,
322                                                key->ip_proto, mask->ip_proto);
323         }
324
325         if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
326                 struct flow_dissector_key_eth_addrs *key =
327                         skb_flow_dissector_target(f->dissector,
328                                                   FLOW_DISSECTOR_KEY_ETH_ADDRS,
329                                                   f->key);
330                 struct flow_dissector_key_eth_addrs *mask =
331                         skb_flow_dissector_target(f->dissector,
332                                                   FLOW_DISSECTOR_KEY_ETH_ADDRS,
333                                                   f->mask);
334
335                 mlxsw_sp_acl_rulei_keymask_buf(rulei,
336                                                MLXSW_AFK_ELEMENT_DMAC,
337                                                key->dst, mask->dst,
338                                                sizeof(key->dst));
339                 mlxsw_sp_acl_rulei_keymask_buf(rulei,
340                                                MLXSW_AFK_ELEMENT_SMAC,
341                                                key->src, mask->src,
342                                                sizeof(key->src));
343         }
344
345         if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
346                 struct flow_dissector_key_vlan *key =
347                         skb_flow_dissector_target(f->dissector,
348                                                   FLOW_DISSECTOR_KEY_VLAN,
349                                                   f->key);
350                 struct flow_dissector_key_vlan *mask =
351                         skb_flow_dissector_target(f->dissector,
352                                                   FLOW_DISSECTOR_KEY_VLAN,
353                                                   f->mask);
354                 if (mask->vlan_id != 0)
355                         mlxsw_sp_acl_rulei_keymask_u32(rulei,
356                                                        MLXSW_AFK_ELEMENT_VID,
357                                                        key->vlan_id,
358                                                        mask->vlan_id);
359                 if (mask->vlan_priority != 0)
360                         mlxsw_sp_acl_rulei_keymask_u32(rulei,
361                                                        MLXSW_AFK_ELEMENT_PCP,
362                                                        key->vlan_priority,
363                                                        mask->vlan_priority);
364         }
365
366         if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS)
367                 mlxsw_sp_flower_parse_ipv4(rulei, f);
368
369         if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS)
370                 mlxsw_sp_flower_parse_ipv6(rulei, f);
371
372         err = mlxsw_sp_flower_parse_ports(mlxsw_sp, rulei, f, ip_proto);
373         if (err)
374                 return err;
375         err = mlxsw_sp_flower_parse_tcp(mlxsw_sp, rulei, f, ip_proto);
376         if (err)
377                 return err;
378
379         err = mlxsw_sp_flower_parse_ip(mlxsw_sp, rulei, f, n_proto_key & n_proto_mask);
380         if (err)
381                 return err;
382
383         return mlxsw_sp_flower_parse_actions(mlxsw_sp, dev, ingress,
384                                              rulei, f->exts);
385 }
386
387 int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
388                             struct tc_cls_flower_offload *f)
389 {
390         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
391         struct net_device *dev = mlxsw_sp_port->dev;
392         struct mlxsw_sp_acl_rule_info *rulei;
393         struct mlxsw_sp_acl_ruleset *ruleset;
394         struct mlxsw_sp_acl_rule *rule;
395         int err;
396
397         ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, dev, ingress,
398                                            f->common.chain_index,
399                                            MLXSW_SP_ACL_PROFILE_FLOWER);
400         if (IS_ERR(ruleset))
401                 return PTR_ERR(ruleset);
402
403         rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset, f->cookie);
404         if (IS_ERR(rule)) {
405                 err = PTR_ERR(rule);
406                 goto err_rule_create;
407         }
408
409         rulei = mlxsw_sp_acl_rule_rulei(rule);
410         err = mlxsw_sp_flower_parse(mlxsw_sp, dev, ingress, rulei, f);
411         if (err)
412                 goto err_flower_parse;
413
414         err = mlxsw_sp_acl_rulei_commit(rulei);
415         if (err)
416                 goto err_rulei_commit;
417
418         err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
419         if (err)
420                 goto err_rule_add;
421
422         mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
423         return 0;
424
425 err_rule_add:
426 err_rulei_commit:
427 err_flower_parse:
428         mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
429 err_rule_create:
430         mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
431         return err;
432 }
433
434 void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
435                              struct tc_cls_flower_offload *f)
436 {
437         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
438         struct mlxsw_sp_acl_ruleset *ruleset;
439         struct mlxsw_sp_acl_rule *rule;
440
441         ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, mlxsw_sp_port->dev,
442                                            ingress, f->common.chain_index,
443                                            MLXSW_SP_ACL_PROFILE_FLOWER);
444         if (IS_ERR(ruleset))
445                 return;
446
447         rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset, f->cookie);
448         if (rule) {
449                 mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
450                 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
451         }
452
453         mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
454 }
455
456 int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
457                           struct tc_cls_flower_offload *f)
458 {
459         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
460         struct mlxsw_sp_acl_ruleset *ruleset;
461         struct mlxsw_sp_acl_rule *rule;
462         u64 packets;
463         u64 lastuse;
464         u64 bytes;
465         int err;
466
467         ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, mlxsw_sp_port->dev,
468                                            ingress, f->common.chain_index,
469                                            MLXSW_SP_ACL_PROFILE_FLOWER);
470         if (WARN_ON(IS_ERR(ruleset)))
471                 return -EINVAL;
472
473         rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset, f->cookie);
474         if (!rule)
475                 return -EINVAL;
476
477         err = mlxsw_sp_acl_rule_get_stats(mlxsw_sp, rule, &packets, &bytes,
478                                           &lastuse);
479         if (err)
480                 goto err_rule_get_stats;
481
482         tcf_exts_stats_update(f->exts, bytes, packets, lastuse);
483
484         mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
485         return 0;
486
487 err_rule_get_stats:
488         mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
489         return err;
490 }