1c9da1ac1SSteen Hegelund // SPDX-License-Identifier: GPL-2.0+ 2c9da1ac1SSteen Hegelund /* Microchip VCAP API 3c9da1ac1SSteen Hegelund * 4c9da1ac1SSteen Hegelund * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5c9da1ac1SSteen Hegelund */ 6c9da1ac1SSteen Hegelund 7c9da1ac1SSteen Hegelund #include <net/tcp.h> 8c9da1ac1SSteen Hegelund 9c9da1ac1SSteen Hegelund #include "sparx5_tc.h" 10c9da1ac1SSteen Hegelund #include "vcap_api.h" 11c9da1ac1SSteen Hegelund #include "vcap_api_client.h" 12c9da1ac1SSteen Hegelund #include "sparx5_main.h" 13c9da1ac1SSteen Hegelund #include "sparx5_vcap_impl.h" 14c9da1ac1SSteen Hegelund 150ca60948SSteen Hegelund #define SPX5_MAX_RULE_SIZE 13 /* allows X1, X2, X4, X6 and X12 rules */ 160ca60948SSteen Hegelund 170ca60948SSteen Hegelund /* Collect keysets and type ids for multiple rules per size */ 180ca60948SSteen Hegelund struct sparx5_wildcard_rule { 190ca60948SSteen Hegelund bool selected; 200ca60948SSteen Hegelund u8 value; 210ca60948SSteen Hegelund u8 mask; 220ca60948SSteen Hegelund enum vcap_keyfield_set keyset; 230ca60948SSteen Hegelund }; 240ca60948SSteen Hegelund 250ca60948SSteen Hegelund struct sparx5_multiple_rules { 260ca60948SSteen Hegelund struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE]; 270ca60948SSteen Hegelund }; 280ca60948SSteen Hegelund 29c9da1ac1SSteen Hegelund struct sparx5_tc_flower_parse_usage { 30c9da1ac1SSteen Hegelund struct flow_cls_offload *fco; 31c9da1ac1SSteen Hegelund struct flow_rule *frule; 32c9da1ac1SSteen Hegelund struct vcap_rule *vrule; 33542e6e2cSSteen Hegelund struct vcap_admin *admin; 34d6c2964dSSteen Hegelund u16 l3_proto; 35d6c2964dSSteen Hegelund u8 l4_proto; 36c9da1ac1SSteen Hegelund unsigned int used_keys; 37c9da1ac1SSteen Hegelund }; 38c9da1ac1SSteen Hegelund 393a344f99SSteen Hegelund enum sparx5_is2_arp_opcode { 403a344f99SSteen Hegelund SPX5_IS2_ARP_REQUEST, 413a344f99SSteen Hegelund SPX5_IS2_ARP_REPLY, 423a344f99SSteen Hegelund SPX5_IS2_RARP_REQUEST, 433a344f99SSteen Hegelund SPX5_IS2_RARP_REPLY, 443a344f99SSteen Hegelund }; 453a344f99SSteen Hegelund 463a344f99SSteen Hegelund enum tc_arp_opcode { 473a344f99SSteen Hegelund TC_ARP_OP_RESERVED, 483a344f99SSteen Hegelund TC_ARP_OP_REQUEST, 493a344f99SSteen Hegelund TC_ARP_OP_REPLY, 503a344f99SSteen Hegelund }; 513a344f99SSteen Hegelund 52c9da1ac1SSteen Hegelund static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st) 53c9da1ac1SSteen Hegelund { 54c9da1ac1SSteen Hegelund enum vcap_key_field smac_key = VCAP_KF_L2_SMAC; 55c9da1ac1SSteen Hegelund enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC; 56c9da1ac1SSteen Hegelund struct flow_match_eth_addrs match; 57c9da1ac1SSteen Hegelund struct vcap_u48_key smac, dmac; 58c9da1ac1SSteen Hegelund int err = 0; 59c9da1ac1SSteen Hegelund 60c9da1ac1SSteen Hegelund flow_rule_match_eth_addrs(st->frule, &match); 61c9da1ac1SSteen Hegelund 62c9da1ac1SSteen Hegelund if (!is_zero_ether_addr(match.mask->src)) { 63c9da1ac1SSteen Hegelund vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN); 64c9da1ac1SSteen Hegelund vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN); 65c9da1ac1SSteen Hegelund err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac); 66c9da1ac1SSteen Hegelund if (err) 67c9da1ac1SSteen Hegelund goto out; 68c9da1ac1SSteen Hegelund } 69c9da1ac1SSteen Hegelund 70c9da1ac1SSteen Hegelund if (!is_zero_ether_addr(match.mask->dst)) { 71c9da1ac1SSteen Hegelund vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN); 72c9da1ac1SSteen Hegelund vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN); 73c9da1ac1SSteen Hegelund err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac); 74c9da1ac1SSteen Hegelund if (err) 75c9da1ac1SSteen Hegelund goto out; 76c9da1ac1SSteen Hegelund } 77c9da1ac1SSteen Hegelund 78c9da1ac1SSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS); 79c9da1ac1SSteen Hegelund 80c9da1ac1SSteen Hegelund return err; 81c9da1ac1SSteen Hegelund 82c9da1ac1SSteen Hegelund out: 83c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error"); 84c9da1ac1SSteen Hegelund return err; 85c9da1ac1SSteen Hegelund } 86c9da1ac1SSteen Hegelund 87d6c2964dSSteen Hegelund static int 88d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ipv4_usage(struct sparx5_tc_flower_parse_usage *st) 89d6c2964dSSteen Hegelund { 90d6c2964dSSteen Hegelund int err = 0; 91d6c2964dSSteen Hegelund 92d6c2964dSSteen Hegelund if (st->l3_proto == ETH_P_IP) { 93d6c2964dSSteen Hegelund struct flow_match_ipv4_addrs mt; 94d6c2964dSSteen Hegelund 95d6c2964dSSteen Hegelund flow_rule_match_ipv4_addrs(st->frule, &mt); 96d6c2964dSSteen Hegelund if (mt.mask->src) { 97d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 98d6c2964dSSteen Hegelund VCAP_KF_L3_IP4_SIP, 99d6c2964dSSteen Hegelund be32_to_cpu(mt.key->src), 100d6c2964dSSteen Hegelund be32_to_cpu(mt.mask->src)); 101d6c2964dSSteen Hegelund if (err) 102d6c2964dSSteen Hegelund goto out; 103d6c2964dSSteen Hegelund } 104d6c2964dSSteen Hegelund if (mt.mask->dst) { 105d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 106d6c2964dSSteen Hegelund VCAP_KF_L3_IP4_DIP, 107d6c2964dSSteen Hegelund be32_to_cpu(mt.key->dst), 108d6c2964dSSteen Hegelund be32_to_cpu(mt.mask->dst)); 109d6c2964dSSteen Hegelund if (err) 110d6c2964dSSteen Hegelund goto out; 111d6c2964dSSteen Hegelund } 112d6c2964dSSteen Hegelund } 113d6c2964dSSteen Hegelund 114d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS); 115d6c2964dSSteen Hegelund 116d6c2964dSSteen Hegelund return err; 117d6c2964dSSteen Hegelund 118d6c2964dSSteen Hegelund out: 119d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error"); 120d6c2964dSSteen Hegelund return err; 121d6c2964dSSteen Hegelund } 122d6c2964dSSteen Hegelund 123d6c2964dSSteen Hegelund static int 124d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ipv6_usage(struct sparx5_tc_flower_parse_usage *st) 125d6c2964dSSteen Hegelund { 126d6c2964dSSteen Hegelund int err = 0; 127d6c2964dSSteen Hegelund 128d6c2964dSSteen Hegelund if (st->l3_proto == ETH_P_IPV6) { 129d6c2964dSSteen Hegelund struct flow_match_ipv6_addrs mt; 130d6c2964dSSteen Hegelund struct vcap_u128_key sip; 131d6c2964dSSteen Hegelund struct vcap_u128_key dip; 132d6c2964dSSteen Hegelund 133d6c2964dSSteen Hegelund flow_rule_match_ipv6_addrs(st->frule, &mt); 134d6c2964dSSteen Hegelund /* Check if address masks are non-zero */ 135d6c2964dSSteen Hegelund if (!ipv6_addr_any(&mt.mask->src)) { 136d6c2964dSSteen Hegelund vcap_netbytes_copy(sip.value, mt.key->src.s6_addr, 16); 137d6c2964dSSteen Hegelund vcap_netbytes_copy(sip.mask, mt.mask->src.s6_addr, 16); 138d6c2964dSSteen Hegelund err = vcap_rule_add_key_u128(st->vrule, 139d6c2964dSSteen Hegelund VCAP_KF_L3_IP6_SIP, &sip); 140d6c2964dSSteen Hegelund if (err) 141d6c2964dSSteen Hegelund goto out; 142d6c2964dSSteen Hegelund } 143d6c2964dSSteen Hegelund if (!ipv6_addr_any(&mt.mask->dst)) { 144d6c2964dSSteen Hegelund vcap_netbytes_copy(dip.value, mt.key->dst.s6_addr, 16); 145d6c2964dSSteen Hegelund vcap_netbytes_copy(dip.mask, mt.mask->dst.s6_addr, 16); 146d6c2964dSSteen Hegelund err = vcap_rule_add_key_u128(st->vrule, 147d6c2964dSSteen Hegelund VCAP_KF_L3_IP6_DIP, &dip); 148d6c2964dSSteen Hegelund if (err) 149d6c2964dSSteen Hegelund goto out; 150d6c2964dSSteen Hegelund } 151d6c2964dSSteen Hegelund } 152d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS); 153d6c2964dSSteen Hegelund return err; 154d6c2964dSSteen Hegelund out: 155d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error"); 156d6c2964dSSteen Hegelund return err; 157d6c2964dSSteen Hegelund } 158d6c2964dSSteen Hegelund 159d6c2964dSSteen Hegelund static int 160d6c2964dSSteen Hegelund sparx5_tc_flower_handler_control_usage(struct sparx5_tc_flower_parse_usage *st) 161d6c2964dSSteen Hegelund { 162d6c2964dSSteen Hegelund struct flow_match_control mt; 163d6c2964dSSteen Hegelund u32 value, mask; 164d6c2964dSSteen Hegelund int err = 0; 165d6c2964dSSteen Hegelund 166d6c2964dSSteen Hegelund flow_rule_match_control(st->frule, &mt); 167d6c2964dSSteen Hegelund 168d6c2964dSSteen Hegelund if (mt.mask->flags) { 169d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) { 170d6c2964dSSteen Hegelund if (mt.key->flags & FLOW_DIS_FIRST_FRAG) { 171d6c2964dSSteen Hegelund value = 1; /* initial fragment */ 172d6c2964dSSteen Hegelund mask = 0x3; 173d6c2964dSSteen Hegelund } else { 174d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { 175d6c2964dSSteen Hegelund value = 3; /* follow up fragment */ 176d6c2964dSSteen Hegelund mask = 0x3; 177d6c2964dSSteen Hegelund } else { 178d6c2964dSSteen Hegelund value = 0; /* no fragment */ 179d6c2964dSSteen Hegelund mask = 0x3; 180d6c2964dSSteen Hegelund } 181d6c2964dSSteen Hegelund } 182d6c2964dSSteen Hegelund } else { 183d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { 184d6c2964dSSteen Hegelund value = 3; /* follow up fragment */ 185d6c2964dSSteen Hegelund mask = 0x3; 186d6c2964dSSteen Hegelund } else { 187d6c2964dSSteen Hegelund value = 0; /* no fragment */ 188d6c2964dSSteen Hegelund mask = 0x3; 189d6c2964dSSteen Hegelund } 190d6c2964dSSteen Hegelund } 191d6c2964dSSteen Hegelund 192d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 193d6c2964dSSteen Hegelund VCAP_KF_L3_FRAGMENT_TYPE, 194d6c2964dSSteen Hegelund value, mask); 195d6c2964dSSteen Hegelund if (err) 196d6c2964dSSteen Hegelund goto out; 197d6c2964dSSteen Hegelund } 198d6c2964dSSteen Hegelund 199d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL); 200d6c2964dSSteen Hegelund 201d6c2964dSSteen Hegelund return err; 202d6c2964dSSteen Hegelund 203d6c2964dSSteen Hegelund out: 204d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); 205d6c2964dSSteen Hegelund return err; 206d6c2964dSSteen Hegelund } 207d6c2964dSSteen Hegelund 208d6c2964dSSteen Hegelund static int 209d6c2964dSSteen Hegelund sparx5_tc_flower_handler_portnum_usage(struct sparx5_tc_flower_parse_usage *st) 210d6c2964dSSteen Hegelund { 211d6c2964dSSteen Hegelund struct flow_match_ports mt; 212d6c2964dSSteen Hegelund u16 value, mask; 213d6c2964dSSteen Hegelund int err = 0; 214d6c2964dSSteen Hegelund 215d6c2964dSSteen Hegelund flow_rule_match_ports(st->frule, &mt); 216d6c2964dSSteen Hegelund 217d6c2964dSSteen Hegelund if (mt.mask->src) { 218d6c2964dSSteen Hegelund value = be16_to_cpu(mt.key->src); 219d6c2964dSSteen Hegelund mask = be16_to_cpu(mt.mask->src); 220d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_SPORT, value, 221d6c2964dSSteen Hegelund mask); 222d6c2964dSSteen Hegelund if (err) 223d6c2964dSSteen Hegelund goto out; 224d6c2964dSSteen Hegelund } 225d6c2964dSSteen Hegelund 226d6c2964dSSteen Hegelund if (mt.mask->dst) { 227d6c2964dSSteen Hegelund value = be16_to_cpu(mt.key->dst); 228d6c2964dSSteen Hegelund mask = be16_to_cpu(mt.mask->dst); 229d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_DPORT, value, 230d6c2964dSSteen Hegelund mask); 231d6c2964dSSteen Hegelund if (err) 232d6c2964dSSteen Hegelund goto out; 233d6c2964dSSteen Hegelund } 234d6c2964dSSteen Hegelund 235d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS); 236d6c2964dSSteen Hegelund 237d6c2964dSSteen Hegelund return err; 238d6c2964dSSteen Hegelund 239d6c2964dSSteen Hegelund out: 240d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error"); 241d6c2964dSSteen Hegelund return err; 242d6c2964dSSteen Hegelund } 243d6c2964dSSteen Hegelund 244d6c2964dSSteen Hegelund static int 245d6c2964dSSteen Hegelund sparx5_tc_flower_handler_basic_usage(struct sparx5_tc_flower_parse_usage *st) 246d6c2964dSSteen Hegelund { 247d6c2964dSSteen Hegelund struct flow_match_basic mt; 248d6c2964dSSteen Hegelund int err = 0; 249d6c2964dSSteen Hegelund 250d6c2964dSSteen Hegelund flow_rule_match_basic(st->frule, &mt); 251d6c2964dSSteen Hegelund 252d6c2964dSSteen Hegelund if (mt.mask->n_proto) { 253d6c2964dSSteen Hegelund st->l3_proto = be16_to_cpu(mt.key->n_proto); 25463e35645SSteen Hegelund if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) { 255d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, 256d6c2964dSSteen Hegelund st->l3_proto, ~0); 257d6c2964dSSteen Hegelund if (err) 258d6c2964dSSteen Hegelund goto out; 259d6c2964dSSteen Hegelund } else if (st->l3_proto == ETH_P_IP) { 260d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 261d6c2964dSSteen Hegelund VCAP_BIT_1); 262d6c2964dSSteen Hegelund if (err) 263d6c2964dSSteen Hegelund goto out; 264d6c2964dSSteen Hegelund } else if (st->l3_proto == ETH_P_IPV6) { 265d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 266d6c2964dSSteen Hegelund VCAP_BIT_0); 267d6c2964dSSteen Hegelund if (err) 268d6c2964dSSteen Hegelund goto out; 2694114ef2cSSteen Hegelund if (st->admin->vtype == VCAP_TYPE_IS0) { 2704114ef2cSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, 2714114ef2cSSteen Hegelund VCAP_KF_IP_SNAP_IS, 2724114ef2cSSteen Hegelund VCAP_BIT_1); 2734114ef2cSSteen Hegelund if (err) 2744114ef2cSSteen Hegelund goto out; 2754114ef2cSSteen Hegelund } 2764114ef2cSSteen Hegelund 277d6c2964dSSteen Hegelund } 278d6c2964dSSteen Hegelund } 279d6c2964dSSteen Hegelund 280d6c2964dSSteen Hegelund if (mt.mask->ip_proto) { 281d6c2964dSSteen Hegelund st->l4_proto = mt.key->ip_proto; 282d6c2964dSSteen Hegelund if (st->l4_proto == IPPROTO_TCP) { 283d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, 284d6c2964dSSteen Hegelund VCAP_KF_TCP_IS, 285d6c2964dSSteen Hegelund VCAP_BIT_1); 286d6c2964dSSteen Hegelund if (err) 287d6c2964dSSteen Hegelund goto out; 288d6c2964dSSteen Hegelund } else if (st->l4_proto == IPPROTO_UDP) { 289d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, 290d6c2964dSSteen Hegelund VCAP_KF_TCP_IS, 291d6c2964dSSteen Hegelund VCAP_BIT_0); 292d6c2964dSSteen Hegelund if (err) 293d6c2964dSSteen Hegelund goto out; 294542e6e2cSSteen Hegelund if (st->admin->vtype == VCAP_TYPE_IS0) { 295542e6e2cSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, 296542e6e2cSSteen Hegelund VCAP_KF_TCP_UDP_IS, 297542e6e2cSSteen Hegelund VCAP_BIT_1); 298542e6e2cSSteen Hegelund if (err) 299542e6e2cSSteen Hegelund goto out; 300542e6e2cSSteen Hegelund } 301d6c2964dSSteen Hegelund } else { 302d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 303d6c2964dSSteen Hegelund VCAP_KF_L3_IP_PROTO, 304d6c2964dSSteen Hegelund st->l4_proto, ~0); 305d6c2964dSSteen Hegelund if (err) 306d6c2964dSSteen Hegelund goto out; 307d6c2964dSSteen Hegelund } 308d6c2964dSSteen Hegelund } 309d6c2964dSSteen Hegelund 310d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC); 311d6c2964dSSteen Hegelund 312d6c2964dSSteen Hegelund return err; 313d6c2964dSSteen Hegelund 314d6c2964dSSteen Hegelund out: 315d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error"); 316d6c2964dSSteen Hegelund return err; 317d6c2964dSSteen Hegelund } 318d6c2964dSSteen Hegelund 319d6c2964dSSteen Hegelund static int 32052df82ccSSteen Hegelund sparx5_tc_flower_handler_cvlan_usage(struct sparx5_tc_flower_parse_usage *st) 32152df82ccSSteen Hegelund { 32252df82ccSSteen Hegelund enum vcap_key_field vid_key = VCAP_KF_8021Q_VID0; 32352df82ccSSteen Hegelund enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP0; 32452df82ccSSteen Hegelund struct flow_match_vlan mt; 32552df82ccSSteen Hegelund u16 tpid; 32652df82ccSSteen Hegelund int err; 32752df82ccSSteen Hegelund 328*a5300724SSteen Hegelund if (st->admin->vtype != VCAP_TYPE_IS0) { 329*a5300724SSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, 330*a5300724SSteen Hegelund "cvlan not supported in this VCAP"); 33152df82ccSSteen Hegelund return -EINVAL; 332*a5300724SSteen Hegelund } 33352df82ccSSteen Hegelund 33452df82ccSSteen Hegelund flow_rule_match_cvlan(st->frule, &mt); 33552df82ccSSteen Hegelund 33652df82ccSSteen Hegelund tpid = be16_to_cpu(mt.key->vlan_tpid); 33752df82ccSSteen Hegelund 33852df82ccSSteen Hegelund if (tpid == ETH_P_8021Q) { 33952df82ccSSteen Hegelund vid_key = VCAP_KF_8021Q_VID1; 34052df82ccSSteen Hegelund pcp_key = VCAP_KF_8021Q_PCP1; 34152df82ccSSteen Hegelund } 34252df82ccSSteen Hegelund 34352df82ccSSteen Hegelund if (mt.mask->vlan_id) { 34452df82ccSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, vid_key, 34552df82ccSSteen Hegelund mt.key->vlan_id, 34652df82ccSSteen Hegelund mt.mask->vlan_id); 34752df82ccSSteen Hegelund if (err) 34852df82ccSSteen Hegelund goto out; 34952df82ccSSteen Hegelund } 35052df82ccSSteen Hegelund 35152df82ccSSteen Hegelund if (mt.mask->vlan_priority) { 35252df82ccSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, pcp_key, 35352df82ccSSteen Hegelund mt.key->vlan_priority, 35452df82ccSSteen Hegelund mt.mask->vlan_priority); 35552df82ccSSteen Hegelund if (err) 35652df82ccSSteen Hegelund goto out; 35752df82ccSSteen Hegelund } 35852df82ccSSteen Hegelund 35952df82ccSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CVLAN); 36052df82ccSSteen Hegelund 36152df82ccSSteen Hegelund return 0; 36252df82ccSSteen Hegelund out: 36352df82ccSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "cvlan parse error"); 36452df82ccSSteen Hegelund return err; 36552df82ccSSteen Hegelund } 36652df82ccSSteen Hegelund 36752df82ccSSteen Hegelund static int 368d6c2964dSSteen Hegelund sparx5_tc_flower_handler_vlan_usage(struct sparx5_tc_flower_parse_usage *st) 369d6c2964dSSteen Hegelund { 370d6c2964dSSteen Hegelund enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS; 371d6c2964dSSteen Hegelund enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS; 372d6c2964dSSteen Hegelund struct flow_match_vlan mt; 373d6c2964dSSteen Hegelund int err; 374d6c2964dSSteen Hegelund 375d6c2964dSSteen Hegelund flow_rule_match_vlan(st->frule, &mt); 376d6c2964dSSteen Hegelund 37752df82ccSSteen Hegelund if (st->admin->vtype == VCAP_TYPE_IS0) { 37852df82ccSSteen Hegelund vid_key = VCAP_KF_8021Q_VID0; 37952df82ccSSteen Hegelund pcp_key = VCAP_KF_8021Q_PCP0; 38052df82ccSSteen Hegelund } 38152df82ccSSteen Hegelund 382d6c2964dSSteen Hegelund if (mt.mask->vlan_id) { 383d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, vid_key, 384d6c2964dSSteen Hegelund mt.key->vlan_id, 385d6c2964dSSteen Hegelund mt.mask->vlan_id); 386d6c2964dSSteen Hegelund if (err) 387d6c2964dSSteen Hegelund goto out; 388d6c2964dSSteen Hegelund } 389d6c2964dSSteen Hegelund 390d6c2964dSSteen Hegelund if (mt.mask->vlan_priority) { 391d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, pcp_key, 392d6c2964dSSteen Hegelund mt.key->vlan_priority, 393d6c2964dSSteen Hegelund mt.mask->vlan_priority); 394d6c2964dSSteen Hegelund if (err) 395d6c2964dSSteen Hegelund goto out; 396d6c2964dSSteen Hegelund } 397d6c2964dSSteen Hegelund 398d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN); 399d6c2964dSSteen Hegelund 4004e9a6139SDan Carpenter return 0; 401d6c2964dSSteen Hegelund out: 402d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error"); 403d6c2964dSSteen Hegelund return err; 404d6c2964dSSteen Hegelund } 405d6c2964dSSteen Hegelund 406d6c2964dSSteen Hegelund static int 407d6c2964dSSteen Hegelund sparx5_tc_flower_handler_tcp_usage(struct sparx5_tc_flower_parse_usage *st) 408d6c2964dSSteen Hegelund { 409d6c2964dSSteen Hegelund struct flow_match_tcp mt; 410d6c2964dSSteen Hegelund u16 tcp_flags_mask; 411d6c2964dSSteen Hegelund u16 tcp_flags_key; 412d6c2964dSSteen Hegelund enum vcap_bit val; 413d6c2964dSSteen Hegelund int err = 0; 414d6c2964dSSteen Hegelund 415d6c2964dSSteen Hegelund flow_rule_match_tcp(st->frule, &mt); 416d6c2964dSSteen Hegelund tcp_flags_key = be16_to_cpu(mt.key->flags); 417d6c2964dSSteen Hegelund tcp_flags_mask = be16_to_cpu(mt.mask->flags); 418d6c2964dSSteen Hegelund 419d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_FIN) { 420d6c2964dSSteen Hegelund val = VCAP_BIT_0; 421d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_FIN) 422d6c2964dSSteen Hegelund val = VCAP_BIT_1; 423d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_FIN, val); 424d6c2964dSSteen Hegelund if (err) 425d6c2964dSSteen Hegelund goto out; 426d6c2964dSSteen Hegelund } 427d6c2964dSSteen Hegelund 428d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_SYN) { 429d6c2964dSSteen Hegelund val = VCAP_BIT_0; 430d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_SYN) 431d6c2964dSSteen Hegelund val = VCAP_BIT_1; 432d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_SYN, val); 433d6c2964dSSteen Hegelund if (err) 434d6c2964dSSteen Hegelund goto out; 435d6c2964dSSteen Hegelund } 436d6c2964dSSteen Hegelund 437d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_RST) { 438d6c2964dSSteen Hegelund val = VCAP_BIT_0; 439d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_RST) 440d6c2964dSSteen Hegelund val = VCAP_BIT_1; 441d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_RST, val); 442d6c2964dSSteen Hegelund if (err) 443d6c2964dSSteen Hegelund goto out; 444d6c2964dSSteen Hegelund } 445d6c2964dSSteen Hegelund 446d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_PSH) { 447d6c2964dSSteen Hegelund val = VCAP_BIT_0; 448d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_PSH) 449d6c2964dSSteen Hegelund val = VCAP_BIT_1; 450d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_PSH, val); 451d6c2964dSSteen Hegelund if (err) 452d6c2964dSSteen Hegelund goto out; 453d6c2964dSSteen Hegelund } 454d6c2964dSSteen Hegelund 455d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_ACK) { 456d6c2964dSSteen Hegelund val = VCAP_BIT_0; 457d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_ACK) 458d6c2964dSSteen Hegelund val = VCAP_BIT_1; 459d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_ACK, val); 460d6c2964dSSteen Hegelund if (err) 461d6c2964dSSteen Hegelund goto out; 462d6c2964dSSteen Hegelund } 463d6c2964dSSteen Hegelund 464d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_URG) { 465d6c2964dSSteen Hegelund val = VCAP_BIT_0; 466d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_URG) 467d6c2964dSSteen Hegelund val = VCAP_BIT_1; 468d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_URG, val); 469d6c2964dSSteen Hegelund if (err) 470d6c2964dSSteen Hegelund goto out; 471d6c2964dSSteen Hegelund } 472d6c2964dSSteen Hegelund 473d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP); 474d6c2964dSSteen Hegelund 475d6c2964dSSteen Hegelund return err; 476d6c2964dSSteen Hegelund 477d6c2964dSSteen Hegelund out: 478d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error"); 479d6c2964dSSteen Hegelund return err; 480d6c2964dSSteen Hegelund } 481d6c2964dSSteen Hegelund 482d6c2964dSSteen Hegelund static int 4833a344f99SSteen Hegelund sparx5_tc_flower_handler_arp_usage(struct sparx5_tc_flower_parse_usage *st) 4843a344f99SSteen Hegelund { 4853a344f99SSteen Hegelund struct flow_match_arp mt; 4863a344f99SSteen Hegelund u16 value, mask; 4873a344f99SSteen Hegelund u32 ipval, ipmsk; 4883a344f99SSteen Hegelund int err; 4893a344f99SSteen Hegelund 4903a344f99SSteen Hegelund flow_rule_match_arp(st->frule, &mt); 4913a344f99SSteen Hegelund 4923a344f99SSteen Hegelund if (mt.mask->op) { 4933a344f99SSteen Hegelund mask = 0x3; 4943a344f99SSteen Hegelund if (st->l3_proto == ETH_P_ARP) { 4953a344f99SSteen Hegelund value = mt.key->op == TC_ARP_OP_REQUEST ? 4963a344f99SSteen Hegelund SPX5_IS2_ARP_REQUEST : 4973a344f99SSteen Hegelund SPX5_IS2_ARP_REPLY; 4983a344f99SSteen Hegelund } else { /* RARP */ 4993a344f99SSteen Hegelund value = mt.key->op == TC_ARP_OP_REQUEST ? 5003a344f99SSteen Hegelund SPX5_IS2_RARP_REQUEST : 5013a344f99SSteen Hegelund SPX5_IS2_RARP_REPLY; 5023a344f99SSteen Hegelund } 5033a344f99SSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ARP_OPCODE, 5043a344f99SSteen Hegelund value, mask); 5053a344f99SSteen Hegelund if (err) 5063a344f99SSteen Hegelund goto out; 5073a344f99SSteen Hegelund } 5083a344f99SSteen Hegelund 5093a344f99SSteen Hegelund /* The IS2 ARP keyset does not support ARP hardware addresses */ 5103a344f99SSteen Hegelund if (!is_zero_ether_addr(mt.mask->sha) || 5114e9a6139SDan Carpenter !is_zero_ether_addr(mt.mask->tha)) { 5124e9a6139SDan Carpenter err = -EINVAL; 5133a344f99SSteen Hegelund goto out; 5144e9a6139SDan Carpenter } 5153a344f99SSteen Hegelund 5163a344f99SSteen Hegelund if (mt.mask->sip) { 5173a344f99SSteen Hegelund ipval = be32_to_cpu((__force __be32)mt.key->sip); 5183a344f99SSteen Hegelund ipmsk = be32_to_cpu((__force __be32)mt.mask->sip); 5193a344f99SSteen Hegelund 5203a344f99SSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_SIP, 5213a344f99SSteen Hegelund ipval, ipmsk); 5223a344f99SSteen Hegelund if (err) 5233a344f99SSteen Hegelund goto out; 5243a344f99SSteen Hegelund } 5253a344f99SSteen Hegelund 5263a344f99SSteen Hegelund if (mt.mask->tip) { 5273a344f99SSteen Hegelund ipval = be32_to_cpu((__force __be32)mt.key->tip); 5283a344f99SSteen Hegelund ipmsk = be32_to_cpu((__force __be32)mt.mask->tip); 5293a344f99SSteen Hegelund 5303a344f99SSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_DIP, 5313a344f99SSteen Hegelund ipval, ipmsk); 5323a344f99SSteen Hegelund if (err) 5333a344f99SSteen Hegelund goto out; 5343a344f99SSteen Hegelund } 5353a344f99SSteen Hegelund 5363a344f99SSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ARP); 5373a344f99SSteen Hegelund 5384e9a6139SDan Carpenter return 0; 5393a344f99SSteen Hegelund 5403a344f99SSteen Hegelund out: 5413a344f99SSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error"); 5423a344f99SSteen Hegelund return err; 5433a344f99SSteen Hegelund } 5443a344f99SSteen Hegelund 5453a344f99SSteen Hegelund static int 546d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ip_usage(struct sparx5_tc_flower_parse_usage *st) 547d6c2964dSSteen Hegelund { 548d6c2964dSSteen Hegelund struct flow_match_ip mt; 549d6c2964dSSteen Hegelund int err = 0; 550d6c2964dSSteen Hegelund 551d6c2964dSSteen Hegelund flow_rule_match_ip(st->frule, &mt); 552d6c2964dSSteen Hegelund 553d6c2964dSSteen Hegelund if (mt.mask->tos) { 554d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_TOS, 555d6c2964dSSteen Hegelund mt.key->tos, 556d6c2964dSSteen Hegelund mt.mask->tos); 557d6c2964dSSteen Hegelund if (err) 558d6c2964dSSteen Hegelund goto out; 559d6c2964dSSteen Hegelund } 560d6c2964dSSteen Hegelund 561d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IP); 562d6c2964dSSteen Hegelund 563d6c2964dSSteen Hegelund return err; 564d6c2964dSSteen Hegelund 565d6c2964dSSteen Hegelund out: 566d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error"); 567d6c2964dSSteen Hegelund return err; 568d6c2964dSSteen Hegelund } 569d6c2964dSSteen Hegelund 570c9da1ac1SSteen Hegelund static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = { 571c9da1ac1SSteen Hegelund [FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage, 572d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = sparx5_tc_flower_handler_ipv4_usage, 573d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = sparx5_tc_flower_handler_ipv6_usage, 574d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage, 575d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_PORTS] = sparx5_tc_flower_handler_portnum_usage, 576d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage, 57752df82ccSSteen Hegelund [FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage, 578d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage, 579d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_TCP] = sparx5_tc_flower_handler_tcp_usage, 5803a344f99SSteen Hegelund [FLOW_DISSECTOR_KEY_ARP] = sparx5_tc_flower_handler_arp_usage, 581d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IP] = sparx5_tc_flower_handler_ip_usage, 582c9da1ac1SSteen Hegelund }; 583c9da1ac1SSteen Hegelund 584c9da1ac1SSteen Hegelund static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, 585c9da1ac1SSteen Hegelund struct vcap_admin *admin, 586abc4010dSSteen Hegelund struct vcap_rule *vrule, 587abc4010dSSteen Hegelund u16 *l3_proto) 588c9da1ac1SSteen Hegelund { 589c9da1ac1SSteen Hegelund struct sparx5_tc_flower_parse_usage state = { 590c9da1ac1SSteen Hegelund .fco = fco, 591c9da1ac1SSteen Hegelund .vrule = vrule, 592abc4010dSSteen Hegelund .l3_proto = ETH_P_ALL, 593542e6e2cSSteen Hegelund .admin = admin, 594c9da1ac1SSteen Hegelund }; 595c9da1ac1SSteen Hegelund int idx, err = 0; 596c9da1ac1SSteen Hegelund 597c9da1ac1SSteen Hegelund state.frule = flow_cls_offload_flow_rule(fco); 598c9da1ac1SSteen Hegelund for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) { 599c9da1ac1SSteen Hegelund if (!flow_rule_match_key(state.frule, idx)) 600c9da1ac1SSteen Hegelund continue; 601c9da1ac1SSteen Hegelund if (!sparx5_tc_flower_usage_handlers[idx]) 602c9da1ac1SSteen Hegelund continue; 603c9da1ac1SSteen Hegelund err = sparx5_tc_flower_usage_handlers[idx](&state); 604c9da1ac1SSteen Hegelund if (err) 605c9da1ac1SSteen Hegelund return err; 606c9da1ac1SSteen Hegelund } 607abc4010dSSteen Hegelund 608abc4010dSSteen Hegelund if (state.frule->match.dissector->used_keys ^ state.used_keys) { 609abc4010dSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 610abc4010dSSteen Hegelund "Unsupported match item"); 611abc4010dSSteen Hegelund return -ENOENT; 612abc4010dSSteen Hegelund } 613abc4010dSSteen Hegelund 614abc4010dSSteen Hegelund if (l3_proto) 615abc4010dSSteen Hegelund *l3_proto = state.l3_proto; 616c9da1ac1SSteen Hegelund return err; 617c9da1ac1SSteen Hegelund } 618c9da1ac1SSteen Hegelund 619392d0ab0SSteen Hegelund static int sparx5_tc_flower_action_check(struct vcap_control *vctrl, 620784c3067SSteen Hegelund struct net_device *ndev, 621784c3067SSteen Hegelund struct flow_cls_offload *fco) 622392d0ab0SSteen Hegelund { 623392d0ab0SSteen Hegelund struct flow_rule *rule = flow_cls_offload_flow_rule(fco); 624392d0ab0SSteen Hegelund struct flow_action_entry *actent, *last_actent = NULL; 625392d0ab0SSteen Hegelund struct flow_action *act = &rule->action; 626392d0ab0SSteen Hegelund u64 action_mask = 0; 627392d0ab0SSteen Hegelund int idx; 628392d0ab0SSteen Hegelund 629392d0ab0SSteen Hegelund if (!flow_action_has_entries(act)) { 630392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); 631392d0ab0SSteen Hegelund return -EINVAL; 632392d0ab0SSteen Hegelund } 633392d0ab0SSteen Hegelund 634392d0ab0SSteen Hegelund if (!flow_action_basic_hw_stats_check(act, fco->common.extack)) 635392d0ab0SSteen Hegelund return -EOPNOTSUPP; 636392d0ab0SSteen Hegelund 637392d0ab0SSteen Hegelund flow_action_for_each(idx, actent, act) { 638392d0ab0SSteen Hegelund if (action_mask & BIT(actent->id)) { 639392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 640392d0ab0SSteen Hegelund "More actions of the same type"); 641392d0ab0SSteen Hegelund return -EINVAL; 642392d0ab0SSteen Hegelund } 643392d0ab0SSteen Hegelund action_mask |= BIT(actent->id); 644392d0ab0SSteen Hegelund last_actent = actent; /* Save last action for later check */ 645392d0ab0SSteen Hegelund } 646392d0ab0SSteen Hegelund 647784c3067SSteen Hegelund /* Check if last action is a goto 648784c3067SSteen Hegelund * The last chain/lookup does not need to have a goto action 649784c3067SSteen Hegelund */ 650784c3067SSteen Hegelund if (last_actent->id == FLOW_ACTION_GOTO) { 651784c3067SSteen Hegelund /* Check if the destination chain is in one of the VCAPs */ 652392d0ab0SSteen Hegelund if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 653392d0ab0SSteen Hegelund last_actent->chain_index)) { 654392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 655392d0ab0SSteen Hegelund "Invalid goto chain"); 656392d0ab0SSteen Hegelund return -EINVAL; 657392d0ab0SSteen Hegelund } 658784c3067SSteen Hegelund } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) { 659784c3067SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 660784c3067SSteen Hegelund "Last action must be 'goto'"); 661784c3067SSteen Hegelund return -EINVAL; 662784c3067SSteen Hegelund } 663392d0ab0SSteen Hegelund 664392d0ab0SSteen Hegelund /* Catch unsupported combinations of actions */ 665392d0ab0SSteen Hegelund if (action_mask & BIT(FLOW_ACTION_TRAP) && 666392d0ab0SSteen Hegelund action_mask & BIT(FLOW_ACTION_ACCEPT)) { 667392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 668392d0ab0SSteen Hegelund "Cannot combine pass and trap action"); 669392d0ab0SSteen Hegelund return -EOPNOTSUPP; 670392d0ab0SSteen Hegelund } 671392d0ab0SSteen Hegelund 672392d0ab0SSteen Hegelund return 0; 673392d0ab0SSteen Hegelund } 674392d0ab0SSteen Hegelund 675542e6e2cSSteen Hegelund /* Add a rule counter action */ 67640e7fe18SSteen Hegelund static int sparx5_tc_add_rule_counter(struct vcap_admin *admin, 67740e7fe18SSteen Hegelund struct vcap_rule *vrule) 67840e7fe18SSteen Hegelund { 67940e7fe18SSteen Hegelund int err; 68040e7fe18SSteen Hegelund 681542e6e2cSSteen Hegelund if (admin->vtype == VCAP_TYPE_IS2) { 682542e6e2cSSteen Hegelund err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID, 683542e6e2cSSteen Hegelund vrule->id); 68440e7fe18SSteen Hegelund if (err) 68540e7fe18SSteen Hegelund return err; 68640e7fe18SSteen Hegelund vcap_rule_set_counter_id(vrule, vrule->id); 687542e6e2cSSteen Hegelund } 688542e6e2cSSteen Hegelund 689542e6e2cSSteen Hegelund return 0; 69040e7fe18SSteen Hegelund } 69140e7fe18SSteen Hegelund 6920ca60948SSteen Hegelund /* Collect all port keysets and apply the first of them, possibly wildcarded */ 6930ca60948SSteen Hegelund static int sparx5_tc_select_protocol_keyset(struct net_device *ndev, 6940ca60948SSteen Hegelund struct vcap_rule *vrule, 6950ca60948SSteen Hegelund struct vcap_admin *admin, 6960ca60948SSteen Hegelund u16 l3_proto, 6970ca60948SSteen Hegelund struct sparx5_multiple_rules *multi) 6980ca60948SSteen Hegelund { 6990ca60948SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 7000ca60948SSteen Hegelund struct vcap_keyset_list portkeysetlist = {}; 7010ca60948SSteen Hegelund enum vcap_keyfield_set portkeysets[10] = {}; 7020ca60948SSteen Hegelund struct vcap_keyset_list matches = {}; 7030ca60948SSteen Hegelund enum vcap_keyfield_set keysets[10]; 7040ca60948SSteen Hegelund int idx, jdx, err = 0, count = 0; 7050ca60948SSteen Hegelund struct sparx5_wildcard_rule *mru; 7060ca60948SSteen Hegelund const struct vcap_set *kinfo; 7070ca60948SSteen Hegelund struct vcap_control *vctrl; 7080ca60948SSteen Hegelund 7090ca60948SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 7100ca60948SSteen Hegelund 7110ca60948SSteen Hegelund /* Find the keysets that the rule can use */ 7120ca60948SSteen Hegelund matches.keysets = keysets; 7130ca60948SSteen Hegelund matches.max = ARRAY_SIZE(keysets); 7140ca60948SSteen Hegelund if (vcap_rule_find_keysets(vrule, &matches) == 0) 7150ca60948SSteen Hegelund return -EINVAL; 7160ca60948SSteen Hegelund 7170ca60948SSteen Hegelund /* Find the keysets that the port configuration supports */ 7180ca60948SSteen Hegelund portkeysetlist.max = ARRAY_SIZE(portkeysets); 7190ca60948SSteen Hegelund portkeysetlist.keysets = portkeysets; 7200ca60948SSteen Hegelund err = sparx5_vcap_get_port_keyset(ndev, 7210ca60948SSteen Hegelund admin, vrule->vcap_chain_id, 7220ca60948SSteen Hegelund l3_proto, 7230ca60948SSteen Hegelund &portkeysetlist); 7240ca60948SSteen Hegelund if (err) 7250ca60948SSteen Hegelund return err; 7260ca60948SSteen Hegelund 7270ca60948SSteen Hegelund /* Find the intersection of the two sets of keyset */ 7280ca60948SSteen Hegelund for (idx = 0; idx < portkeysetlist.cnt; ++idx) { 7290ca60948SSteen Hegelund kinfo = vcap_keyfieldset(vctrl, admin->vtype, 7300ca60948SSteen Hegelund portkeysetlist.keysets[idx]); 7310ca60948SSteen Hegelund if (!kinfo) 7320ca60948SSteen Hegelund continue; 7330ca60948SSteen Hegelund 7340ca60948SSteen Hegelund /* Find a port keyset that matches the required keys 7350ca60948SSteen Hegelund * If there are multiple keysets then compose a type id mask 7360ca60948SSteen Hegelund */ 7370ca60948SSteen Hegelund for (jdx = 0; jdx < matches.cnt; ++jdx) { 7380ca60948SSteen Hegelund if (portkeysetlist.keysets[idx] != matches.keysets[jdx]) 7390ca60948SSteen Hegelund continue; 7400ca60948SSteen Hegelund 7410ca60948SSteen Hegelund mru = &multi->rule[kinfo->sw_per_item]; 7420ca60948SSteen Hegelund if (!mru->selected) { 7430ca60948SSteen Hegelund mru->selected = true; 7440ca60948SSteen Hegelund mru->keyset = portkeysetlist.keysets[idx]; 7450ca60948SSteen Hegelund mru->value = kinfo->type_id; 7460ca60948SSteen Hegelund } 7470ca60948SSteen Hegelund mru->value &= kinfo->type_id; 7480ca60948SSteen Hegelund mru->mask |= kinfo->type_id; 7490ca60948SSteen Hegelund ++count; 7500ca60948SSteen Hegelund } 7510ca60948SSteen Hegelund } 7520ca60948SSteen Hegelund if (count == 0) 7530ca60948SSteen Hegelund return -EPROTO; 7540ca60948SSteen Hegelund 7550ca60948SSteen Hegelund if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt) 7560ca60948SSteen Hegelund return -ENOENT; 7570ca60948SSteen Hegelund 7580ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 7590ca60948SSteen Hegelund mru = &multi->rule[idx]; 7600ca60948SSteen Hegelund if (!mru->selected) 7610ca60948SSteen Hegelund continue; 7620ca60948SSteen Hegelund 7630ca60948SSteen Hegelund /* Align the mask to the combined value */ 7640ca60948SSteen Hegelund mru->mask ^= mru->value; 7650ca60948SSteen Hegelund } 7660ca60948SSteen Hegelund 7670ca60948SSteen Hegelund /* Set the chosen keyset on the rule and set a wildcarded type if there 7680ca60948SSteen Hegelund * are more than one keyset 7690ca60948SSteen Hegelund */ 7700ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 7710ca60948SSteen Hegelund mru = &multi->rule[idx]; 7720ca60948SSteen Hegelund if (!mru->selected) 7730ca60948SSteen Hegelund continue; 7740ca60948SSteen Hegelund 7750ca60948SSteen Hegelund vcap_set_rule_set_keyset(vrule, mru->keyset); 7760ca60948SSteen Hegelund if (count > 1) 7770ca60948SSteen Hegelund /* Some keysets do not have a type field */ 7780ca60948SSteen Hegelund vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, 7790ca60948SSteen Hegelund mru->value, 7800ca60948SSteen Hegelund ~mru->mask); 7810ca60948SSteen Hegelund mru->selected = false; /* mark as done */ 7820ca60948SSteen Hegelund break; /* Stop here and add more rules later */ 7830ca60948SSteen Hegelund } 7840ca60948SSteen Hegelund return err; 7850ca60948SSteen Hegelund } 7860ca60948SSteen Hegelund 7870ca60948SSteen Hegelund static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl, 7880ca60948SSteen Hegelund struct flow_cls_offload *fco, 7890ca60948SSteen Hegelund struct vcap_rule *erule, 7900ca60948SSteen Hegelund struct vcap_admin *admin, 7910ca60948SSteen Hegelund struct sparx5_wildcard_rule *rule) 7920ca60948SSteen Hegelund { 7930ca60948SSteen Hegelund enum vcap_key_field keylist[] = { 7940ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK, 7950ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK_SEL, 7960ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK_RNG, 7970ca60948SSteen Hegelund VCAP_KF_LOOKUP_FIRST_IS, 7980ca60948SSteen Hegelund VCAP_KF_TYPE, 7990ca60948SSteen Hegelund }; 8000ca60948SSteen Hegelund struct vcap_rule *vrule; 8010ca60948SSteen Hegelund int err; 8020ca60948SSteen Hegelund 8030ca60948SSteen Hegelund /* Add an extra rule with a special user and the new keyset */ 8040ca60948SSteen Hegelund erule->user = VCAP_USER_TC_EXTRA; 8050ca60948SSteen Hegelund vrule = vcap_copy_rule(erule); 8060ca60948SSteen Hegelund if (IS_ERR(vrule)) 8070ca60948SSteen Hegelund return PTR_ERR(vrule); 8080ca60948SSteen Hegelund 8090ca60948SSteen Hegelund /* Link the new rule to the existing rule with the cookie */ 8100ca60948SSteen Hegelund vrule->cookie = erule->cookie; 8110ca60948SSteen Hegelund vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true); 8120ca60948SSteen Hegelund err = vcap_set_rule_set_keyset(vrule, rule->keyset); 8130ca60948SSteen Hegelund if (err) { 8140ca60948SSteen Hegelund pr_err("%s:%d: could not set keyset %s in rule: %u\n", 8150ca60948SSteen Hegelund __func__, __LINE__, 8160ca60948SSteen Hegelund vcap_keyset_name(vctrl, rule->keyset), 8170ca60948SSteen Hegelund vrule->id); 8180ca60948SSteen Hegelund goto out; 8190ca60948SSteen Hegelund } 8200ca60948SSteen Hegelund 8210ca60948SSteen Hegelund /* Some keysets do not have a type field, so ignore return value */ 8220ca60948SSteen Hegelund vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask); 8230ca60948SSteen Hegelund 8240ca60948SSteen Hegelund err = vcap_set_rule_set_actionset(vrule, erule->actionset); 8250ca60948SSteen Hegelund if (err) 8260ca60948SSteen Hegelund goto out; 8270ca60948SSteen Hegelund 8280ca60948SSteen Hegelund err = sparx5_tc_add_rule_counter(admin, vrule); 8290ca60948SSteen Hegelund if (err) 8300ca60948SSteen Hegelund goto out; 8310ca60948SSteen Hegelund 8320ca60948SSteen Hegelund err = vcap_val_rule(vrule, ETH_P_ALL); 8330ca60948SSteen Hegelund if (err) { 8340ca60948SSteen Hegelund pr_err("%s:%d: could not validate rule: %u\n", 8350ca60948SSteen Hegelund __func__, __LINE__, vrule->id); 8360ca60948SSteen Hegelund vcap_set_tc_exterr(fco, vrule); 8370ca60948SSteen Hegelund goto out; 8380ca60948SSteen Hegelund } 8390ca60948SSteen Hegelund err = vcap_add_rule(vrule); 8400ca60948SSteen Hegelund if (err) { 8410ca60948SSteen Hegelund pr_err("%s:%d: could not add rule: %u\n", 8420ca60948SSteen Hegelund __func__, __LINE__, vrule->id); 8430ca60948SSteen Hegelund goto out; 8440ca60948SSteen Hegelund } 8450ca60948SSteen Hegelund out: 8460ca60948SSteen Hegelund vcap_free_rule(vrule); 8470ca60948SSteen Hegelund return err; 8480ca60948SSteen Hegelund } 8490ca60948SSteen Hegelund 8500ca60948SSteen Hegelund static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl, 8510ca60948SSteen Hegelund struct flow_cls_offload *fco, 8520ca60948SSteen Hegelund struct vcap_rule *erule, 8530ca60948SSteen Hegelund struct vcap_admin *admin, 8540ca60948SSteen Hegelund struct sparx5_multiple_rules *multi) 8550ca60948SSteen Hegelund { 8560ca60948SSteen Hegelund int idx, err = 0; 8570ca60948SSteen Hegelund 8580ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 8590ca60948SSteen Hegelund if (!multi->rule[idx].selected) 8600ca60948SSteen Hegelund continue; 8610ca60948SSteen Hegelund 8620ca60948SSteen Hegelund err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin, 8630ca60948SSteen Hegelund &multi->rule[idx]); 8640ca60948SSteen Hegelund if (err) 8650ca60948SSteen Hegelund break; 8660ca60948SSteen Hegelund } 8670ca60948SSteen Hegelund return err; 8680ca60948SSteen Hegelund } 8690ca60948SSteen Hegelund 870542e6e2cSSteen Hegelund /* Add the actionset that is the default for the VCAP type */ 871542e6e2cSSteen Hegelund static int sparx5_tc_set_actionset(struct vcap_admin *admin, 872542e6e2cSSteen Hegelund struct vcap_rule *vrule) 873542e6e2cSSteen Hegelund { 874542e6e2cSSteen Hegelund enum vcap_actionfield_set aset; 875542e6e2cSSteen Hegelund int err = 0; 876542e6e2cSSteen Hegelund 877542e6e2cSSteen Hegelund switch (admin->vtype) { 878542e6e2cSSteen Hegelund case VCAP_TYPE_IS0: 879542e6e2cSSteen Hegelund aset = VCAP_AFS_CLASSIFICATION; 880542e6e2cSSteen Hegelund break; 881542e6e2cSSteen Hegelund case VCAP_TYPE_IS2: 882542e6e2cSSteen Hegelund aset = VCAP_AFS_BASE_TYPE; 883542e6e2cSSteen Hegelund break; 884542e6e2cSSteen Hegelund default: 885542e6e2cSSteen Hegelund return -EINVAL; 886542e6e2cSSteen Hegelund } 887542e6e2cSSteen Hegelund /* Do not overwrite any current actionset */ 888542e6e2cSSteen Hegelund if (vrule->actionset == VCAP_AFS_NO_VALUE) 889542e6e2cSSteen Hegelund err = vcap_set_rule_set_actionset(vrule, aset); 890542e6e2cSSteen Hegelund return err; 891542e6e2cSSteen Hegelund } 892542e6e2cSSteen Hegelund 89388bd9ea7SSteen Hegelund /* Add the VCAP key to match on for a rule target value */ 89488bd9ea7SSteen Hegelund static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin, 89588bd9ea7SSteen Hegelund struct vcap_rule *vrule, 89688bd9ea7SSteen Hegelund int target_cid) 89788bd9ea7SSteen Hegelund { 89888bd9ea7SSteen Hegelund int link_val = target_cid % VCAP_CID_LOOKUP_SIZE; 89988bd9ea7SSteen Hegelund int err; 90088bd9ea7SSteen Hegelund 90188bd9ea7SSteen Hegelund if (!link_val) 90288bd9ea7SSteen Hegelund return 0; 90388bd9ea7SSteen Hegelund 90488bd9ea7SSteen Hegelund switch (admin->vtype) { 90588bd9ea7SSteen Hegelund case VCAP_TYPE_IS0: 90688bd9ea7SSteen Hegelund /* Add NXT_IDX key for chaining rules between IS0 instances */ 90788bd9ea7SSteen Hegelund err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL, 90888bd9ea7SSteen Hegelund 1, /* enable */ 90988bd9ea7SSteen Hegelund ~0); 91088bd9ea7SSteen Hegelund if (err) 91188bd9ea7SSteen Hegelund return err; 91288bd9ea7SSteen Hegelund return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX, 91388bd9ea7SSteen Hegelund link_val, /* target */ 91488bd9ea7SSteen Hegelund ~0); 91588bd9ea7SSteen Hegelund case VCAP_TYPE_IS2: 91688bd9ea7SSteen Hegelund /* Add PAG key for chaining rules from IS0 */ 91788bd9ea7SSteen Hegelund return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG, 91888bd9ea7SSteen Hegelund link_val, /* target */ 91988bd9ea7SSteen Hegelund ~0); 92088bd9ea7SSteen Hegelund default: 92188bd9ea7SSteen Hegelund break; 92288bd9ea7SSteen Hegelund } 92388bd9ea7SSteen Hegelund return 0; 92488bd9ea7SSteen Hegelund } 92588bd9ea7SSteen Hegelund 92688bd9ea7SSteen Hegelund /* Add the VCAP action that adds a target value to a rule */ 92788bd9ea7SSteen Hegelund static int sparx5_tc_add_rule_link(struct vcap_control *vctrl, 92888bd9ea7SSteen Hegelund struct vcap_admin *admin, 92988bd9ea7SSteen Hegelund struct vcap_rule *vrule, 93088bd9ea7SSteen Hegelund int from_cid, int to_cid) 93188bd9ea7SSteen Hegelund { 93288bd9ea7SSteen Hegelund struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid); 93388bd9ea7SSteen Hegelund int diff, err = 0; 93488bd9ea7SSteen Hegelund 93588bd9ea7SSteen Hegelund diff = vcap_chain_offset(vctrl, from_cid, to_cid); 93688bd9ea7SSteen Hegelund if (!(to_admin && diff > 0)) { 93788bd9ea7SSteen Hegelund pr_err("%s:%d: unsupported chain direction: %d\n", 93888bd9ea7SSteen Hegelund __func__, __LINE__, to_cid); 93988bd9ea7SSteen Hegelund return -EINVAL; 94088bd9ea7SSteen Hegelund } 94188bd9ea7SSteen Hegelund if (admin->vtype == VCAP_TYPE_IS0 && 94288bd9ea7SSteen Hegelund to_admin->vtype == VCAP_TYPE_IS0) { 94388bd9ea7SSteen Hegelund /* Between IS0 instances the G_IDX value is used */ 94488bd9ea7SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff); 94588bd9ea7SSteen Hegelund if (err) 94688bd9ea7SSteen Hegelund goto out; 94788bd9ea7SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL, 94888bd9ea7SSteen Hegelund 1); /* Replace */ 94988bd9ea7SSteen Hegelund if (err) 95088bd9ea7SSteen Hegelund goto out; 95188bd9ea7SSteen Hegelund } else if (admin->vtype == VCAP_TYPE_IS0 && 95288bd9ea7SSteen Hegelund to_admin->vtype == VCAP_TYPE_IS2) { 95388bd9ea7SSteen Hegelund /* Between IS0 and IS2 the PAG value is used */ 95488bd9ea7SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff); 95588bd9ea7SSteen Hegelund if (err) 95688bd9ea7SSteen Hegelund goto out; 95788bd9ea7SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 95888bd9ea7SSteen Hegelund VCAP_AF_PAG_OVERRIDE_MASK, 95988bd9ea7SSteen Hegelund 0xff); 96088bd9ea7SSteen Hegelund if (err) 96188bd9ea7SSteen Hegelund goto out; 96288bd9ea7SSteen Hegelund } else { 96388bd9ea7SSteen Hegelund pr_err("%s:%d: unsupported chain destination: %d\n", 96488bd9ea7SSteen Hegelund __func__, __LINE__, to_cid); 96588bd9ea7SSteen Hegelund err = -EOPNOTSUPP; 96688bd9ea7SSteen Hegelund } 96788bd9ea7SSteen Hegelund out: 96888bd9ea7SSteen Hegelund return err; 96988bd9ea7SSteen Hegelund } 97088bd9ea7SSteen Hegelund 971c9da1ac1SSteen Hegelund static int sparx5_tc_flower_replace(struct net_device *ndev, 972c9da1ac1SSteen Hegelund struct flow_cls_offload *fco, 973c9da1ac1SSteen Hegelund struct vcap_admin *admin) 974c9da1ac1SSteen Hegelund { 975c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 9760ca60948SSteen Hegelund struct sparx5_multiple_rules multi = {}; 977c9da1ac1SSteen Hegelund struct flow_action_entry *act; 978c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 979c9da1ac1SSteen Hegelund struct flow_rule *frule; 980c9da1ac1SSteen Hegelund struct vcap_rule *vrule; 981abc4010dSSteen Hegelund u16 l3_proto; 982c9da1ac1SSteen Hegelund int err, idx; 983c9da1ac1SSteen Hegelund 984c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 985392d0ab0SSteen Hegelund 986784c3067SSteen Hegelund err = sparx5_tc_flower_action_check(vctrl, ndev, fco); 987392d0ab0SSteen Hegelund if (err) 988392d0ab0SSteen Hegelund return err; 989392d0ab0SSteen Hegelund 990c9da1ac1SSteen Hegelund vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC, 991c9da1ac1SSteen Hegelund fco->common.prio, 0); 992c9da1ac1SSteen Hegelund if (IS_ERR(vrule)) 993c9da1ac1SSteen Hegelund return PTR_ERR(vrule); 994c9da1ac1SSteen Hegelund 995c9da1ac1SSteen Hegelund vrule->cookie = fco->cookie; 996bcddc196SSteen Hegelund 997bcddc196SSteen Hegelund l3_proto = ETH_P_ALL; 998bcddc196SSteen Hegelund err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto); 999bcddc196SSteen Hegelund if (err) 1000bcddc196SSteen Hegelund goto out; 100140e7fe18SSteen Hegelund 100240e7fe18SSteen Hegelund err = sparx5_tc_add_rule_counter(admin, vrule); 100340e7fe18SSteen Hegelund if (err) 100440e7fe18SSteen Hegelund goto out; 100540e7fe18SSteen Hegelund 100688bd9ea7SSteen Hegelund err = sparx5_tc_add_rule_link_target(admin, vrule, 100788bd9ea7SSteen Hegelund fco->common.chain_index); 100888bd9ea7SSteen Hegelund if (err) 100988bd9ea7SSteen Hegelund goto out; 101088bd9ea7SSteen Hegelund 1011392d0ab0SSteen Hegelund frule = flow_cls_offload_flow_rule(fco); 1012c9da1ac1SSteen Hegelund flow_action_for_each(idx, act, &frule->action) { 1013c9da1ac1SSteen Hegelund switch (act->id) { 1014c9da1ac1SSteen Hegelund case FLOW_ACTION_TRAP: 101588bd9ea7SSteen Hegelund if (admin->vtype != VCAP_TYPE_IS2) { 101688bd9ea7SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 101788bd9ea7SSteen Hegelund "Trap action not supported in this VCAP"); 101888bd9ea7SSteen Hegelund err = -EOPNOTSUPP; 101988bd9ea7SSteen Hegelund goto out; 102088bd9ea7SSteen Hegelund } 1021c9da1ac1SSteen Hegelund err = vcap_rule_add_action_bit(vrule, 1022c9da1ac1SSteen Hegelund VCAP_AF_CPU_COPY_ENA, 1023c9da1ac1SSteen Hegelund VCAP_BIT_1); 1024c9da1ac1SSteen Hegelund if (err) 1025c9da1ac1SSteen Hegelund goto out; 1026c9da1ac1SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 1027c9da1ac1SSteen Hegelund VCAP_AF_CPU_QUEUE_NUM, 0); 1028c9da1ac1SSteen Hegelund if (err) 1029c9da1ac1SSteen Hegelund goto out; 1030c9da1ac1SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, 1031c9da1ac1SSteen Hegelund SPX5_PMM_REPLACE_ALL); 1032c9da1ac1SSteen Hegelund if (err) 1033c9da1ac1SSteen Hegelund goto out; 1034c9da1ac1SSteen Hegelund break; 1035c9da1ac1SSteen Hegelund case FLOW_ACTION_ACCEPT: 1036542e6e2cSSteen Hegelund err = sparx5_tc_set_actionset(admin, vrule); 1037c9da1ac1SSteen Hegelund if (err) 1038c9da1ac1SSteen Hegelund goto out; 1039c9da1ac1SSteen Hegelund break; 1040392d0ab0SSteen Hegelund case FLOW_ACTION_GOTO: 1041542e6e2cSSteen Hegelund err = sparx5_tc_set_actionset(admin, vrule); 1042542e6e2cSSteen Hegelund if (err) 1043542e6e2cSSteen Hegelund goto out; 104488bd9ea7SSteen Hegelund sparx5_tc_add_rule_link(vctrl, admin, vrule, 104588bd9ea7SSteen Hegelund fco->common.chain_index, 104688bd9ea7SSteen Hegelund act->chain_index); 1047392d0ab0SSteen Hegelund break; 1048c9da1ac1SSteen Hegelund default: 1049c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1050c9da1ac1SSteen Hegelund "Unsupported TC action"); 1051c9da1ac1SSteen Hegelund err = -EOPNOTSUPP; 1052c9da1ac1SSteen Hegelund goto out; 1053c9da1ac1SSteen Hegelund } 1054c9da1ac1SSteen Hegelund } 10550ca60948SSteen Hegelund 10560ca60948SSteen Hegelund err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, l3_proto, 10570ca60948SSteen Hegelund &multi); 10580ca60948SSteen Hegelund if (err) { 10590ca60948SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 10600ca60948SSteen Hegelund "No matching port keyset for filter protocol and keys"); 10610ca60948SSteen Hegelund goto out; 10620ca60948SSteen Hegelund } 10630ca60948SSteen Hegelund 1064abc4010dSSteen Hegelund /* provide the l3 protocol to guide the keyset selection */ 1065abc4010dSSteen Hegelund err = vcap_val_rule(vrule, l3_proto); 1066c9da1ac1SSteen Hegelund if (err) { 1067c9da1ac1SSteen Hegelund vcap_set_tc_exterr(fco, vrule); 1068c9da1ac1SSteen Hegelund goto out; 1069c9da1ac1SSteen Hegelund } 1070c9da1ac1SSteen Hegelund err = vcap_add_rule(vrule); 1071c9da1ac1SSteen Hegelund if (err) 1072c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1073c9da1ac1SSteen Hegelund "Could not add the filter"); 10740ca60948SSteen Hegelund 10750ca60948SSteen Hegelund if (l3_proto == ETH_P_ALL) 10760ca60948SSteen Hegelund err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin, 10770ca60948SSteen Hegelund &multi); 10780ca60948SSteen Hegelund 1079c9da1ac1SSteen Hegelund out: 1080c9da1ac1SSteen Hegelund vcap_free_rule(vrule); 1081c9da1ac1SSteen Hegelund return err; 1082c9da1ac1SSteen Hegelund } 1083c9da1ac1SSteen Hegelund 1084c9da1ac1SSteen Hegelund static int sparx5_tc_flower_destroy(struct net_device *ndev, 1085c9da1ac1SSteen Hegelund struct flow_cls_offload *fco, 1086c9da1ac1SSteen Hegelund struct vcap_admin *admin) 1087c9da1ac1SSteen Hegelund { 1088c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 1089c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 1090c9da1ac1SSteen Hegelund int err = -ENOENT, rule_id; 1091c9da1ac1SSteen Hegelund 1092c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 1093c9da1ac1SSteen Hegelund while (true) { 1094c9da1ac1SSteen Hegelund rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie); 1095c9da1ac1SSteen Hegelund if (rule_id <= 0) 1096c9da1ac1SSteen Hegelund break; 1097c9da1ac1SSteen Hegelund err = vcap_del_rule(vctrl, ndev, rule_id); 1098c9da1ac1SSteen Hegelund if (err) { 1099c9da1ac1SSteen Hegelund pr_err("%s:%d: could not delete rule %d\n", 1100c9da1ac1SSteen Hegelund __func__, __LINE__, rule_id); 1101c9da1ac1SSteen Hegelund break; 1102c9da1ac1SSteen Hegelund } 1103c9da1ac1SSteen Hegelund } 1104c9da1ac1SSteen Hegelund return err; 1105c9da1ac1SSteen Hegelund } 1106c9da1ac1SSteen Hegelund 110740e7fe18SSteen Hegelund static int sparx5_tc_flower_stats(struct net_device *ndev, 110840e7fe18SSteen Hegelund struct flow_cls_offload *fco, 110940e7fe18SSteen Hegelund struct vcap_admin *admin) 111040e7fe18SSteen Hegelund { 111140e7fe18SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 111227d293ccSSteen Hegelund struct vcap_counter ctr = {}; 111340e7fe18SSteen Hegelund struct vcap_control *vctrl; 111440e7fe18SSteen Hegelund ulong lastused = 0; 111540e7fe18SSteen Hegelund int err; 111640e7fe18SSteen Hegelund 111740e7fe18SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 111827d293ccSSteen Hegelund err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie); 111940e7fe18SSteen Hegelund if (err) 112040e7fe18SSteen Hegelund return err; 112127d293ccSSteen Hegelund flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused, 112240e7fe18SSteen Hegelund FLOW_ACTION_HW_STATS_IMMEDIATE); 112340e7fe18SSteen Hegelund return err; 112440e7fe18SSteen Hegelund } 112540e7fe18SSteen Hegelund 1126c9da1ac1SSteen Hegelund int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, 1127c9da1ac1SSteen Hegelund bool ingress) 1128c9da1ac1SSteen Hegelund { 1129c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 1130c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 1131c9da1ac1SSteen Hegelund struct vcap_admin *admin; 1132c9da1ac1SSteen Hegelund int err = -EINVAL; 1133c9da1ac1SSteen Hegelund 1134c9da1ac1SSteen Hegelund /* Get vcap instance from the chain id */ 1135c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 1136c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, fco->common.chain_index); 1137c9da1ac1SSteen Hegelund if (!admin) { 1138c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain"); 1139c9da1ac1SSteen Hegelund return err; 1140c9da1ac1SSteen Hegelund } 1141c9da1ac1SSteen Hegelund 1142c9da1ac1SSteen Hegelund switch (fco->command) { 1143c9da1ac1SSteen Hegelund case FLOW_CLS_REPLACE: 1144c9da1ac1SSteen Hegelund return sparx5_tc_flower_replace(ndev, fco, admin); 1145c9da1ac1SSteen Hegelund case FLOW_CLS_DESTROY: 1146c9da1ac1SSteen Hegelund return sparx5_tc_flower_destroy(ndev, fco, admin); 114740e7fe18SSteen Hegelund case FLOW_CLS_STATS: 114840e7fe18SSteen Hegelund return sparx5_tc_flower_stats(ndev, fco, admin); 1149c9da1ac1SSteen Hegelund default: 1150c9da1ac1SSteen Hegelund return -EOPNOTSUPP; 1151c9da1ac1SSteen Hegelund } 1152c9da1ac1SSteen Hegelund } 1153