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