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; 33d6c2964dSSteen Hegelund u16 l3_proto; 34d6c2964dSSteen Hegelund u8 l4_proto; 35c9da1ac1SSteen Hegelund unsigned int used_keys; 36c9da1ac1SSteen Hegelund }; 37c9da1ac1SSteen Hegelund 3840e7fe18SSteen Hegelund struct sparx5_tc_rule_pkt_cnt { 3940e7fe18SSteen Hegelund u64 cookie; 4040e7fe18SSteen Hegelund u32 pkts; 4140e7fe18SSteen Hegelund }; 4240e7fe18SSteen Hegelund 43d6c2964dSSteen Hegelund /* These protocols have dedicated keysets in IS2 and a TC dissector 44d6c2964dSSteen Hegelund * ETH_P_ARP does not have a TC dissector 45d6c2964dSSteen Hegelund */ 46d6c2964dSSteen Hegelund static u16 sparx5_tc_known_etypes[] = { 47d6c2964dSSteen Hegelund ETH_P_ALL, 483a344f99SSteen Hegelund ETH_P_ARP, 49d6c2964dSSteen Hegelund ETH_P_IP, 50d6c2964dSSteen Hegelund ETH_P_IPV6, 51d6c2964dSSteen Hegelund }; 52d6c2964dSSteen Hegelund 533a344f99SSteen Hegelund enum sparx5_is2_arp_opcode { 543a344f99SSteen Hegelund SPX5_IS2_ARP_REQUEST, 553a344f99SSteen Hegelund SPX5_IS2_ARP_REPLY, 563a344f99SSteen Hegelund SPX5_IS2_RARP_REQUEST, 573a344f99SSteen Hegelund SPX5_IS2_RARP_REPLY, 583a344f99SSteen Hegelund }; 593a344f99SSteen Hegelund 603a344f99SSteen Hegelund enum tc_arp_opcode { 613a344f99SSteen Hegelund TC_ARP_OP_RESERVED, 623a344f99SSteen Hegelund TC_ARP_OP_REQUEST, 633a344f99SSteen Hegelund TC_ARP_OP_REPLY, 643a344f99SSteen Hegelund }; 653a344f99SSteen Hegelund 66d6c2964dSSteen Hegelund static bool sparx5_tc_is_known_etype(u16 etype) 67d6c2964dSSteen Hegelund { 68d6c2964dSSteen Hegelund int idx; 69d6c2964dSSteen Hegelund 70d6c2964dSSteen Hegelund /* For now this only knows about IS2 traffic classification */ 71d6c2964dSSteen Hegelund for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_known_etypes); ++idx) 72d6c2964dSSteen Hegelund if (sparx5_tc_known_etypes[idx] == etype) 73d6c2964dSSteen Hegelund return true; 74d6c2964dSSteen Hegelund 75d6c2964dSSteen Hegelund return false; 76d6c2964dSSteen Hegelund } 77d6c2964dSSteen Hegelund 78c9da1ac1SSteen Hegelund static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st) 79c9da1ac1SSteen Hegelund { 80c9da1ac1SSteen Hegelund enum vcap_key_field smac_key = VCAP_KF_L2_SMAC; 81c9da1ac1SSteen Hegelund enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC; 82c9da1ac1SSteen Hegelund struct flow_match_eth_addrs match; 83c9da1ac1SSteen Hegelund struct vcap_u48_key smac, dmac; 84c9da1ac1SSteen Hegelund int err = 0; 85c9da1ac1SSteen Hegelund 86c9da1ac1SSteen Hegelund flow_rule_match_eth_addrs(st->frule, &match); 87c9da1ac1SSteen Hegelund 88c9da1ac1SSteen Hegelund if (!is_zero_ether_addr(match.mask->src)) { 89c9da1ac1SSteen Hegelund vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN); 90c9da1ac1SSteen Hegelund vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN); 91c9da1ac1SSteen Hegelund err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac); 92c9da1ac1SSteen Hegelund if (err) 93c9da1ac1SSteen Hegelund goto out; 94c9da1ac1SSteen Hegelund } 95c9da1ac1SSteen Hegelund 96c9da1ac1SSteen Hegelund if (!is_zero_ether_addr(match.mask->dst)) { 97c9da1ac1SSteen Hegelund vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN); 98c9da1ac1SSteen Hegelund vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN); 99c9da1ac1SSteen Hegelund err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac); 100c9da1ac1SSteen Hegelund if (err) 101c9da1ac1SSteen Hegelund goto out; 102c9da1ac1SSteen Hegelund } 103c9da1ac1SSteen Hegelund 104c9da1ac1SSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS); 105c9da1ac1SSteen Hegelund 106c9da1ac1SSteen Hegelund return err; 107c9da1ac1SSteen Hegelund 108c9da1ac1SSteen Hegelund out: 109c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error"); 110c9da1ac1SSteen Hegelund return err; 111c9da1ac1SSteen Hegelund } 112c9da1ac1SSteen Hegelund 113d6c2964dSSteen Hegelund static int 114d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ipv4_usage(struct sparx5_tc_flower_parse_usage *st) 115d6c2964dSSteen Hegelund { 116d6c2964dSSteen Hegelund int err = 0; 117d6c2964dSSteen Hegelund 118d6c2964dSSteen Hegelund if (st->l3_proto == ETH_P_IP) { 119d6c2964dSSteen Hegelund struct flow_match_ipv4_addrs mt; 120d6c2964dSSteen Hegelund 121d6c2964dSSteen Hegelund flow_rule_match_ipv4_addrs(st->frule, &mt); 122d6c2964dSSteen Hegelund if (mt.mask->src) { 123d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 124d6c2964dSSteen Hegelund VCAP_KF_L3_IP4_SIP, 125d6c2964dSSteen Hegelund be32_to_cpu(mt.key->src), 126d6c2964dSSteen Hegelund be32_to_cpu(mt.mask->src)); 127d6c2964dSSteen Hegelund if (err) 128d6c2964dSSteen Hegelund goto out; 129d6c2964dSSteen Hegelund } 130d6c2964dSSteen Hegelund if (mt.mask->dst) { 131d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 132d6c2964dSSteen Hegelund VCAP_KF_L3_IP4_DIP, 133d6c2964dSSteen Hegelund be32_to_cpu(mt.key->dst), 134d6c2964dSSteen Hegelund be32_to_cpu(mt.mask->dst)); 135d6c2964dSSteen Hegelund if (err) 136d6c2964dSSteen Hegelund goto out; 137d6c2964dSSteen Hegelund } 138d6c2964dSSteen Hegelund } 139d6c2964dSSteen Hegelund 140d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS); 141d6c2964dSSteen Hegelund 142d6c2964dSSteen Hegelund return err; 143d6c2964dSSteen Hegelund 144d6c2964dSSteen Hegelund out: 145d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error"); 146d6c2964dSSteen Hegelund return err; 147d6c2964dSSteen Hegelund } 148d6c2964dSSteen Hegelund 149d6c2964dSSteen Hegelund static int 150d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ipv6_usage(struct sparx5_tc_flower_parse_usage *st) 151d6c2964dSSteen Hegelund { 152d6c2964dSSteen Hegelund int err = 0; 153d6c2964dSSteen Hegelund 154d6c2964dSSteen Hegelund if (st->l3_proto == ETH_P_IPV6) { 155d6c2964dSSteen Hegelund struct flow_match_ipv6_addrs mt; 156d6c2964dSSteen Hegelund struct vcap_u128_key sip; 157d6c2964dSSteen Hegelund struct vcap_u128_key dip; 158d6c2964dSSteen Hegelund 159d6c2964dSSteen Hegelund flow_rule_match_ipv6_addrs(st->frule, &mt); 160d6c2964dSSteen Hegelund /* Check if address masks are non-zero */ 161d6c2964dSSteen Hegelund if (!ipv6_addr_any(&mt.mask->src)) { 162d6c2964dSSteen Hegelund vcap_netbytes_copy(sip.value, mt.key->src.s6_addr, 16); 163d6c2964dSSteen Hegelund vcap_netbytes_copy(sip.mask, mt.mask->src.s6_addr, 16); 164d6c2964dSSteen Hegelund err = vcap_rule_add_key_u128(st->vrule, 165d6c2964dSSteen Hegelund VCAP_KF_L3_IP6_SIP, &sip); 166d6c2964dSSteen Hegelund if (err) 167d6c2964dSSteen Hegelund goto out; 168d6c2964dSSteen Hegelund } 169d6c2964dSSteen Hegelund if (!ipv6_addr_any(&mt.mask->dst)) { 170d6c2964dSSteen Hegelund vcap_netbytes_copy(dip.value, mt.key->dst.s6_addr, 16); 171d6c2964dSSteen Hegelund vcap_netbytes_copy(dip.mask, mt.mask->dst.s6_addr, 16); 172d6c2964dSSteen Hegelund err = vcap_rule_add_key_u128(st->vrule, 173d6c2964dSSteen Hegelund VCAP_KF_L3_IP6_DIP, &dip); 174d6c2964dSSteen Hegelund if (err) 175d6c2964dSSteen Hegelund goto out; 176d6c2964dSSteen Hegelund } 177d6c2964dSSteen Hegelund } 178d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS); 179d6c2964dSSteen Hegelund return err; 180d6c2964dSSteen Hegelund out: 181d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error"); 182d6c2964dSSteen Hegelund return err; 183d6c2964dSSteen Hegelund } 184d6c2964dSSteen Hegelund 185d6c2964dSSteen Hegelund static int 186d6c2964dSSteen Hegelund sparx5_tc_flower_handler_control_usage(struct sparx5_tc_flower_parse_usage *st) 187d6c2964dSSteen Hegelund { 188d6c2964dSSteen Hegelund struct flow_match_control mt; 189d6c2964dSSteen Hegelund u32 value, mask; 190d6c2964dSSteen Hegelund int err = 0; 191d6c2964dSSteen Hegelund 192d6c2964dSSteen Hegelund flow_rule_match_control(st->frule, &mt); 193d6c2964dSSteen Hegelund 194d6c2964dSSteen Hegelund if (mt.mask->flags) { 195d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) { 196d6c2964dSSteen Hegelund if (mt.key->flags & FLOW_DIS_FIRST_FRAG) { 197d6c2964dSSteen Hegelund value = 1; /* initial fragment */ 198d6c2964dSSteen Hegelund mask = 0x3; 199d6c2964dSSteen Hegelund } else { 200d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { 201d6c2964dSSteen Hegelund value = 3; /* follow up fragment */ 202d6c2964dSSteen Hegelund mask = 0x3; 203d6c2964dSSteen Hegelund } else { 204d6c2964dSSteen Hegelund value = 0; /* no fragment */ 205d6c2964dSSteen Hegelund mask = 0x3; 206d6c2964dSSteen Hegelund } 207d6c2964dSSteen Hegelund } 208d6c2964dSSteen Hegelund } else { 209d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { 210d6c2964dSSteen Hegelund value = 3; /* follow up fragment */ 211d6c2964dSSteen Hegelund mask = 0x3; 212d6c2964dSSteen Hegelund } else { 213d6c2964dSSteen Hegelund value = 0; /* no fragment */ 214d6c2964dSSteen Hegelund mask = 0x3; 215d6c2964dSSteen Hegelund } 216d6c2964dSSteen Hegelund } 217d6c2964dSSteen Hegelund 218d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 219d6c2964dSSteen Hegelund VCAP_KF_L3_FRAGMENT_TYPE, 220d6c2964dSSteen Hegelund value, mask); 221d6c2964dSSteen Hegelund if (err) 222d6c2964dSSteen Hegelund goto out; 223d6c2964dSSteen Hegelund } 224d6c2964dSSteen Hegelund 225d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL); 226d6c2964dSSteen Hegelund 227d6c2964dSSteen Hegelund return err; 228d6c2964dSSteen Hegelund 229d6c2964dSSteen Hegelund out: 230d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); 231d6c2964dSSteen Hegelund return err; 232d6c2964dSSteen Hegelund } 233d6c2964dSSteen Hegelund 234d6c2964dSSteen Hegelund static int 235d6c2964dSSteen Hegelund sparx5_tc_flower_handler_portnum_usage(struct sparx5_tc_flower_parse_usage *st) 236d6c2964dSSteen Hegelund { 237d6c2964dSSteen Hegelund struct flow_match_ports mt; 238d6c2964dSSteen Hegelund u16 value, mask; 239d6c2964dSSteen Hegelund int err = 0; 240d6c2964dSSteen Hegelund 241d6c2964dSSteen Hegelund flow_rule_match_ports(st->frule, &mt); 242d6c2964dSSteen Hegelund 243d6c2964dSSteen Hegelund if (mt.mask->src) { 244d6c2964dSSteen Hegelund value = be16_to_cpu(mt.key->src); 245d6c2964dSSteen Hegelund mask = be16_to_cpu(mt.mask->src); 246d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_SPORT, value, 247d6c2964dSSteen Hegelund mask); 248d6c2964dSSteen Hegelund if (err) 249d6c2964dSSteen Hegelund goto out; 250d6c2964dSSteen Hegelund } 251d6c2964dSSteen Hegelund 252d6c2964dSSteen Hegelund if (mt.mask->dst) { 253d6c2964dSSteen Hegelund value = be16_to_cpu(mt.key->dst); 254d6c2964dSSteen Hegelund mask = be16_to_cpu(mt.mask->dst); 255d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_DPORT, value, 256d6c2964dSSteen Hegelund mask); 257d6c2964dSSteen Hegelund if (err) 258d6c2964dSSteen Hegelund goto out; 259d6c2964dSSteen Hegelund } 260d6c2964dSSteen Hegelund 261d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS); 262d6c2964dSSteen Hegelund 263d6c2964dSSteen Hegelund return err; 264d6c2964dSSteen Hegelund 265d6c2964dSSteen Hegelund out: 266d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error"); 267d6c2964dSSteen Hegelund return err; 268d6c2964dSSteen Hegelund } 269d6c2964dSSteen Hegelund 270d6c2964dSSteen Hegelund static int 271d6c2964dSSteen Hegelund sparx5_tc_flower_handler_basic_usage(struct sparx5_tc_flower_parse_usage *st) 272d6c2964dSSteen Hegelund { 273d6c2964dSSteen Hegelund struct flow_match_basic mt; 274d6c2964dSSteen Hegelund int err = 0; 275d6c2964dSSteen Hegelund 276d6c2964dSSteen Hegelund flow_rule_match_basic(st->frule, &mt); 277d6c2964dSSteen Hegelund 278d6c2964dSSteen Hegelund if (mt.mask->n_proto) { 279d6c2964dSSteen Hegelund st->l3_proto = be16_to_cpu(mt.key->n_proto); 280d6c2964dSSteen Hegelund if (!sparx5_tc_is_known_etype(st->l3_proto)) { 281d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, 282d6c2964dSSteen Hegelund st->l3_proto, ~0); 283d6c2964dSSteen Hegelund if (err) 284d6c2964dSSteen Hegelund goto out; 285d6c2964dSSteen Hegelund } else if (st->l3_proto == ETH_P_IP) { 286d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 287d6c2964dSSteen Hegelund VCAP_BIT_1); 288d6c2964dSSteen Hegelund if (err) 289d6c2964dSSteen Hegelund goto out; 290d6c2964dSSteen Hegelund } else if (st->l3_proto == ETH_P_IPV6) { 291d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 292d6c2964dSSteen Hegelund VCAP_BIT_0); 293d6c2964dSSteen Hegelund if (err) 294d6c2964dSSteen Hegelund goto out; 295d6c2964dSSteen Hegelund } 296d6c2964dSSteen Hegelund } 297d6c2964dSSteen Hegelund 298d6c2964dSSteen Hegelund if (mt.mask->ip_proto) { 299d6c2964dSSteen Hegelund st->l4_proto = mt.key->ip_proto; 300d6c2964dSSteen Hegelund if (st->l4_proto == IPPROTO_TCP) { 301d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, 302d6c2964dSSteen Hegelund VCAP_KF_TCP_IS, 303d6c2964dSSteen Hegelund VCAP_BIT_1); 304d6c2964dSSteen Hegelund if (err) 305d6c2964dSSteen Hegelund goto out; 306d6c2964dSSteen Hegelund } else if (st->l4_proto == IPPROTO_UDP) { 307d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, 308d6c2964dSSteen Hegelund VCAP_KF_TCP_IS, 309d6c2964dSSteen Hegelund VCAP_BIT_0); 310d6c2964dSSteen Hegelund if (err) 311d6c2964dSSteen Hegelund goto out; 312d6c2964dSSteen Hegelund } else { 313d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 314d6c2964dSSteen Hegelund VCAP_KF_L3_IP_PROTO, 315d6c2964dSSteen Hegelund st->l4_proto, ~0); 316d6c2964dSSteen Hegelund if (err) 317d6c2964dSSteen Hegelund goto out; 318d6c2964dSSteen Hegelund } 319d6c2964dSSteen Hegelund } 320d6c2964dSSteen Hegelund 321d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC); 322d6c2964dSSteen Hegelund 323d6c2964dSSteen Hegelund return err; 324d6c2964dSSteen Hegelund 325d6c2964dSSteen Hegelund out: 326d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error"); 327d6c2964dSSteen Hegelund return err; 328d6c2964dSSteen Hegelund } 329d6c2964dSSteen Hegelund 330d6c2964dSSteen Hegelund static int 331d6c2964dSSteen Hegelund sparx5_tc_flower_handler_vlan_usage(struct sparx5_tc_flower_parse_usage *st) 332d6c2964dSSteen Hegelund { 333d6c2964dSSteen Hegelund enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS; 334d6c2964dSSteen Hegelund enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS; 335d6c2964dSSteen Hegelund struct flow_match_vlan mt; 336d6c2964dSSteen Hegelund int err; 337d6c2964dSSteen Hegelund 338d6c2964dSSteen Hegelund flow_rule_match_vlan(st->frule, &mt); 339d6c2964dSSteen Hegelund 340d6c2964dSSteen Hegelund if (mt.mask->vlan_id) { 341d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, vid_key, 342d6c2964dSSteen Hegelund mt.key->vlan_id, 343d6c2964dSSteen Hegelund mt.mask->vlan_id); 344d6c2964dSSteen Hegelund if (err) 345d6c2964dSSteen Hegelund goto out; 346d6c2964dSSteen Hegelund } 347d6c2964dSSteen Hegelund 348d6c2964dSSteen Hegelund if (mt.mask->vlan_priority) { 349d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, pcp_key, 350d6c2964dSSteen Hegelund mt.key->vlan_priority, 351d6c2964dSSteen Hegelund mt.mask->vlan_priority); 352d6c2964dSSteen Hegelund if (err) 353d6c2964dSSteen Hegelund goto out; 354d6c2964dSSteen Hegelund } 355d6c2964dSSteen Hegelund 356d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN); 357d6c2964dSSteen Hegelund 3584e9a6139SDan Carpenter return 0; 359d6c2964dSSteen Hegelund out: 360d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error"); 361d6c2964dSSteen Hegelund return err; 362d6c2964dSSteen Hegelund } 363d6c2964dSSteen Hegelund 364d6c2964dSSteen Hegelund static int 365d6c2964dSSteen Hegelund sparx5_tc_flower_handler_tcp_usage(struct sparx5_tc_flower_parse_usage *st) 366d6c2964dSSteen Hegelund { 367d6c2964dSSteen Hegelund struct flow_match_tcp mt; 368d6c2964dSSteen Hegelund u16 tcp_flags_mask; 369d6c2964dSSteen Hegelund u16 tcp_flags_key; 370d6c2964dSSteen Hegelund enum vcap_bit val; 371d6c2964dSSteen Hegelund int err = 0; 372d6c2964dSSteen Hegelund 373d6c2964dSSteen Hegelund flow_rule_match_tcp(st->frule, &mt); 374d6c2964dSSteen Hegelund tcp_flags_key = be16_to_cpu(mt.key->flags); 375d6c2964dSSteen Hegelund tcp_flags_mask = be16_to_cpu(mt.mask->flags); 376d6c2964dSSteen Hegelund 377d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_FIN) { 378d6c2964dSSteen Hegelund val = VCAP_BIT_0; 379d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_FIN) 380d6c2964dSSteen Hegelund val = VCAP_BIT_1; 381d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_FIN, val); 382d6c2964dSSteen Hegelund if (err) 383d6c2964dSSteen Hegelund goto out; 384d6c2964dSSteen Hegelund } 385d6c2964dSSteen Hegelund 386d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_SYN) { 387d6c2964dSSteen Hegelund val = VCAP_BIT_0; 388d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_SYN) 389d6c2964dSSteen Hegelund val = VCAP_BIT_1; 390d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_SYN, val); 391d6c2964dSSteen Hegelund if (err) 392d6c2964dSSteen Hegelund goto out; 393d6c2964dSSteen Hegelund } 394d6c2964dSSteen Hegelund 395d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_RST) { 396d6c2964dSSteen Hegelund val = VCAP_BIT_0; 397d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_RST) 398d6c2964dSSteen Hegelund val = VCAP_BIT_1; 399d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_RST, val); 400d6c2964dSSteen Hegelund if (err) 401d6c2964dSSteen Hegelund goto out; 402d6c2964dSSteen Hegelund } 403d6c2964dSSteen Hegelund 404d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_PSH) { 405d6c2964dSSteen Hegelund val = VCAP_BIT_0; 406d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_PSH) 407d6c2964dSSteen Hegelund val = VCAP_BIT_1; 408d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_PSH, val); 409d6c2964dSSteen Hegelund if (err) 410d6c2964dSSteen Hegelund goto out; 411d6c2964dSSteen Hegelund } 412d6c2964dSSteen Hegelund 413d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_ACK) { 414d6c2964dSSteen Hegelund val = VCAP_BIT_0; 415d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_ACK) 416d6c2964dSSteen Hegelund val = VCAP_BIT_1; 417d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_ACK, val); 418d6c2964dSSteen Hegelund if (err) 419d6c2964dSSteen Hegelund goto out; 420d6c2964dSSteen Hegelund } 421d6c2964dSSteen Hegelund 422d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_URG) { 423d6c2964dSSteen Hegelund val = VCAP_BIT_0; 424d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_URG) 425d6c2964dSSteen Hegelund val = VCAP_BIT_1; 426d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_URG, val); 427d6c2964dSSteen Hegelund if (err) 428d6c2964dSSteen Hegelund goto out; 429d6c2964dSSteen Hegelund } 430d6c2964dSSteen Hegelund 431d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP); 432d6c2964dSSteen Hegelund 433d6c2964dSSteen Hegelund return err; 434d6c2964dSSteen Hegelund 435d6c2964dSSteen Hegelund out: 436d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error"); 437d6c2964dSSteen Hegelund return err; 438d6c2964dSSteen Hegelund } 439d6c2964dSSteen Hegelund 440d6c2964dSSteen Hegelund static int 4413a344f99SSteen Hegelund sparx5_tc_flower_handler_arp_usage(struct sparx5_tc_flower_parse_usage *st) 4423a344f99SSteen Hegelund { 4433a344f99SSteen Hegelund struct flow_match_arp mt; 4443a344f99SSteen Hegelund u16 value, mask; 4453a344f99SSteen Hegelund u32 ipval, ipmsk; 4463a344f99SSteen Hegelund int err; 4473a344f99SSteen Hegelund 4483a344f99SSteen Hegelund flow_rule_match_arp(st->frule, &mt); 4493a344f99SSteen Hegelund 4503a344f99SSteen Hegelund if (mt.mask->op) { 4513a344f99SSteen Hegelund mask = 0x3; 4523a344f99SSteen Hegelund if (st->l3_proto == ETH_P_ARP) { 4533a344f99SSteen Hegelund value = mt.key->op == TC_ARP_OP_REQUEST ? 4543a344f99SSteen Hegelund SPX5_IS2_ARP_REQUEST : 4553a344f99SSteen Hegelund SPX5_IS2_ARP_REPLY; 4563a344f99SSteen Hegelund } else { /* RARP */ 4573a344f99SSteen Hegelund value = mt.key->op == TC_ARP_OP_REQUEST ? 4583a344f99SSteen Hegelund SPX5_IS2_RARP_REQUEST : 4593a344f99SSteen Hegelund SPX5_IS2_RARP_REPLY; 4603a344f99SSteen Hegelund } 4613a344f99SSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ARP_OPCODE, 4623a344f99SSteen Hegelund value, mask); 4633a344f99SSteen Hegelund if (err) 4643a344f99SSteen Hegelund goto out; 4653a344f99SSteen Hegelund } 4663a344f99SSteen Hegelund 4673a344f99SSteen Hegelund /* The IS2 ARP keyset does not support ARP hardware addresses */ 4683a344f99SSteen Hegelund if (!is_zero_ether_addr(mt.mask->sha) || 4694e9a6139SDan Carpenter !is_zero_ether_addr(mt.mask->tha)) { 4704e9a6139SDan Carpenter err = -EINVAL; 4713a344f99SSteen Hegelund goto out; 4724e9a6139SDan Carpenter } 4733a344f99SSteen Hegelund 4743a344f99SSteen Hegelund if (mt.mask->sip) { 4753a344f99SSteen Hegelund ipval = be32_to_cpu((__force __be32)mt.key->sip); 4763a344f99SSteen Hegelund ipmsk = be32_to_cpu((__force __be32)mt.mask->sip); 4773a344f99SSteen Hegelund 4783a344f99SSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_SIP, 4793a344f99SSteen Hegelund ipval, ipmsk); 4803a344f99SSteen Hegelund if (err) 4813a344f99SSteen Hegelund goto out; 4823a344f99SSteen Hegelund } 4833a344f99SSteen Hegelund 4843a344f99SSteen Hegelund if (mt.mask->tip) { 4853a344f99SSteen Hegelund ipval = be32_to_cpu((__force __be32)mt.key->tip); 4863a344f99SSteen Hegelund ipmsk = be32_to_cpu((__force __be32)mt.mask->tip); 4873a344f99SSteen Hegelund 4883a344f99SSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_DIP, 4893a344f99SSteen Hegelund ipval, ipmsk); 4903a344f99SSteen Hegelund if (err) 4913a344f99SSteen Hegelund goto out; 4923a344f99SSteen Hegelund } 4933a344f99SSteen Hegelund 4943a344f99SSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ARP); 4953a344f99SSteen Hegelund 4964e9a6139SDan Carpenter return 0; 4973a344f99SSteen Hegelund 4983a344f99SSteen Hegelund out: 4993a344f99SSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error"); 5003a344f99SSteen Hegelund return err; 5013a344f99SSteen Hegelund } 5023a344f99SSteen Hegelund 5033a344f99SSteen Hegelund static int 504d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ip_usage(struct sparx5_tc_flower_parse_usage *st) 505d6c2964dSSteen Hegelund { 506d6c2964dSSteen Hegelund struct flow_match_ip mt; 507d6c2964dSSteen Hegelund int err = 0; 508d6c2964dSSteen Hegelund 509d6c2964dSSteen Hegelund flow_rule_match_ip(st->frule, &mt); 510d6c2964dSSteen Hegelund 511d6c2964dSSteen Hegelund if (mt.mask->tos) { 512d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_TOS, 513d6c2964dSSteen Hegelund mt.key->tos, 514d6c2964dSSteen Hegelund mt.mask->tos); 515d6c2964dSSteen Hegelund if (err) 516d6c2964dSSteen Hegelund goto out; 517d6c2964dSSteen Hegelund } 518d6c2964dSSteen Hegelund 519d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IP); 520d6c2964dSSteen Hegelund 521d6c2964dSSteen Hegelund return err; 522d6c2964dSSteen Hegelund 523d6c2964dSSteen Hegelund out: 524d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error"); 525d6c2964dSSteen Hegelund return err; 526d6c2964dSSteen Hegelund } 527d6c2964dSSteen Hegelund 528c9da1ac1SSteen Hegelund static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = { 529c9da1ac1SSteen Hegelund [FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage, 530d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = sparx5_tc_flower_handler_ipv4_usage, 531d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = sparx5_tc_flower_handler_ipv6_usage, 532d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage, 533d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_PORTS] = sparx5_tc_flower_handler_portnum_usage, 534d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage, 535d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage, 536d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_TCP] = sparx5_tc_flower_handler_tcp_usage, 5373a344f99SSteen Hegelund [FLOW_DISSECTOR_KEY_ARP] = sparx5_tc_flower_handler_arp_usage, 538d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IP] = sparx5_tc_flower_handler_ip_usage, 539c9da1ac1SSteen Hegelund }; 540c9da1ac1SSteen Hegelund 541c9da1ac1SSteen Hegelund static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, 542c9da1ac1SSteen Hegelund struct vcap_admin *admin, 543abc4010dSSteen Hegelund struct vcap_rule *vrule, 544abc4010dSSteen Hegelund u16 *l3_proto) 545c9da1ac1SSteen Hegelund { 546c9da1ac1SSteen Hegelund struct sparx5_tc_flower_parse_usage state = { 547c9da1ac1SSteen Hegelund .fco = fco, 548c9da1ac1SSteen Hegelund .vrule = vrule, 549abc4010dSSteen Hegelund .l3_proto = ETH_P_ALL, 550c9da1ac1SSteen Hegelund }; 551c9da1ac1SSteen Hegelund int idx, err = 0; 552c9da1ac1SSteen Hegelund 553c9da1ac1SSteen Hegelund state.frule = flow_cls_offload_flow_rule(fco); 554c9da1ac1SSteen Hegelund for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) { 555c9da1ac1SSteen Hegelund if (!flow_rule_match_key(state.frule, idx)) 556c9da1ac1SSteen Hegelund continue; 557c9da1ac1SSteen Hegelund if (!sparx5_tc_flower_usage_handlers[idx]) 558c9da1ac1SSteen Hegelund continue; 559c9da1ac1SSteen Hegelund err = sparx5_tc_flower_usage_handlers[idx](&state); 560c9da1ac1SSteen Hegelund if (err) 561c9da1ac1SSteen Hegelund return err; 562c9da1ac1SSteen Hegelund } 563abc4010dSSteen Hegelund 564abc4010dSSteen Hegelund if (state.frule->match.dissector->used_keys ^ state.used_keys) { 565abc4010dSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 566abc4010dSSteen Hegelund "Unsupported match item"); 567abc4010dSSteen Hegelund return -ENOENT; 568abc4010dSSteen Hegelund } 569abc4010dSSteen Hegelund 570abc4010dSSteen Hegelund if (l3_proto) 571abc4010dSSteen Hegelund *l3_proto = state.l3_proto; 572c9da1ac1SSteen Hegelund return err; 573c9da1ac1SSteen Hegelund } 574c9da1ac1SSteen Hegelund 575392d0ab0SSteen Hegelund static int sparx5_tc_flower_action_check(struct vcap_control *vctrl, 576*784c3067SSteen Hegelund struct net_device *ndev, 577*784c3067SSteen Hegelund struct flow_cls_offload *fco) 578392d0ab0SSteen Hegelund { 579392d0ab0SSteen Hegelund struct flow_rule *rule = flow_cls_offload_flow_rule(fco); 580392d0ab0SSteen Hegelund struct flow_action_entry *actent, *last_actent = NULL; 581392d0ab0SSteen Hegelund struct flow_action *act = &rule->action; 582392d0ab0SSteen Hegelund u64 action_mask = 0; 583392d0ab0SSteen Hegelund int idx; 584392d0ab0SSteen Hegelund 585392d0ab0SSteen Hegelund if (!flow_action_has_entries(act)) { 586392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); 587392d0ab0SSteen Hegelund return -EINVAL; 588392d0ab0SSteen Hegelund } 589392d0ab0SSteen Hegelund 590392d0ab0SSteen Hegelund if (!flow_action_basic_hw_stats_check(act, fco->common.extack)) 591392d0ab0SSteen Hegelund return -EOPNOTSUPP; 592392d0ab0SSteen Hegelund 593392d0ab0SSteen Hegelund flow_action_for_each(idx, actent, act) { 594392d0ab0SSteen Hegelund if (action_mask & BIT(actent->id)) { 595392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 596392d0ab0SSteen Hegelund "More actions of the same type"); 597392d0ab0SSteen Hegelund return -EINVAL; 598392d0ab0SSteen Hegelund } 599392d0ab0SSteen Hegelund action_mask |= BIT(actent->id); 600392d0ab0SSteen Hegelund last_actent = actent; /* Save last action for later check */ 601392d0ab0SSteen Hegelund } 602392d0ab0SSteen Hegelund 603*784c3067SSteen Hegelund /* Check if last action is a goto 604*784c3067SSteen Hegelund * The last chain/lookup does not need to have a goto action 605*784c3067SSteen Hegelund */ 606*784c3067SSteen Hegelund if (last_actent->id == FLOW_ACTION_GOTO) { 607*784c3067SSteen Hegelund /* Check if the destination chain is in one of the VCAPs */ 608392d0ab0SSteen Hegelund if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 609392d0ab0SSteen Hegelund last_actent->chain_index)) { 610392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 611392d0ab0SSteen Hegelund "Invalid goto chain"); 612392d0ab0SSteen Hegelund return -EINVAL; 613392d0ab0SSteen Hegelund } 614*784c3067SSteen Hegelund } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) { 615*784c3067SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 616*784c3067SSteen Hegelund "Last action must be 'goto'"); 617*784c3067SSteen Hegelund return -EINVAL; 618*784c3067SSteen Hegelund } 619392d0ab0SSteen Hegelund 620392d0ab0SSteen Hegelund /* Catch unsupported combinations of actions */ 621392d0ab0SSteen Hegelund if (action_mask & BIT(FLOW_ACTION_TRAP) && 622392d0ab0SSteen Hegelund action_mask & BIT(FLOW_ACTION_ACCEPT)) { 623392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 624392d0ab0SSteen Hegelund "Cannot combine pass and trap action"); 625392d0ab0SSteen Hegelund return -EOPNOTSUPP; 626392d0ab0SSteen Hegelund } 627392d0ab0SSteen Hegelund 628392d0ab0SSteen Hegelund return 0; 629392d0ab0SSteen Hegelund } 630392d0ab0SSteen Hegelund 63140e7fe18SSteen Hegelund /* Add a rule counter action - only IS2 is considered for now */ 63240e7fe18SSteen Hegelund static int sparx5_tc_add_rule_counter(struct vcap_admin *admin, 63340e7fe18SSteen Hegelund struct vcap_rule *vrule) 63440e7fe18SSteen Hegelund { 63540e7fe18SSteen Hegelund int err; 63640e7fe18SSteen Hegelund 6370ca60948SSteen Hegelund err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID, vrule->id); 63840e7fe18SSteen Hegelund if (err) 63940e7fe18SSteen Hegelund return err; 64040e7fe18SSteen Hegelund 64140e7fe18SSteen Hegelund vcap_rule_set_counter_id(vrule, vrule->id); 64240e7fe18SSteen Hegelund return err; 64340e7fe18SSteen Hegelund } 64440e7fe18SSteen Hegelund 6450ca60948SSteen Hegelund /* Collect all port keysets and apply the first of them, possibly wildcarded */ 6460ca60948SSteen Hegelund static int sparx5_tc_select_protocol_keyset(struct net_device *ndev, 6470ca60948SSteen Hegelund struct vcap_rule *vrule, 6480ca60948SSteen Hegelund struct vcap_admin *admin, 6490ca60948SSteen Hegelund u16 l3_proto, 6500ca60948SSteen Hegelund struct sparx5_multiple_rules *multi) 6510ca60948SSteen Hegelund { 6520ca60948SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 6530ca60948SSteen Hegelund struct vcap_keyset_list portkeysetlist = {}; 6540ca60948SSteen Hegelund enum vcap_keyfield_set portkeysets[10] = {}; 6550ca60948SSteen Hegelund struct vcap_keyset_list matches = {}; 6560ca60948SSteen Hegelund enum vcap_keyfield_set keysets[10]; 6570ca60948SSteen Hegelund int idx, jdx, err = 0, count = 0; 6580ca60948SSteen Hegelund struct sparx5_wildcard_rule *mru; 6590ca60948SSteen Hegelund const struct vcap_set *kinfo; 6600ca60948SSteen Hegelund struct vcap_control *vctrl; 6610ca60948SSteen Hegelund 6620ca60948SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 6630ca60948SSteen Hegelund 6640ca60948SSteen Hegelund /* Find the keysets that the rule can use */ 6650ca60948SSteen Hegelund matches.keysets = keysets; 6660ca60948SSteen Hegelund matches.max = ARRAY_SIZE(keysets); 6670ca60948SSteen Hegelund if (vcap_rule_find_keysets(vrule, &matches) == 0) 6680ca60948SSteen Hegelund return -EINVAL; 6690ca60948SSteen Hegelund 6700ca60948SSteen Hegelund /* Find the keysets that the port configuration supports */ 6710ca60948SSteen Hegelund portkeysetlist.max = ARRAY_SIZE(portkeysets); 6720ca60948SSteen Hegelund portkeysetlist.keysets = portkeysets; 6730ca60948SSteen Hegelund err = sparx5_vcap_get_port_keyset(ndev, 6740ca60948SSteen Hegelund admin, vrule->vcap_chain_id, 6750ca60948SSteen Hegelund l3_proto, 6760ca60948SSteen Hegelund &portkeysetlist); 6770ca60948SSteen Hegelund if (err) 6780ca60948SSteen Hegelund return err; 6790ca60948SSteen Hegelund 6800ca60948SSteen Hegelund /* Find the intersection of the two sets of keyset */ 6810ca60948SSteen Hegelund for (idx = 0; idx < portkeysetlist.cnt; ++idx) { 6820ca60948SSteen Hegelund kinfo = vcap_keyfieldset(vctrl, admin->vtype, 6830ca60948SSteen Hegelund portkeysetlist.keysets[idx]); 6840ca60948SSteen Hegelund if (!kinfo) 6850ca60948SSteen Hegelund continue; 6860ca60948SSteen Hegelund 6870ca60948SSteen Hegelund /* Find a port keyset that matches the required keys 6880ca60948SSteen Hegelund * If there are multiple keysets then compose a type id mask 6890ca60948SSteen Hegelund */ 6900ca60948SSteen Hegelund for (jdx = 0; jdx < matches.cnt; ++jdx) { 6910ca60948SSteen Hegelund if (portkeysetlist.keysets[idx] != matches.keysets[jdx]) 6920ca60948SSteen Hegelund continue; 6930ca60948SSteen Hegelund 6940ca60948SSteen Hegelund mru = &multi->rule[kinfo->sw_per_item]; 6950ca60948SSteen Hegelund if (!mru->selected) { 6960ca60948SSteen Hegelund mru->selected = true; 6970ca60948SSteen Hegelund mru->keyset = portkeysetlist.keysets[idx]; 6980ca60948SSteen Hegelund mru->value = kinfo->type_id; 6990ca60948SSteen Hegelund } 7000ca60948SSteen Hegelund mru->value &= kinfo->type_id; 7010ca60948SSteen Hegelund mru->mask |= kinfo->type_id; 7020ca60948SSteen Hegelund ++count; 7030ca60948SSteen Hegelund } 7040ca60948SSteen Hegelund } 7050ca60948SSteen Hegelund if (count == 0) 7060ca60948SSteen Hegelund return -EPROTO; 7070ca60948SSteen Hegelund 7080ca60948SSteen Hegelund if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt) 7090ca60948SSteen Hegelund return -ENOENT; 7100ca60948SSteen Hegelund 7110ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 7120ca60948SSteen Hegelund mru = &multi->rule[idx]; 7130ca60948SSteen Hegelund if (!mru->selected) 7140ca60948SSteen Hegelund continue; 7150ca60948SSteen Hegelund 7160ca60948SSteen Hegelund /* Align the mask to the combined value */ 7170ca60948SSteen Hegelund mru->mask ^= mru->value; 7180ca60948SSteen Hegelund } 7190ca60948SSteen Hegelund 7200ca60948SSteen Hegelund /* Set the chosen keyset on the rule and set a wildcarded type if there 7210ca60948SSteen Hegelund * are more than one keyset 7220ca60948SSteen Hegelund */ 7230ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 7240ca60948SSteen Hegelund mru = &multi->rule[idx]; 7250ca60948SSteen Hegelund if (!mru->selected) 7260ca60948SSteen Hegelund continue; 7270ca60948SSteen Hegelund 7280ca60948SSteen Hegelund vcap_set_rule_set_keyset(vrule, mru->keyset); 7290ca60948SSteen Hegelund if (count > 1) 7300ca60948SSteen Hegelund /* Some keysets do not have a type field */ 7310ca60948SSteen Hegelund vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, 7320ca60948SSteen Hegelund mru->value, 7330ca60948SSteen Hegelund ~mru->mask); 7340ca60948SSteen Hegelund mru->selected = false; /* mark as done */ 7350ca60948SSteen Hegelund break; /* Stop here and add more rules later */ 7360ca60948SSteen Hegelund } 7370ca60948SSteen Hegelund return err; 7380ca60948SSteen Hegelund } 7390ca60948SSteen Hegelund 7400ca60948SSteen Hegelund static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl, 7410ca60948SSteen Hegelund struct flow_cls_offload *fco, 7420ca60948SSteen Hegelund struct vcap_rule *erule, 7430ca60948SSteen Hegelund struct vcap_admin *admin, 7440ca60948SSteen Hegelund struct sparx5_wildcard_rule *rule) 7450ca60948SSteen Hegelund { 7460ca60948SSteen Hegelund enum vcap_key_field keylist[] = { 7470ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK, 7480ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK_SEL, 7490ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK_RNG, 7500ca60948SSteen Hegelund VCAP_KF_LOOKUP_FIRST_IS, 7510ca60948SSteen Hegelund VCAP_KF_TYPE, 7520ca60948SSteen Hegelund }; 7530ca60948SSteen Hegelund struct vcap_rule *vrule; 7540ca60948SSteen Hegelund int err; 7550ca60948SSteen Hegelund 7560ca60948SSteen Hegelund /* Add an extra rule with a special user and the new keyset */ 7570ca60948SSteen Hegelund erule->user = VCAP_USER_TC_EXTRA; 7580ca60948SSteen Hegelund vrule = vcap_copy_rule(erule); 7590ca60948SSteen Hegelund if (IS_ERR(vrule)) 7600ca60948SSteen Hegelund return PTR_ERR(vrule); 7610ca60948SSteen Hegelund 7620ca60948SSteen Hegelund /* Link the new rule to the existing rule with the cookie */ 7630ca60948SSteen Hegelund vrule->cookie = erule->cookie; 7640ca60948SSteen Hegelund vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true); 7650ca60948SSteen Hegelund err = vcap_set_rule_set_keyset(vrule, rule->keyset); 7660ca60948SSteen Hegelund if (err) { 7670ca60948SSteen Hegelund pr_err("%s:%d: could not set keyset %s in rule: %u\n", 7680ca60948SSteen Hegelund __func__, __LINE__, 7690ca60948SSteen Hegelund vcap_keyset_name(vctrl, rule->keyset), 7700ca60948SSteen Hegelund vrule->id); 7710ca60948SSteen Hegelund goto out; 7720ca60948SSteen Hegelund } 7730ca60948SSteen Hegelund 7740ca60948SSteen Hegelund /* Some keysets do not have a type field, so ignore return value */ 7750ca60948SSteen Hegelund vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask); 7760ca60948SSteen Hegelund 7770ca60948SSteen Hegelund err = vcap_set_rule_set_actionset(vrule, erule->actionset); 7780ca60948SSteen Hegelund if (err) 7790ca60948SSteen Hegelund goto out; 7800ca60948SSteen Hegelund 7810ca60948SSteen Hegelund err = sparx5_tc_add_rule_counter(admin, vrule); 7820ca60948SSteen Hegelund if (err) 7830ca60948SSteen Hegelund goto out; 7840ca60948SSteen Hegelund 7850ca60948SSteen Hegelund err = vcap_val_rule(vrule, ETH_P_ALL); 7860ca60948SSteen Hegelund if (err) { 7870ca60948SSteen Hegelund pr_err("%s:%d: could not validate rule: %u\n", 7880ca60948SSteen Hegelund __func__, __LINE__, vrule->id); 7890ca60948SSteen Hegelund vcap_set_tc_exterr(fco, vrule); 7900ca60948SSteen Hegelund goto out; 7910ca60948SSteen Hegelund } 7920ca60948SSteen Hegelund err = vcap_add_rule(vrule); 7930ca60948SSteen Hegelund if (err) { 7940ca60948SSteen Hegelund pr_err("%s:%d: could not add rule: %u\n", 7950ca60948SSteen Hegelund __func__, __LINE__, vrule->id); 7960ca60948SSteen Hegelund goto out; 7970ca60948SSteen Hegelund } 7980ca60948SSteen Hegelund out: 7990ca60948SSteen Hegelund vcap_free_rule(vrule); 8000ca60948SSteen Hegelund return err; 8010ca60948SSteen Hegelund } 8020ca60948SSteen Hegelund 8030ca60948SSteen Hegelund static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl, 8040ca60948SSteen Hegelund struct flow_cls_offload *fco, 8050ca60948SSteen Hegelund struct vcap_rule *erule, 8060ca60948SSteen Hegelund struct vcap_admin *admin, 8070ca60948SSteen Hegelund struct sparx5_multiple_rules *multi) 8080ca60948SSteen Hegelund { 8090ca60948SSteen Hegelund int idx, err = 0; 8100ca60948SSteen Hegelund 8110ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 8120ca60948SSteen Hegelund if (!multi->rule[idx].selected) 8130ca60948SSteen Hegelund continue; 8140ca60948SSteen Hegelund 8150ca60948SSteen Hegelund err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin, 8160ca60948SSteen Hegelund &multi->rule[idx]); 8170ca60948SSteen Hegelund if (err) 8180ca60948SSteen Hegelund break; 8190ca60948SSteen Hegelund } 8200ca60948SSteen Hegelund return err; 8210ca60948SSteen Hegelund } 8220ca60948SSteen Hegelund 823c9da1ac1SSteen Hegelund static int sparx5_tc_flower_replace(struct net_device *ndev, 824c9da1ac1SSteen Hegelund struct flow_cls_offload *fco, 825c9da1ac1SSteen Hegelund struct vcap_admin *admin) 826c9da1ac1SSteen Hegelund { 827c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 8280ca60948SSteen Hegelund struct sparx5_multiple_rules multi = {}; 829c9da1ac1SSteen Hegelund struct flow_action_entry *act; 830c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 831c9da1ac1SSteen Hegelund struct flow_rule *frule; 832c9da1ac1SSteen Hegelund struct vcap_rule *vrule; 833abc4010dSSteen Hegelund u16 l3_proto; 834c9da1ac1SSteen Hegelund int err, idx; 835c9da1ac1SSteen Hegelund 836c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 837392d0ab0SSteen Hegelund 838*784c3067SSteen Hegelund err = sparx5_tc_flower_action_check(vctrl, ndev, fco); 839392d0ab0SSteen Hegelund if (err) 840392d0ab0SSteen Hegelund return err; 841392d0ab0SSteen Hegelund 842c9da1ac1SSteen Hegelund vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC, 843c9da1ac1SSteen Hegelund fco->common.prio, 0); 844c9da1ac1SSteen Hegelund if (IS_ERR(vrule)) 845c9da1ac1SSteen Hegelund return PTR_ERR(vrule); 846c9da1ac1SSteen Hegelund 847c9da1ac1SSteen Hegelund vrule->cookie = fco->cookie; 848bcddc196SSteen Hegelund 849bcddc196SSteen Hegelund l3_proto = ETH_P_ALL; 850bcddc196SSteen Hegelund err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto); 851bcddc196SSteen Hegelund if (err) 852bcddc196SSteen Hegelund goto out; 85340e7fe18SSteen Hegelund 85440e7fe18SSteen Hegelund err = sparx5_tc_add_rule_counter(admin, vrule); 85540e7fe18SSteen Hegelund if (err) 85640e7fe18SSteen Hegelund goto out; 85740e7fe18SSteen Hegelund 858392d0ab0SSteen Hegelund frule = flow_cls_offload_flow_rule(fco); 859c9da1ac1SSteen Hegelund flow_action_for_each(idx, act, &frule->action) { 860c9da1ac1SSteen Hegelund switch (act->id) { 861c9da1ac1SSteen Hegelund case FLOW_ACTION_TRAP: 862c9da1ac1SSteen Hegelund err = vcap_rule_add_action_bit(vrule, 863c9da1ac1SSteen Hegelund VCAP_AF_CPU_COPY_ENA, 864c9da1ac1SSteen Hegelund VCAP_BIT_1); 865c9da1ac1SSteen Hegelund if (err) 866c9da1ac1SSteen Hegelund goto out; 867c9da1ac1SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 868c9da1ac1SSteen Hegelund VCAP_AF_CPU_QUEUE_NUM, 0); 869c9da1ac1SSteen Hegelund if (err) 870c9da1ac1SSteen Hegelund goto out; 871c9da1ac1SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, 872c9da1ac1SSteen Hegelund SPX5_PMM_REPLACE_ALL); 873c9da1ac1SSteen Hegelund if (err) 874c9da1ac1SSteen Hegelund goto out; 875c9da1ac1SSteen Hegelund /* For now the actionset is hardcoded */ 876c9da1ac1SSteen Hegelund err = vcap_set_rule_set_actionset(vrule, 877c9da1ac1SSteen Hegelund VCAP_AFS_BASE_TYPE); 878c9da1ac1SSteen Hegelund if (err) 879c9da1ac1SSteen Hegelund goto out; 880c9da1ac1SSteen Hegelund break; 881c9da1ac1SSteen Hegelund case FLOW_ACTION_ACCEPT: 882c9da1ac1SSteen Hegelund /* For now the actionset is hardcoded */ 883c9da1ac1SSteen Hegelund err = vcap_set_rule_set_actionset(vrule, 884c9da1ac1SSteen Hegelund VCAP_AFS_BASE_TYPE); 885c9da1ac1SSteen Hegelund if (err) 886c9da1ac1SSteen Hegelund goto out; 887c9da1ac1SSteen Hegelund break; 888392d0ab0SSteen Hegelund case FLOW_ACTION_GOTO: 889392d0ab0SSteen Hegelund /* Links between VCAPs will be added later */ 890392d0ab0SSteen Hegelund break; 891c9da1ac1SSteen Hegelund default: 892c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 893c9da1ac1SSteen Hegelund "Unsupported TC action"); 894c9da1ac1SSteen Hegelund err = -EOPNOTSUPP; 895c9da1ac1SSteen Hegelund goto out; 896c9da1ac1SSteen Hegelund } 897c9da1ac1SSteen Hegelund } 8980ca60948SSteen Hegelund 8990ca60948SSteen Hegelund err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, l3_proto, 9000ca60948SSteen Hegelund &multi); 9010ca60948SSteen Hegelund if (err) { 9020ca60948SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 9030ca60948SSteen Hegelund "No matching port keyset for filter protocol and keys"); 9040ca60948SSteen Hegelund goto out; 9050ca60948SSteen Hegelund } 9060ca60948SSteen Hegelund 907abc4010dSSteen Hegelund /* provide the l3 protocol to guide the keyset selection */ 908abc4010dSSteen Hegelund err = vcap_val_rule(vrule, l3_proto); 909c9da1ac1SSteen Hegelund if (err) { 910c9da1ac1SSteen Hegelund vcap_set_tc_exterr(fco, vrule); 911c9da1ac1SSteen Hegelund goto out; 912c9da1ac1SSteen Hegelund } 913c9da1ac1SSteen Hegelund err = vcap_add_rule(vrule); 914c9da1ac1SSteen Hegelund if (err) 915c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 916c9da1ac1SSteen Hegelund "Could not add the filter"); 9170ca60948SSteen Hegelund 9180ca60948SSteen Hegelund if (l3_proto == ETH_P_ALL) 9190ca60948SSteen Hegelund err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin, 9200ca60948SSteen Hegelund &multi); 9210ca60948SSteen Hegelund 922c9da1ac1SSteen Hegelund out: 923c9da1ac1SSteen Hegelund vcap_free_rule(vrule); 924c9da1ac1SSteen Hegelund return err; 925c9da1ac1SSteen Hegelund } 926c9da1ac1SSteen Hegelund 927c9da1ac1SSteen Hegelund static int sparx5_tc_flower_destroy(struct net_device *ndev, 928c9da1ac1SSteen Hegelund struct flow_cls_offload *fco, 929c9da1ac1SSteen Hegelund struct vcap_admin *admin) 930c9da1ac1SSteen Hegelund { 931c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 932c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 933c9da1ac1SSteen Hegelund int err = -ENOENT, rule_id; 934c9da1ac1SSteen Hegelund 935c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 936c9da1ac1SSteen Hegelund while (true) { 937c9da1ac1SSteen Hegelund rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie); 938c9da1ac1SSteen Hegelund if (rule_id <= 0) 939c9da1ac1SSteen Hegelund break; 940c9da1ac1SSteen Hegelund err = vcap_del_rule(vctrl, ndev, rule_id); 941c9da1ac1SSteen Hegelund if (err) { 942c9da1ac1SSteen Hegelund pr_err("%s:%d: could not delete rule %d\n", 943c9da1ac1SSteen Hegelund __func__, __LINE__, rule_id); 944c9da1ac1SSteen Hegelund break; 945c9da1ac1SSteen Hegelund } 946c9da1ac1SSteen Hegelund } 947c9da1ac1SSteen Hegelund return err; 948c9da1ac1SSteen Hegelund } 949c9da1ac1SSteen Hegelund 95040e7fe18SSteen Hegelund /* Collect packet counts from all rules with the same cookie */ 95140e7fe18SSteen Hegelund static int sparx5_tc_rule_counter_cb(void *arg, struct vcap_rule *rule) 95240e7fe18SSteen Hegelund { 95340e7fe18SSteen Hegelund struct sparx5_tc_rule_pkt_cnt *rinfo = arg; 95440e7fe18SSteen Hegelund struct vcap_counter counter; 95540e7fe18SSteen Hegelund int err = 0; 95640e7fe18SSteen Hegelund 95740e7fe18SSteen Hegelund if (rule->cookie == rinfo->cookie) { 95840e7fe18SSteen Hegelund err = vcap_rule_get_counter(rule, &counter); 95940e7fe18SSteen Hegelund if (err) 96040e7fe18SSteen Hegelund return err; 96140e7fe18SSteen Hegelund rinfo->pkts += counter.value; 96240e7fe18SSteen Hegelund /* Reset the rule counter */ 96340e7fe18SSteen Hegelund counter.value = 0; 96440e7fe18SSteen Hegelund vcap_rule_set_counter(rule, &counter); 96540e7fe18SSteen Hegelund } 96640e7fe18SSteen Hegelund return err; 96740e7fe18SSteen Hegelund } 96840e7fe18SSteen Hegelund 96940e7fe18SSteen Hegelund static int sparx5_tc_flower_stats(struct net_device *ndev, 97040e7fe18SSteen Hegelund struct flow_cls_offload *fco, 97140e7fe18SSteen Hegelund struct vcap_admin *admin) 97240e7fe18SSteen Hegelund { 97340e7fe18SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 97440e7fe18SSteen Hegelund struct sparx5_tc_rule_pkt_cnt rinfo = {}; 97540e7fe18SSteen Hegelund struct vcap_control *vctrl; 97640e7fe18SSteen Hegelund ulong lastused = 0; 97740e7fe18SSteen Hegelund u64 drops = 0; 97840e7fe18SSteen Hegelund u32 pkts = 0; 97940e7fe18SSteen Hegelund int err; 98040e7fe18SSteen Hegelund 98140e7fe18SSteen Hegelund rinfo.cookie = fco->cookie; 98240e7fe18SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 98340e7fe18SSteen Hegelund err = vcap_rule_iter(vctrl, sparx5_tc_rule_counter_cb, &rinfo); 98440e7fe18SSteen Hegelund if (err) 98540e7fe18SSteen Hegelund return err; 98640e7fe18SSteen Hegelund pkts = rinfo.pkts; 98740e7fe18SSteen Hegelund flow_stats_update(&fco->stats, 0x0, pkts, drops, lastused, 98840e7fe18SSteen Hegelund FLOW_ACTION_HW_STATS_IMMEDIATE); 98940e7fe18SSteen Hegelund return err; 99040e7fe18SSteen Hegelund } 99140e7fe18SSteen Hegelund 992c9da1ac1SSteen Hegelund int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, 993c9da1ac1SSteen Hegelund bool ingress) 994c9da1ac1SSteen Hegelund { 995c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 996c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 997c9da1ac1SSteen Hegelund struct vcap_admin *admin; 998c9da1ac1SSteen Hegelund int err = -EINVAL; 999c9da1ac1SSteen Hegelund 1000c9da1ac1SSteen Hegelund /* Get vcap instance from the chain id */ 1001c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 1002c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, fco->common.chain_index); 1003c9da1ac1SSteen Hegelund if (!admin) { 1004c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain"); 1005c9da1ac1SSteen Hegelund return err; 1006c9da1ac1SSteen Hegelund } 1007c9da1ac1SSteen Hegelund 1008c9da1ac1SSteen Hegelund switch (fco->command) { 1009c9da1ac1SSteen Hegelund case FLOW_CLS_REPLACE: 1010c9da1ac1SSteen Hegelund return sparx5_tc_flower_replace(ndev, fco, admin); 1011c9da1ac1SSteen Hegelund case FLOW_CLS_DESTROY: 1012c9da1ac1SSteen Hegelund return sparx5_tc_flower_destroy(ndev, fco, admin); 101340e7fe18SSteen Hegelund case FLOW_CLS_STATS: 101440e7fe18SSteen Hegelund return sparx5_tc_flower_stats(ndev, fco, admin); 1015c9da1ac1SSteen Hegelund default: 1016c9da1ac1SSteen Hegelund return -EOPNOTSUPP; 1017c9da1ac1SSteen Hegelund } 1018c9da1ac1SSteen Hegelund } 1019