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 15c9da1ac1SSteen Hegelund struct sparx5_tc_flower_parse_usage { 16c9da1ac1SSteen Hegelund struct flow_cls_offload *fco; 17c9da1ac1SSteen Hegelund struct flow_rule *frule; 18c9da1ac1SSteen Hegelund struct vcap_rule *vrule; 19d6c2964dSSteen Hegelund u16 l3_proto; 20d6c2964dSSteen Hegelund u8 l4_proto; 21c9da1ac1SSteen Hegelund unsigned int used_keys; 22c9da1ac1SSteen Hegelund }; 23c9da1ac1SSteen Hegelund 24d6c2964dSSteen Hegelund /* These protocols have dedicated keysets in IS2 and a TC dissector 25d6c2964dSSteen Hegelund * ETH_P_ARP does not have a TC dissector 26d6c2964dSSteen Hegelund */ 27d6c2964dSSteen Hegelund static u16 sparx5_tc_known_etypes[] = { 28d6c2964dSSteen Hegelund ETH_P_ALL, 29d6c2964dSSteen Hegelund ETH_P_IP, 30d6c2964dSSteen Hegelund ETH_P_IPV6, 31d6c2964dSSteen Hegelund }; 32d6c2964dSSteen Hegelund 33d6c2964dSSteen Hegelund static bool sparx5_tc_is_known_etype(u16 etype) 34d6c2964dSSteen Hegelund { 35d6c2964dSSteen Hegelund int idx; 36d6c2964dSSteen Hegelund 37d6c2964dSSteen Hegelund /* For now this only knows about IS2 traffic classification */ 38d6c2964dSSteen Hegelund for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_known_etypes); ++idx) 39d6c2964dSSteen Hegelund if (sparx5_tc_known_etypes[idx] == etype) 40d6c2964dSSteen Hegelund return true; 41d6c2964dSSteen Hegelund 42d6c2964dSSteen Hegelund return false; 43d6c2964dSSteen Hegelund } 44d6c2964dSSteen Hegelund 45c9da1ac1SSteen Hegelund static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st) 46c9da1ac1SSteen Hegelund { 47c9da1ac1SSteen Hegelund enum vcap_key_field smac_key = VCAP_KF_L2_SMAC; 48c9da1ac1SSteen Hegelund enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC; 49c9da1ac1SSteen Hegelund struct flow_match_eth_addrs match; 50c9da1ac1SSteen Hegelund struct vcap_u48_key smac, dmac; 51c9da1ac1SSteen Hegelund int err = 0; 52c9da1ac1SSteen Hegelund 53c9da1ac1SSteen Hegelund flow_rule_match_eth_addrs(st->frule, &match); 54c9da1ac1SSteen Hegelund 55c9da1ac1SSteen Hegelund if (!is_zero_ether_addr(match.mask->src)) { 56c9da1ac1SSteen Hegelund vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN); 57c9da1ac1SSteen Hegelund vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN); 58c9da1ac1SSteen Hegelund err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac); 59c9da1ac1SSteen Hegelund if (err) 60c9da1ac1SSteen Hegelund goto out; 61c9da1ac1SSteen Hegelund } 62c9da1ac1SSteen Hegelund 63c9da1ac1SSteen Hegelund if (!is_zero_ether_addr(match.mask->dst)) { 64c9da1ac1SSteen Hegelund vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN); 65c9da1ac1SSteen Hegelund vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN); 66c9da1ac1SSteen Hegelund err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac); 67c9da1ac1SSteen Hegelund if (err) 68c9da1ac1SSteen Hegelund goto out; 69c9da1ac1SSteen Hegelund } 70c9da1ac1SSteen Hegelund 71c9da1ac1SSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS); 72c9da1ac1SSteen Hegelund 73c9da1ac1SSteen Hegelund return err; 74c9da1ac1SSteen Hegelund 75c9da1ac1SSteen Hegelund out: 76c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error"); 77c9da1ac1SSteen Hegelund return err; 78c9da1ac1SSteen Hegelund } 79c9da1ac1SSteen Hegelund 80d6c2964dSSteen Hegelund static int 81d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ipv4_usage(struct sparx5_tc_flower_parse_usage *st) 82d6c2964dSSteen Hegelund { 83d6c2964dSSteen Hegelund int err = 0; 84d6c2964dSSteen Hegelund 85d6c2964dSSteen Hegelund if (st->l3_proto == ETH_P_IP) { 86d6c2964dSSteen Hegelund struct flow_match_ipv4_addrs mt; 87d6c2964dSSteen Hegelund 88d6c2964dSSteen Hegelund flow_rule_match_ipv4_addrs(st->frule, &mt); 89d6c2964dSSteen Hegelund if (mt.mask->src) { 90d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 91d6c2964dSSteen Hegelund VCAP_KF_L3_IP4_SIP, 92d6c2964dSSteen Hegelund be32_to_cpu(mt.key->src), 93d6c2964dSSteen Hegelund be32_to_cpu(mt.mask->src)); 94d6c2964dSSteen Hegelund if (err) 95d6c2964dSSteen Hegelund goto out; 96d6c2964dSSteen Hegelund } 97d6c2964dSSteen Hegelund if (mt.mask->dst) { 98d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 99d6c2964dSSteen Hegelund VCAP_KF_L3_IP4_DIP, 100d6c2964dSSteen Hegelund be32_to_cpu(mt.key->dst), 101d6c2964dSSteen Hegelund be32_to_cpu(mt.mask->dst)); 102d6c2964dSSteen Hegelund if (err) 103d6c2964dSSteen Hegelund goto out; 104d6c2964dSSteen Hegelund } 105d6c2964dSSteen Hegelund } 106d6c2964dSSteen Hegelund 107d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS); 108d6c2964dSSteen Hegelund 109d6c2964dSSteen Hegelund return err; 110d6c2964dSSteen Hegelund 111d6c2964dSSteen Hegelund out: 112d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error"); 113d6c2964dSSteen Hegelund return err; 114d6c2964dSSteen Hegelund } 115d6c2964dSSteen Hegelund 116d6c2964dSSteen Hegelund static int 117d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ipv6_usage(struct sparx5_tc_flower_parse_usage *st) 118d6c2964dSSteen Hegelund { 119d6c2964dSSteen Hegelund int err = 0; 120d6c2964dSSteen Hegelund 121d6c2964dSSteen Hegelund if (st->l3_proto == ETH_P_IPV6) { 122d6c2964dSSteen Hegelund struct flow_match_ipv6_addrs mt; 123d6c2964dSSteen Hegelund struct vcap_u128_key sip; 124d6c2964dSSteen Hegelund struct vcap_u128_key dip; 125d6c2964dSSteen Hegelund 126d6c2964dSSteen Hegelund flow_rule_match_ipv6_addrs(st->frule, &mt); 127d6c2964dSSteen Hegelund /* Check if address masks are non-zero */ 128d6c2964dSSteen Hegelund if (!ipv6_addr_any(&mt.mask->src)) { 129d6c2964dSSteen Hegelund vcap_netbytes_copy(sip.value, mt.key->src.s6_addr, 16); 130d6c2964dSSteen Hegelund vcap_netbytes_copy(sip.mask, mt.mask->src.s6_addr, 16); 131d6c2964dSSteen Hegelund err = vcap_rule_add_key_u128(st->vrule, 132d6c2964dSSteen Hegelund VCAP_KF_L3_IP6_SIP, &sip); 133d6c2964dSSteen Hegelund if (err) 134d6c2964dSSteen Hegelund goto out; 135d6c2964dSSteen Hegelund } 136d6c2964dSSteen Hegelund if (!ipv6_addr_any(&mt.mask->dst)) { 137d6c2964dSSteen Hegelund vcap_netbytes_copy(dip.value, mt.key->dst.s6_addr, 16); 138d6c2964dSSteen Hegelund vcap_netbytes_copy(dip.mask, mt.mask->dst.s6_addr, 16); 139d6c2964dSSteen Hegelund err = vcap_rule_add_key_u128(st->vrule, 140d6c2964dSSteen Hegelund VCAP_KF_L3_IP6_DIP, &dip); 141d6c2964dSSteen Hegelund if (err) 142d6c2964dSSteen Hegelund goto out; 143d6c2964dSSteen Hegelund } 144d6c2964dSSteen Hegelund } 145d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS); 146d6c2964dSSteen Hegelund return err; 147d6c2964dSSteen Hegelund out: 148d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error"); 149d6c2964dSSteen Hegelund return err; 150d6c2964dSSteen Hegelund } 151d6c2964dSSteen Hegelund 152d6c2964dSSteen Hegelund static int 153d6c2964dSSteen Hegelund sparx5_tc_flower_handler_control_usage(struct sparx5_tc_flower_parse_usage *st) 154d6c2964dSSteen Hegelund { 155d6c2964dSSteen Hegelund struct flow_match_control mt; 156d6c2964dSSteen Hegelund u32 value, mask; 157d6c2964dSSteen Hegelund int err = 0; 158d6c2964dSSteen Hegelund 159d6c2964dSSteen Hegelund flow_rule_match_control(st->frule, &mt); 160d6c2964dSSteen Hegelund 161d6c2964dSSteen Hegelund if (mt.mask->flags) { 162d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) { 163d6c2964dSSteen Hegelund if (mt.key->flags & FLOW_DIS_FIRST_FRAG) { 164d6c2964dSSteen Hegelund value = 1; /* initial fragment */ 165d6c2964dSSteen Hegelund mask = 0x3; 166d6c2964dSSteen Hegelund } else { 167d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { 168d6c2964dSSteen Hegelund value = 3; /* follow up fragment */ 169d6c2964dSSteen Hegelund mask = 0x3; 170d6c2964dSSteen Hegelund } else { 171d6c2964dSSteen Hegelund value = 0; /* no fragment */ 172d6c2964dSSteen Hegelund mask = 0x3; 173d6c2964dSSteen Hegelund } 174d6c2964dSSteen Hegelund } 175d6c2964dSSteen Hegelund } else { 176d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { 177d6c2964dSSteen Hegelund value = 3; /* follow up fragment */ 178d6c2964dSSteen Hegelund mask = 0x3; 179d6c2964dSSteen Hegelund } else { 180d6c2964dSSteen Hegelund value = 0; /* no fragment */ 181d6c2964dSSteen Hegelund mask = 0x3; 182d6c2964dSSteen Hegelund } 183d6c2964dSSteen Hegelund } 184d6c2964dSSteen Hegelund 185d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 186d6c2964dSSteen Hegelund VCAP_KF_L3_FRAGMENT_TYPE, 187d6c2964dSSteen Hegelund value, mask); 188d6c2964dSSteen Hegelund if (err) 189d6c2964dSSteen Hegelund goto out; 190d6c2964dSSteen Hegelund } 191d6c2964dSSteen Hegelund 192d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL); 193d6c2964dSSteen Hegelund 194d6c2964dSSteen Hegelund return err; 195d6c2964dSSteen Hegelund 196d6c2964dSSteen Hegelund out: 197d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); 198d6c2964dSSteen Hegelund return err; 199d6c2964dSSteen Hegelund } 200d6c2964dSSteen Hegelund 201d6c2964dSSteen Hegelund static int 202d6c2964dSSteen Hegelund sparx5_tc_flower_handler_portnum_usage(struct sparx5_tc_flower_parse_usage *st) 203d6c2964dSSteen Hegelund { 204d6c2964dSSteen Hegelund struct flow_match_ports mt; 205d6c2964dSSteen Hegelund u16 value, mask; 206d6c2964dSSteen Hegelund int err = 0; 207d6c2964dSSteen Hegelund 208d6c2964dSSteen Hegelund flow_rule_match_ports(st->frule, &mt); 209d6c2964dSSteen Hegelund 210d6c2964dSSteen Hegelund if (mt.mask->src) { 211d6c2964dSSteen Hegelund value = be16_to_cpu(mt.key->src); 212d6c2964dSSteen Hegelund mask = be16_to_cpu(mt.mask->src); 213d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_SPORT, value, 214d6c2964dSSteen Hegelund mask); 215d6c2964dSSteen Hegelund if (err) 216d6c2964dSSteen Hegelund goto out; 217d6c2964dSSteen Hegelund } 218d6c2964dSSteen Hegelund 219d6c2964dSSteen Hegelund if (mt.mask->dst) { 220d6c2964dSSteen Hegelund value = be16_to_cpu(mt.key->dst); 221d6c2964dSSteen Hegelund mask = be16_to_cpu(mt.mask->dst); 222d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_DPORT, value, 223d6c2964dSSteen Hegelund mask); 224d6c2964dSSteen Hegelund if (err) 225d6c2964dSSteen Hegelund goto out; 226d6c2964dSSteen Hegelund } 227d6c2964dSSteen Hegelund 228d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS); 229d6c2964dSSteen Hegelund 230d6c2964dSSteen Hegelund return err; 231d6c2964dSSteen Hegelund 232d6c2964dSSteen Hegelund out: 233d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error"); 234d6c2964dSSteen Hegelund return err; 235d6c2964dSSteen Hegelund } 236d6c2964dSSteen Hegelund 237d6c2964dSSteen Hegelund static int 238d6c2964dSSteen Hegelund sparx5_tc_flower_handler_basic_usage(struct sparx5_tc_flower_parse_usage *st) 239d6c2964dSSteen Hegelund { 240d6c2964dSSteen Hegelund struct flow_match_basic mt; 241d6c2964dSSteen Hegelund int err = 0; 242d6c2964dSSteen Hegelund 243d6c2964dSSteen Hegelund flow_rule_match_basic(st->frule, &mt); 244d6c2964dSSteen Hegelund 245d6c2964dSSteen Hegelund if (mt.mask->n_proto) { 246d6c2964dSSteen Hegelund st->l3_proto = be16_to_cpu(mt.key->n_proto); 247d6c2964dSSteen Hegelund if (!sparx5_tc_is_known_etype(st->l3_proto)) { 248d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, 249d6c2964dSSteen Hegelund st->l3_proto, ~0); 250d6c2964dSSteen Hegelund if (err) 251d6c2964dSSteen Hegelund goto out; 252d6c2964dSSteen Hegelund } else if (st->l3_proto == ETH_P_IP) { 253d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 254d6c2964dSSteen Hegelund VCAP_BIT_1); 255d6c2964dSSteen Hegelund if (err) 256d6c2964dSSteen Hegelund goto out; 257d6c2964dSSteen Hegelund } else if (st->l3_proto == ETH_P_IPV6) { 258d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 259d6c2964dSSteen Hegelund VCAP_BIT_0); 260d6c2964dSSteen Hegelund if (err) 261d6c2964dSSteen Hegelund goto out; 262d6c2964dSSteen Hegelund } 263d6c2964dSSteen Hegelund } 264d6c2964dSSteen Hegelund 265d6c2964dSSteen Hegelund if (mt.mask->ip_proto) { 266d6c2964dSSteen Hegelund st->l4_proto = mt.key->ip_proto; 267d6c2964dSSteen Hegelund if (st->l4_proto == IPPROTO_TCP) { 268d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, 269d6c2964dSSteen Hegelund VCAP_KF_TCP_IS, 270d6c2964dSSteen Hegelund VCAP_BIT_1); 271d6c2964dSSteen Hegelund if (err) 272d6c2964dSSteen Hegelund goto out; 273d6c2964dSSteen Hegelund } else if (st->l4_proto == IPPROTO_UDP) { 274d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, 275d6c2964dSSteen Hegelund VCAP_KF_TCP_IS, 276d6c2964dSSteen Hegelund VCAP_BIT_0); 277d6c2964dSSteen Hegelund if (err) 278d6c2964dSSteen Hegelund goto out; 279d6c2964dSSteen Hegelund } else { 280d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 281d6c2964dSSteen Hegelund VCAP_KF_L3_IP_PROTO, 282d6c2964dSSteen Hegelund st->l4_proto, ~0); 283d6c2964dSSteen Hegelund if (err) 284d6c2964dSSteen Hegelund goto out; 285d6c2964dSSteen Hegelund } 286d6c2964dSSteen Hegelund } 287d6c2964dSSteen Hegelund 288d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC); 289d6c2964dSSteen Hegelund 290d6c2964dSSteen Hegelund return err; 291d6c2964dSSteen Hegelund 292d6c2964dSSteen Hegelund out: 293d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error"); 294d6c2964dSSteen Hegelund return err; 295d6c2964dSSteen Hegelund } 296d6c2964dSSteen Hegelund 297d6c2964dSSteen Hegelund static int 298d6c2964dSSteen Hegelund sparx5_tc_flower_handler_vlan_usage(struct sparx5_tc_flower_parse_usage *st) 299d6c2964dSSteen Hegelund { 300d6c2964dSSteen Hegelund enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS; 301d6c2964dSSteen Hegelund enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS; 302d6c2964dSSteen Hegelund struct flow_match_vlan mt; 303d6c2964dSSteen Hegelund int err; 304d6c2964dSSteen Hegelund 305d6c2964dSSteen Hegelund flow_rule_match_vlan(st->frule, &mt); 306d6c2964dSSteen Hegelund 307d6c2964dSSteen Hegelund if (mt.mask->vlan_id) { 308d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, vid_key, 309d6c2964dSSteen Hegelund mt.key->vlan_id, 310d6c2964dSSteen Hegelund mt.mask->vlan_id); 311d6c2964dSSteen Hegelund if (err) 312d6c2964dSSteen Hegelund goto out; 313d6c2964dSSteen Hegelund } 314d6c2964dSSteen Hegelund 315d6c2964dSSteen Hegelund if (mt.mask->vlan_priority) { 316d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, pcp_key, 317d6c2964dSSteen Hegelund mt.key->vlan_priority, 318d6c2964dSSteen Hegelund mt.mask->vlan_priority); 319d6c2964dSSteen Hegelund if (err) 320d6c2964dSSteen Hegelund goto out; 321d6c2964dSSteen Hegelund } 322d6c2964dSSteen Hegelund 323d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN); 324d6c2964dSSteen Hegelund 325d6c2964dSSteen Hegelund return err; 326d6c2964dSSteen Hegelund out: 327d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error"); 328d6c2964dSSteen Hegelund return err; 329d6c2964dSSteen Hegelund } 330d6c2964dSSteen Hegelund 331d6c2964dSSteen Hegelund static int 332d6c2964dSSteen Hegelund sparx5_tc_flower_handler_tcp_usage(struct sparx5_tc_flower_parse_usage *st) 333d6c2964dSSteen Hegelund { 334d6c2964dSSteen Hegelund struct flow_match_tcp mt; 335d6c2964dSSteen Hegelund u16 tcp_flags_mask; 336d6c2964dSSteen Hegelund u16 tcp_flags_key; 337d6c2964dSSteen Hegelund enum vcap_bit val; 338d6c2964dSSteen Hegelund int err = 0; 339d6c2964dSSteen Hegelund 340d6c2964dSSteen Hegelund flow_rule_match_tcp(st->frule, &mt); 341d6c2964dSSteen Hegelund tcp_flags_key = be16_to_cpu(mt.key->flags); 342d6c2964dSSteen Hegelund tcp_flags_mask = be16_to_cpu(mt.mask->flags); 343d6c2964dSSteen Hegelund 344d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_FIN) { 345d6c2964dSSteen Hegelund val = VCAP_BIT_0; 346d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_FIN) 347d6c2964dSSteen Hegelund val = VCAP_BIT_1; 348d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_FIN, val); 349d6c2964dSSteen Hegelund if (err) 350d6c2964dSSteen Hegelund goto out; 351d6c2964dSSteen Hegelund } 352d6c2964dSSteen Hegelund 353d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_SYN) { 354d6c2964dSSteen Hegelund val = VCAP_BIT_0; 355d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_SYN) 356d6c2964dSSteen Hegelund val = VCAP_BIT_1; 357d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_SYN, val); 358d6c2964dSSteen Hegelund if (err) 359d6c2964dSSteen Hegelund goto out; 360d6c2964dSSteen Hegelund } 361d6c2964dSSteen Hegelund 362d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_RST) { 363d6c2964dSSteen Hegelund val = VCAP_BIT_0; 364d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_RST) 365d6c2964dSSteen Hegelund val = VCAP_BIT_1; 366d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_RST, val); 367d6c2964dSSteen Hegelund if (err) 368d6c2964dSSteen Hegelund goto out; 369d6c2964dSSteen Hegelund } 370d6c2964dSSteen Hegelund 371d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_PSH) { 372d6c2964dSSteen Hegelund val = VCAP_BIT_0; 373d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_PSH) 374d6c2964dSSteen Hegelund val = VCAP_BIT_1; 375d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_PSH, val); 376d6c2964dSSteen Hegelund if (err) 377d6c2964dSSteen Hegelund goto out; 378d6c2964dSSteen Hegelund } 379d6c2964dSSteen Hegelund 380d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_ACK) { 381d6c2964dSSteen Hegelund val = VCAP_BIT_0; 382d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_ACK) 383d6c2964dSSteen Hegelund val = VCAP_BIT_1; 384d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_ACK, val); 385d6c2964dSSteen Hegelund if (err) 386d6c2964dSSteen Hegelund goto out; 387d6c2964dSSteen Hegelund } 388d6c2964dSSteen Hegelund 389d6c2964dSSteen Hegelund if (tcp_flags_mask & TCPHDR_URG) { 390d6c2964dSSteen Hegelund val = VCAP_BIT_0; 391d6c2964dSSteen Hegelund if (tcp_flags_key & TCPHDR_URG) 392d6c2964dSSteen Hegelund val = VCAP_BIT_1; 393d6c2964dSSteen Hegelund err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_URG, val); 394d6c2964dSSteen Hegelund if (err) 395d6c2964dSSteen Hegelund goto out; 396d6c2964dSSteen Hegelund } 397d6c2964dSSteen Hegelund 398d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP); 399d6c2964dSSteen Hegelund 400d6c2964dSSteen Hegelund return err; 401d6c2964dSSteen Hegelund 402d6c2964dSSteen Hegelund out: 403d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error"); 404d6c2964dSSteen Hegelund return err; 405d6c2964dSSteen Hegelund } 406d6c2964dSSteen Hegelund 407d6c2964dSSteen Hegelund static int 408d6c2964dSSteen Hegelund sparx5_tc_flower_handler_ip_usage(struct sparx5_tc_flower_parse_usage *st) 409d6c2964dSSteen Hegelund { 410d6c2964dSSteen Hegelund struct flow_match_ip mt; 411d6c2964dSSteen Hegelund int err = 0; 412d6c2964dSSteen Hegelund 413d6c2964dSSteen Hegelund flow_rule_match_ip(st->frule, &mt); 414d6c2964dSSteen Hegelund 415d6c2964dSSteen Hegelund if (mt.mask->tos) { 416d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_TOS, 417d6c2964dSSteen Hegelund mt.key->tos, 418d6c2964dSSteen Hegelund mt.mask->tos); 419d6c2964dSSteen Hegelund if (err) 420d6c2964dSSteen Hegelund goto out; 421d6c2964dSSteen Hegelund } 422d6c2964dSSteen Hegelund 423d6c2964dSSteen Hegelund st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IP); 424d6c2964dSSteen Hegelund 425d6c2964dSSteen Hegelund return err; 426d6c2964dSSteen Hegelund 427d6c2964dSSteen Hegelund out: 428d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error"); 429d6c2964dSSteen Hegelund return err; 430d6c2964dSSteen Hegelund } 431d6c2964dSSteen Hegelund 432c9da1ac1SSteen Hegelund static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = { 433c9da1ac1SSteen Hegelund [FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage, 434d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = sparx5_tc_flower_handler_ipv4_usage, 435d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = sparx5_tc_flower_handler_ipv6_usage, 436d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage, 437d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_PORTS] = sparx5_tc_flower_handler_portnum_usage, 438d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage, 439d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage, 440d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_TCP] = sparx5_tc_flower_handler_tcp_usage, 441d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_IP] = sparx5_tc_flower_handler_ip_usage, 442c9da1ac1SSteen Hegelund }; 443c9da1ac1SSteen Hegelund 444c9da1ac1SSteen Hegelund static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, 445c9da1ac1SSteen Hegelund struct vcap_admin *admin, 446*abc4010dSSteen Hegelund struct vcap_rule *vrule, 447*abc4010dSSteen Hegelund u16 *l3_proto) 448c9da1ac1SSteen Hegelund { 449c9da1ac1SSteen Hegelund struct sparx5_tc_flower_parse_usage state = { 450c9da1ac1SSteen Hegelund .fco = fco, 451c9da1ac1SSteen Hegelund .vrule = vrule, 452*abc4010dSSteen Hegelund .l3_proto = ETH_P_ALL, 453c9da1ac1SSteen Hegelund }; 454c9da1ac1SSteen Hegelund int idx, err = 0; 455c9da1ac1SSteen Hegelund 456c9da1ac1SSteen Hegelund state.frule = flow_cls_offload_flow_rule(fco); 457c9da1ac1SSteen Hegelund for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) { 458c9da1ac1SSteen Hegelund if (!flow_rule_match_key(state.frule, idx)) 459c9da1ac1SSteen Hegelund continue; 460c9da1ac1SSteen Hegelund if (!sparx5_tc_flower_usage_handlers[idx]) 461c9da1ac1SSteen Hegelund continue; 462c9da1ac1SSteen Hegelund err = sparx5_tc_flower_usage_handlers[idx](&state); 463c9da1ac1SSteen Hegelund if (err) 464c9da1ac1SSteen Hegelund return err; 465c9da1ac1SSteen Hegelund } 466*abc4010dSSteen Hegelund 467*abc4010dSSteen Hegelund if (state.frule->match.dissector->used_keys ^ state.used_keys) { 468*abc4010dSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 469*abc4010dSSteen Hegelund "Unsupported match item"); 470*abc4010dSSteen Hegelund return -ENOENT; 471*abc4010dSSteen Hegelund } 472*abc4010dSSteen Hegelund 473*abc4010dSSteen Hegelund if (l3_proto) 474*abc4010dSSteen Hegelund *l3_proto = state.l3_proto; 475c9da1ac1SSteen Hegelund return err; 476c9da1ac1SSteen Hegelund } 477c9da1ac1SSteen Hegelund 478392d0ab0SSteen Hegelund static int sparx5_tc_flower_action_check(struct vcap_control *vctrl, 479392d0ab0SSteen Hegelund struct flow_cls_offload *fco, 480392d0ab0SSteen Hegelund struct vcap_admin *admin) 481392d0ab0SSteen Hegelund { 482392d0ab0SSteen Hegelund struct flow_rule *rule = flow_cls_offload_flow_rule(fco); 483392d0ab0SSteen Hegelund struct flow_action_entry *actent, *last_actent = NULL; 484392d0ab0SSteen Hegelund struct flow_action *act = &rule->action; 485392d0ab0SSteen Hegelund u64 action_mask = 0; 486392d0ab0SSteen Hegelund int idx; 487392d0ab0SSteen Hegelund 488392d0ab0SSteen Hegelund if (!flow_action_has_entries(act)) { 489392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); 490392d0ab0SSteen Hegelund return -EINVAL; 491392d0ab0SSteen Hegelund } 492392d0ab0SSteen Hegelund 493392d0ab0SSteen Hegelund if (!flow_action_basic_hw_stats_check(act, fco->common.extack)) 494392d0ab0SSteen Hegelund return -EOPNOTSUPP; 495392d0ab0SSteen Hegelund 496392d0ab0SSteen Hegelund flow_action_for_each(idx, actent, act) { 497392d0ab0SSteen Hegelund if (action_mask & BIT(actent->id)) { 498392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 499392d0ab0SSteen Hegelund "More actions of the same type"); 500392d0ab0SSteen Hegelund return -EINVAL; 501392d0ab0SSteen Hegelund } 502392d0ab0SSteen Hegelund action_mask |= BIT(actent->id); 503392d0ab0SSteen Hegelund last_actent = actent; /* Save last action for later check */ 504392d0ab0SSteen Hegelund } 505392d0ab0SSteen Hegelund 506392d0ab0SSteen Hegelund /* Check that last action is a goto */ 507392d0ab0SSteen Hegelund if (last_actent->id != FLOW_ACTION_GOTO) { 508392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 509392d0ab0SSteen Hegelund "Last action must be 'goto'"); 510392d0ab0SSteen Hegelund return -EINVAL; 511392d0ab0SSteen Hegelund } 512392d0ab0SSteen Hegelund 513392d0ab0SSteen Hegelund /* Check if the goto chain is in the next lookup */ 514392d0ab0SSteen Hegelund if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 515392d0ab0SSteen Hegelund last_actent->chain_index)) { 516392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 517392d0ab0SSteen Hegelund "Invalid goto chain"); 518392d0ab0SSteen Hegelund return -EINVAL; 519392d0ab0SSteen Hegelund } 520392d0ab0SSteen Hegelund 521392d0ab0SSteen Hegelund /* Catch unsupported combinations of actions */ 522392d0ab0SSteen Hegelund if (action_mask & BIT(FLOW_ACTION_TRAP) && 523392d0ab0SSteen Hegelund action_mask & BIT(FLOW_ACTION_ACCEPT)) { 524392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 525392d0ab0SSteen Hegelund "Cannot combine pass and trap action"); 526392d0ab0SSteen Hegelund return -EOPNOTSUPP; 527392d0ab0SSteen Hegelund } 528392d0ab0SSteen Hegelund 529392d0ab0SSteen Hegelund return 0; 530392d0ab0SSteen Hegelund } 531392d0ab0SSteen Hegelund 532c9da1ac1SSteen Hegelund static int sparx5_tc_flower_replace(struct net_device *ndev, 533c9da1ac1SSteen Hegelund struct flow_cls_offload *fco, 534c9da1ac1SSteen Hegelund struct vcap_admin *admin) 535c9da1ac1SSteen Hegelund { 536c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 537c9da1ac1SSteen Hegelund struct flow_action_entry *act; 538c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 539c9da1ac1SSteen Hegelund struct flow_rule *frule; 540c9da1ac1SSteen Hegelund struct vcap_rule *vrule; 541*abc4010dSSteen Hegelund u16 l3_proto; 542c9da1ac1SSteen Hegelund int err, idx; 543c9da1ac1SSteen Hegelund 544c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 545392d0ab0SSteen Hegelund 546392d0ab0SSteen Hegelund err = sparx5_tc_flower_action_check(vctrl, fco, admin); 547392d0ab0SSteen Hegelund if (err) 548392d0ab0SSteen Hegelund return err; 549392d0ab0SSteen Hegelund 550c9da1ac1SSteen Hegelund vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC, 551c9da1ac1SSteen Hegelund fco->common.prio, 0); 552c9da1ac1SSteen Hegelund if (IS_ERR(vrule)) 553c9da1ac1SSteen Hegelund return PTR_ERR(vrule); 554c9da1ac1SSteen Hegelund 555c9da1ac1SSteen Hegelund vrule->cookie = fco->cookie; 556*abc4010dSSteen Hegelund sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto); 557392d0ab0SSteen Hegelund frule = flow_cls_offload_flow_rule(fco); 558c9da1ac1SSteen Hegelund flow_action_for_each(idx, act, &frule->action) { 559c9da1ac1SSteen Hegelund switch (act->id) { 560c9da1ac1SSteen Hegelund case FLOW_ACTION_TRAP: 561c9da1ac1SSteen Hegelund err = vcap_rule_add_action_bit(vrule, 562c9da1ac1SSteen Hegelund VCAP_AF_CPU_COPY_ENA, 563c9da1ac1SSteen Hegelund VCAP_BIT_1); 564c9da1ac1SSteen Hegelund if (err) 565c9da1ac1SSteen Hegelund goto out; 566c9da1ac1SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 567c9da1ac1SSteen Hegelund VCAP_AF_CPU_QUEUE_NUM, 0); 568c9da1ac1SSteen Hegelund if (err) 569c9da1ac1SSteen Hegelund goto out; 570c9da1ac1SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, 571c9da1ac1SSteen Hegelund SPX5_PMM_REPLACE_ALL); 572c9da1ac1SSteen Hegelund if (err) 573c9da1ac1SSteen Hegelund goto out; 574c9da1ac1SSteen Hegelund /* For now the actionset is hardcoded */ 575c9da1ac1SSteen Hegelund err = vcap_set_rule_set_actionset(vrule, 576c9da1ac1SSteen Hegelund VCAP_AFS_BASE_TYPE); 577c9da1ac1SSteen Hegelund if (err) 578c9da1ac1SSteen Hegelund goto out; 579c9da1ac1SSteen Hegelund break; 580c9da1ac1SSteen Hegelund case FLOW_ACTION_ACCEPT: 581c9da1ac1SSteen Hegelund /* For now the actionset is hardcoded */ 582c9da1ac1SSteen Hegelund err = vcap_set_rule_set_actionset(vrule, 583c9da1ac1SSteen Hegelund VCAP_AFS_BASE_TYPE); 584c9da1ac1SSteen Hegelund if (err) 585c9da1ac1SSteen Hegelund goto out; 586c9da1ac1SSteen Hegelund break; 587392d0ab0SSteen Hegelund case FLOW_ACTION_GOTO: 588392d0ab0SSteen Hegelund /* Links between VCAPs will be added later */ 589392d0ab0SSteen Hegelund break; 590c9da1ac1SSteen Hegelund default: 591c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 592c9da1ac1SSteen Hegelund "Unsupported TC action"); 593c9da1ac1SSteen Hegelund err = -EOPNOTSUPP; 594c9da1ac1SSteen Hegelund goto out; 595c9da1ac1SSteen Hegelund } 596c9da1ac1SSteen Hegelund } 597*abc4010dSSteen Hegelund /* provide the l3 protocol to guide the keyset selection */ 598*abc4010dSSteen Hegelund err = vcap_val_rule(vrule, l3_proto); 599c9da1ac1SSteen Hegelund if (err) { 600c9da1ac1SSteen Hegelund vcap_set_tc_exterr(fco, vrule); 601c9da1ac1SSteen Hegelund goto out; 602c9da1ac1SSteen Hegelund } 603c9da1ac1SSteen Hegelund err = vcap_add_rule(vrule); 604c9da1ac1SSteen Hegelund if (err) 605c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 606c9da1ac1SSteen Hegelund "Could not add the filter"); 607c9da1ac1SSteen Hegelund out: 608c9da1ac1SSteen Hegelund vcap_free_rule(vrule); 609c9da1ac1SSteen Hegelund return err; 610c9da1ac1SSteen Hegelund } 611c9da1ac1SSteen Hegelund 612c9da1ac1SSteen Hegelund static int sparx5_tc_flower_destroy(struct net_device *ndev, 613c9da1ac1SSteen Hegelund struct flow_cls_offload *fco, 614c9da1ac1SSteen Hegelund struct vcap_admin *admin) 615c9da1ac1SSteen Hegelund { 616c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 617c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 618c9da1ac1SSteen Hegelund int err = -ENOENT, rule_id; 619c9da1ac1SSteen Hegelund 620c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 621c9da1ac1SSteen Hegelund while (true) { 622c9da1ac1SSteen Hegelund rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie); 623c9da1ac1SSteen Hegelund if (rule_id <= 0) 624c9da1ac1SSteen Hegelund break; 625c9da1ac1SSteen Hegelund err = vcap_del_rule(vctrl, ndev, rule_id); 626c9da1ac1SSteen Hegelund if (err) { 627c9da1ac1SSteen Hegelund pr_err("%s:%d: could not delete rule %d\n", 628c9da1ac1SSteen Hegelund __func__, __LINE__, rule_id); 629c9da1ac1SSteen Hegelund break; 630c9da1ac1SSteen Hegelund } 631c9da1ac1SSteen Hegelund } 632c9da1ac1SSteen Hegelund return err; 633c9da1ac1SSteen Hegelund } 634c9da1ac1SSteen Hegelund 635c9da1ac1SSteen Hegelund int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, 636c9da1ac1SSteen Hegelund bool ingress) 637c9da1ac1SSteen Hegelund { 638c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 639c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 640c9da1ac1SSteen Hegelund struct vcap_admin *admin; 641c9da1ac1SSteen Hegelund int err = -EINVAL; 642c9da1ac1SSteen Hegelund 643c9da1ac1SSteen Hegelund /* Get vcap instance from the chain id */ 644c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 645c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, fco->common.chain_index); 646c9da1ac1SSteen Hegelund if (!admin) { 647c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain"); 648c9da1ac1SSteen Hegelund return err; 649c9da1ac1SSteen Hegelund } 650c9da1ac1SSteen Hegelund 651c9da1ac1SSteen Hegelund switch (fco->command) { 652c9da1ac1SSteen Hegelund case FLOW_CLS_REPLACE: 653c9da1ac1SSteen Hegelund return sparx5_tc_flower_replace(ndev, fco, admin); 654c9da1ac1SSteen Hegelund case FLOW_CLS_DESTROY: 655c9da1ac1SSteen Hegelund return sparx5_tc_flower_destroy(ndev, fco, admin); 656c9da1ac1SSteen Hegelund default: 657c9da1ac1SSteen Hegelund return -EOPNOTSUPP; 658c9da1ac1SSteen Hegelund } 659c9da1ac1SSteen Hegelund } 660