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 
43 #include "spectrum.h"
44 #include "core_acl_flex_keys.h"
45 
46 static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
47 					 struct net_device *dev,
48 					 struct mlxsw_sp_acl_rule_info *rulei,
49 					 struct tcf_exts *exts)
50 {
51 	const struct tc_action *a;
52 	LIST_HEAD(actions);
53 	int err;
54 
55 	if (tc_no_actions(exts))
56 		return 0;
57 
58 	tcf_exts_to_list(exts, &actions);
59 	list_for_each_entry(a, &actions, list) {
60 		if (is_tcf_gact_shot(a)) {
61 			err = mlxsw_sp_acl_rulei_act_drop(rulei);
62 			if (err)
63 				return err;
64 		} else if (is_tcf_mirred_egress_redirect(a)) {
65 			int ifindex = tcf_mirred_ifindex(a);
66 			struct net_device *out_dev;
67 
68 			out_dev = __dev_get_by_index(dev_net(dev), ifindex);
69 			if (out_dev == dev)
70 				out_dev = NULL;
71 
72 			err = mlxsw_sp_acl_rulei_act_fwd(mlxsw_sp, rulei,
73 							 out_dev);
74 			if (err)
75 				return err;
76 		} else {
77 			dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n");
78 			return -EOPNOTSUPP;
79 		}
80 	}
81 	return 0;
82 }
83 
84 static void mlxsw_sp_flower_parse_ipv4(struct mlxsw_sp_acl_rule_info *rulei,
85 				       struct tc_cls_flower_offload *f)
86 {
87 	struct flow_dissector_key_ipv4_addrs *key =
88 		skb_flow_dissector_target(f->dissector,
89 					  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
90 					  f->key);
91 	struct flow_dissector_key_ipv4_addrs *mask =
92 		skb_flow_dissector_target(f->dissector,
93 					  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
94 					  f->mask);
95 
96 	mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_SRC_IP4,
97 				       ntohl(key->src), ntohl(mask->src));
98 	mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_DST_IP4,
99 				       ntohl(key->dst), ntohl(mask->dst));
100 }
101 
102 static void mlxsw_sp_flower_parse_ipv6(struct mlxsw_sp_acl_rule_info *rulei,
103 				       struct tc_cls_flower_offload *f)
104 {
105 	struct flow_dissector_key_ipv6_addrs *key =
106 		skb_flow_dissector_target(f->dissector,
107 					  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
108 					  f->key);
109 	struct flow_dissector_key_ipv6_addrs *mask =
110 		skb_flow_dissector_target(f->dissector,
111 					  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
112 					  f->mask);
113 	size_t addr_half_size = sizeof(key->src) / 2;
114 
115 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP6_HI,
116 				       &key->src.s6_addr[0],
117 				       &mask->src.s6_addr[0],
118 				       addr_half_size);
119 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP6_LO,
120 				       &key->src.s6_addr[addr_half_size],
121 				       &mask->src.s6_addr[addr_half_size],
122 				       addr_half_size);
123 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP6_HI,
124 				       &key->dst.s6_addr[0],
125 				       &mask->dst.s6_addr[0],
126 				       addr_half_size);
127 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP6_LO,
128 				       &key->dst.s6_addr[addr_half_size],
129 				       &mask->dst.s6_addr[addr_half_size],
130 				       addr_half_size);
131 }
132 
133 static int mlxsw_sp_flower_parse_ports(struct mlxsw_sp *mlxsw_sp,
134 				       struct mlxsw_sp_acl_rule_info *rulei,
135 				       struct tc_cls_flower_offload *f,
136 				       u8 ip_proto)
137 {
138 	struct flow_dissector_key_ports *key, *mask;
139 
140 	if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS))
141 		return 0;
142 
143 	if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
144 		dev_err(mlxsw_sp->bus_info->dev, "Only UDP and TCP keys are supported\n");
145 		return -EINVAL;
146 	}
147 
148 	key = skb_flow_dissector_target(f->dissector,
149 					FLOW_DISSECTOR_KEY_PORTS,
150 					f->key);
151 	mask = skb_flow_dissector_target(f->dissector,
152 					 FLOW_DISSECTOR_KEY_PORTS,
153 					 f->mask);
154 	mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_DST_L4_PORT,
155 				       ntohs(key->dst), ntohs(mask->dst));
156 	mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_SRC_L4_PORT,
157 				       ntohs(key->src), ntohs(mask->src));
158 	return 0;
159 }
160 
161 static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
162 				 struct net_device *dev,
163 				 struct mlxsw_sp_acl_rule_info *rulei,
164 				 struct tc_cls_flower_offload *f)
165 {
166 	u16 addr_type = 0;
167 	u8 ip_proto = 0;
168 	int err;
169 
170 	if (f->dissector->used_keys &
171 	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
172 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
173 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
174 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
175 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
176 	      BIT(FLOW_DISSECTOR_KEY_PORTS))) {
177 		dev_err(mlxsw_sp->bus_info->dev, "Unsupported key\n");
178 		return -EOPNOTSUPP;
179 	}
180 
181 	mlxsw_sp_acl_rulei_priority(rulei, f->prio);
182 
183 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
184 		struct flow_dissector_key_control *key =
185 			skb_flow_dissector_target(f->dissector,
186 						  FLOW_DISSECTOR_KEY_CONTROL,
187 						  f->key);
188 		addr_type = key->addr_type;
189 	}
190 
191 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
192 		struct flow_dissector_key_basic *key =
193 			skb_flow_dissector_target(f->dissector,
194 						  FLOW_DISSECTOR_KEY_BASIC,
195 						  f->key);
196 		struct flow_dissector_key_basic *mask =
197 			skb_flow_dissector_target(f->dissector,
198 						  FLOW_DISSECTOR_KEY_BASIC,
199 						  f->mask);
200 		u16 n_proto_key = ntohs(key->n_proto);
201 		u16 n_proto_mask = ntohs(mask->n_proto);
202 
203 		if (n_proto_key == ETH_P_ALL) {
204 			n_proto_key = 0;
205 			n_proto_mask = 0;
206 		}
207 		mlxsw_sp_acl_rulei_keymask_u32(rulei,
208 					       MLXSW_AFK_ELEMENT_ETHERTYPE,
209 					       n_proto_key, n_proto_mask);
210 
211 		ip_proto = key->ip_proto;
212 		mlxsw_sp_acl_rulei_keymask_u32(rulei,
213 					       MLXSW_AFK_ELEMENT_IP_PROTO,
214 					       key->ip_proto, mask->ip_proto);
215 	}
216 
217 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
218 		struct flow_dissector_key_eth_addrs *key =
219 			skb_flow_dissector_target(f->dissector,
220 						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
221 						  f->key);
222 		struct flow_dissector_key_eth_addrs *mask =
223 			skb_flow_dissector_target(f->dissector,
224 						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
225 						  f->mask);
226 
227 		mlxsw_sp_acl_rulei_keymask_buf(rulei,
228 					       MLXSW_AFK_ELEMENT_DMAC,
229 					       key->dst, mask->dst,
230 					       sizeof(key->dst));
231 		mlxsw_sp_acl_rulei_keymask_buf(rulei,
232 					       MLXSW_AFK_ELEMENT_SMAC,
233 					       key->src, mask->src,
234 					       sizeof(key->src));
235 	}
236 
237 	if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS)
238 		mlxsw_sp_flower_parse_ipv4(rulei, f);
239 
240 	if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS)
241 		mlxsw_sp_flower_parse_ipv6(rulei, f);
242 
243 	err = mlxsw_sp_flower_parse_ports(mlxsw_sp, rulei, f, ip_proto);
244 	if (err)
245 		return err;
246 
247 	return mlxsw_sp_flower_parse_actions(mlxsw_sp, dev, rulei, f->exts);
248 }
249 
250 int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
251 			    __be16 protocol, struct tc_cls_flower_offload *f)
252 {
253 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
254 	struct net_device *dev = mlxsw_sp_port->dev;
255 	struct mlxsw_sp_acl_rule_info *rulei;
256 	struct mlxsw_sp_acl_ruleset *ruleset;
257 	struct mlxsw_sp_acl_rule *rule;
258 	int err;
259 
260 	ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, dev, ingress,
261 					   MLXSW_SP_ACL_PROFILE_FLOWER);
262 	if (IS_ERR(ruleset))
263 		return PTR_ERR(ruleset);
264 
265 	rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset, f->cookie);
266 	if (IS_ERR(rule)) {
267 		err = PTR_ERR(rule);
268 		goto err_rule_create;
269 	}
270 
271 	rulei = mlxsw_sp_acl_rule_rulei(rule);
272 	err = mlxsw_sp_flower_parse(mlxsw_sp, dev, rulei, f);
273 	if (err)
274 		goto err_flower_parse;
275 
276 	err = mlxsw_sp_acl_rulei_commit(rulei);
277 	if (err)
278 		goto err_rulei_commit;
279 
280 	err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
281 	if (err)
282 		goto err_rule_add;
283 
284 	mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
285 	return 0;
286 
287 err_rule_add:
288 err_rulei_commit:
289 err_flower_parse:
290 	mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
291 err_rule_create:
292 	mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
293 	return err;
294 }
295 
296 void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
297 			     struct tc_cls_flower_offload *f)
298 {
299 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
300 	struct mlxsw_sp_acl_ruleset *ruleset;
301 	struct mlxsw_sp_acl_rule *rule;
302 
303 	ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, mlxsw_sp_port->dev,
304 					   ingress,
305 					   MLXSW_SP_ACL_PROFILE_FLOWER);
306 	if (WARN_ON(IS_ERR(ruleset)))
307 		return;
308 
309 	rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset, f->cookie);
310 	if (!WARN_ON(!rule)) {
311 		mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
312 		mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
313 	}
314 
315 	mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
316 }
317