diff options
Diffstat (limited to 'drivers/net/ethernet/microchip/vcap')
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_ag_api.h | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api.c | 39 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api_client.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c | 66 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_model_kunit.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_tc.c | 409 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_tc.h | 31 |
11 files changed, 566 insertions, 22 deletions
diff --git a/drivers/net/ethernet/microchip/vcap/Makefile b/drivers/net/ethernet/microchip/vcap/Makefile index 0adb8f5a8735..c86f20e6491f 100644 --- a/drivers/net/ethernet/microchip/vcap/Makefile +++ b/drivers/net/ethernet/microchip/vcap/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_VCAP) += vcap.o obj-$(CONFIG_VCAP_KUNIT_TEST) += vcap_model_kunit.o vcap-$(CONFIG_DEBUG_FS) += vcap_api_debugfs.o -vcap-y += vcap_api.o +vcap-y += vcap_api.o vcap_tc.o diff --git a/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h b/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h index 962383f20f1b..9c6766c4b75d 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h @@ -1,10 +1,10 @@ /* SPDX-License-Identifier: BSD-3-Clause */ -/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. +/* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries. * Microchip VCAP API */ -/* This file is autogenerated by cml-utils 2022-12-06 09:49:28 +0100. - * Commit ID: cd9451f1b9d8cafa58f845de66a6e373658019ef +/* This file is autogenerated by cml-utils 2023-01-17 16:52:16 +0100. + * Commit ID: 229ec79be5df142c1f335a01d0e63232d4feb2ba */ #ifndef __VCAP_AG_API__ @@ -276,7 +276,8 @@ enum vcap_keyfield_set { * Select the mode of the Generic Index * VCAP_KF_LOOKUP_PAG: W8, sparx5: is2, lan966x: is2 * Classified Policy Association Group: chains rules from IS1/CLM to IS2 - * VCAP_KF_MIRROR_ENA: *** No docstring *** + * VCAP_KF_MIRROR_PROBE: W2, sparx5: es2 + * Identifies frame copies generated as a result of mirroring * VCAP_KF_OAM_CCM_CNTS_EQ0: W1, sparx5: is2/es2, lan966x: is2 * Dual-ended loss measurement counters in CCM frames are all zero * VCAP_KF_OAM_DETECTED: W1, lan966x: is2 @@ -407,7 +408,7 @@ enum vcap_key_field { VCAP_KF_LOOKUP_GEN_IDX, VCAP_KF_LOOKUP_GEN_IDX_SEL, VCAP_KF_LOOKUP_PAG, - VCAP_KF_MIRROR_ENA, + VCAP_KF_MIRROR_PROBE, VCAP_KF_OAM_CCM_CNTS_EQ0, VCAP_KF_OAM_DETECTED, VCAP_KF_OAM_FLAGS, diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index 83223c4770f2..6307d59f23da 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -1601,15 +1601,17 @@ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) } EXPORT_SYMBOL_GPL(vcap_find_admin); -/* Is this the last admin instance ordered by chain id */ +/* Is this the last admin instance ordered by chain id and direction */ static bool vcap_admin_is_last(struct vcap_control *vctrl, - struct vcap_admin *admin) + struct vcap_admin *admin, + bool ingress) { struct vcap_admin *iter, *last = NULL; int max_cid = 0; list_for_each_entry(iter, &vctrl->list, list) { - if (iter->first_cid > max_cid) { + if (iter->first_cid > max_cid && + iter->ingress == ingress) { last = iter; max_cid = iter->first_cid; } @@ -2753,7 +2755,7 @@ int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key, EXPORT_SYMBOL_GPL(vcap_rule_get_key_u32); /* Find a client action field in a rule */ -static struct vcap_client_actionfield * +struct vcap_client_actionfield * vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act) { struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule; @@ -2764,6 +2766,7 @@ vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act) return caf; return NULL; } +EXPORT_SYMBOL_GPL(vcap_find_actionfield); /* Check if the actionfield is already in the rule */ static bool vcap_actionfield_unique(struct vcap_rule *rule, @@ -3177,7 +3180,7 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, EXPORT_SYMBOL_GPL(vcap_enable_lookups); /* Is this chain id the last lookup of all VCAPs */ -bool vcap_is_last_chain(struct vcap_control *vctrl, int cid) +bool vcap_is_last_chain(struct vcap_control *vctrl, int cid, bool ingress) { struct vcap_admin *admin; int lookup; @@ -3189,7 +3192,7 @@ bool vcap_is_last_chain(struct vcap_control *vctrl, int cid) if (!admin) return false; - if (!vcap_admin_is_last(vctrl, admin)) + if (!vcap_admin_is_last(vctrl, admin, ingress)) return false; /* This must be the last lookup in this VCAP type */ @@ -3264,6 +3267,28 @@ static int vcap_rule_get_key(struct vcap_rule *rule, return 0; } +/* Find a keyset having the same size as the provided rule, where the keyset + * does not have a type id. + */ +static int vcap_rule_get_untyped_keyset(struct vcap_rule_internal *ri, + struct vcap_keyset_list *matches) +{ + struct vcap_control *vctrl = ri->vctrl; + enum vcap_type vt = ri->admin->vtype; + const struct vcap_set *keyfield_set; + int idx; + + keyfield_set = vctrl->vcaps[vt].keyfield_set; + for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) { + if (keyfield_set[idx].sw_per_item == ri->keyset_sw && + keyfield_set[idx].type_id == (u8)-1) { + vcap_keyset_list_add(matches, idx); + return 0; + } + } + return -EINVAL; +} + /* Get the keysets that matches the rule key type/mask */ int vcap_rule_get_keysets(struct vcap_rule_internal *ri, struct vcap_keyset_list *matches) @@ -3277,7 +3302,7 @@ int vcap_rule_get_keysets(struct vcap_rule_internal *ri, err = vcap_rule_get_key(&ri->data, VCAP_KF_TYPE, &kf); if (err) - return err; + return vcap_rule_get_untyped_keyset(ri, matches); if (kf.ctrl.type == VCAP_FIELD_BIT) { value = kf.data.u1.value; diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.h b/drivers/net/ethernet/microchip/vcap/vcap_api.h index 40491116b0a9..62db270f65af 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.h @@ -176,6 +176,7 @@ struct vcap_admin { int first_valid_addr; /* bottom of address range to be used */ int last_used_addr; /* address of lowest added rule */ bool w32be; /* vcap uses "32bit-word big-endian" encoding */ + bool ingress; /* chain traffic direction */ struct vcap_cache_data cache; /* encoded rule data */ }; diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h index 69ea230ba8a1..417af9754bcc 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h @@ -222,7 +222,7 @@ int vcap_chain_offset(struct vcap_control *vctrl, int from_cid, int to_cid); /* Is the next chain id in the following lookup, possible in another VCAP */ bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid); /* Is this chain id the last lookup of all VCAPs */ -bool vcap_is_last_chain(struct vcap_control *vctrl, int cid); +bool vcap_is_last_chain(struct vcap_control *vctrl, int cid, bool ingress); /* Provide all rules via a callback interface */ int vcap_rule_iter(struct vcap_control *vctrl, int (*callback)(void *, struct vcap_rule *), void *arg); @@ -268,4 +268,7 @@ int vcap_rule_mod_action_u32(struct vcap_rule *rule, /* Get a 32 bit key field value and mask from the rule */ int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key, u32 *value, u32 *mask); + +struct vcap_client_actionfield * +vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act); #endif /* __VCAP_API_CLIENT__ */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c index d49b1cf7712f..c2c3397c5898 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c @@ -44,11 +44,14 @@ static void vcap_debugfs_show_rule_keyfield(struct vcap_control *vctrl, out->prf(out->dst, "%pI4h/%pI4h", &data->u32.value, &data->u32.mask); } else if (key == VCAP_KF_ETYPE || - key == VCAP_KF_IF_IGR_PORT_MASK) { + key == VCAP_KF_IF_IGR_PORT_MASK || + key == VCAP_KF_IF_EGR_PORT_MASK) { hex = true; } else { u32 fmsk = (1 << keyfield[key].width) - 1; + if (keyfield[key].width == 32) + fmsk = ~0; out->prf(out->dst, "%u/%u", data->u32.value & fmsk, data->u32.mask & fmsk); } @@ -277,6 +280,7 @@ static void vcap_show_admin_info(struct vcap_control *vctrl, out->prf(out->dst, "version: %d\n", vcap->version); out->prf(out->dst, "vtype: %d\n", admin->vtype); out->prf(out->dst, "vinst: %d\n", admin->vinst); + out->prf(out->dst, "ingress: %d\n", admin->ingress); out->prf(out->dst, "first_cid: %d\n", admin->first_cid); out->prf(out->dst, "last_cid: %d\n", admin->last_cid); out->prf(out->dst, "lookups: %d\n", admin->lookups); diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c index cbf7e0f110b8..b9c1c9d5eee8 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c @@ -389,6 +389,7 @@ static const char * const test_admin_info_expect[] = { "version: 1\n", "vtype: 2\n", "vinst: 0\n", + "ingress: 1\n", "first_cid: 10000\n", "last_cid: 19999\n", "lookups: 4\n", @@ -407,6 +408,7 @@ static void vcap_api_show_admin_test(struct kunit *test) .last_valid_addr = 3071, .first_valid_addr = 0, .last_used_addr = 794, + .ingress = true, }; struct vcap_output_print out = { .prf = (void *)test_prf, @@ -435,6 +437,7 @@ static const char * const test_admin_expect[] = { "version: 1\n", "vtype: 2\n", "vinst: 0\n", + "ingress: 1\n", "first_cid: 8000000\n", "last_cid: 8199999\n", "lookups: 4\n", @@ -496,6 +499,7 @@ static void vcap_api_show_admin_rule_test(struct kunit *test) .last_valid_addr = 3071, .first_valid_addr = 0, .last_used_addr = 794, + .ingress = true, .cache = { .keystream = keydata, .maskstream = mskdata, diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c index a31cd08e3752..b2753aac8ad2 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c @@ -2145,6 +2145,71 @@ static void vcap_api_filter_keylist_test(struct kunit *test) KUNIT_EXPECT_EQ(test, 26, idx); } +static void vcap_api_rule_chain_path_test(struct kunit *test) +{ + struct vcap_admin admin1 = { + .vtype = VCAP_TYPE_IS0, + .vinst = 0, + .first_cid = 1000000, + .last_cid = 1199999, + .lookups = 6, + .lookups_per_instance = 2, + }; + struct vcap_enabled_port eport3 = { + .ndev = &test_netdev, + .cookie = 0x100, + .src_cid = 0, + .dst_cid = 1000000, + }; + struct vcap_enabled_port eport2 = { + .ndev = &test_netdev, + .cookie = 0x200, + .src_cid = 1000000, + .dst_cid = 1100000, + }; + struct vcap_enabled_port eport1 = { + .ndev = &test_netdev, + .cookie = 0x300, + .src_cid = 1100000, + .dst_cid = 8000000, + }; + bool ret; + int chain; + + vcap_test_api_init(&admin1); + list_add_tail(&eport1.list, &admin1.enabled); + list_add_tail(&eport2.list, &admin1.enabled); + list_add_tail(&eport3.list, &admin1.enabled); + + ret = vcap_path_exist(&test_vctrl, &test_netdev, 1000000); + KUNIT_EXPECT_EQ(test, true, ret); + + ret = vcap_path_exist(&test_vctrl, &test_netdev, 1100000); + KUNIT_EXPECT_EQ(test, true, ret); + + ret = vcap_path_exist(&test_vctrl, &test_netdev, 1200000); + KUNIT_EXPECT_EQ(test, false, ret); + + chain = vcap_get_next_chain(&test_vctrl, &test_netdev, 0); + KUNIT_EXPECT_EQ(test, 1000000, chain); + + chain = vcap_get_next_chain(&test_vctrl, &test_netdev, 1000000); + KUNIT_EXPECT_EQ(test, 1100000, chain); + + chain = vcap_get_next_chain(&test_vctrl, &test_netdev, 1100000); + KUNIT_EXPECT_EQ(test, 8000000, chain); +} + +static struct kunit_case vcap_api_rule_enable_test_cases[] = { + KUNIT_CASE(vcap_api_rule_chain_path_test), + {} +}; + +static struct kunit_suite vcap_api_rule_enable_test_suite = { + .name = "VCAP_API_Rule_Enable_Testsuite", + .test_cases = vcap_api_rule_enable_test_cases, +}; + static struct kunit_suite vcap_api_rule_remove_test_suite = { .name = "VCAP_API_Rule_Remove_Testsuite", .test_cases = vcap_api_rule_remove_test_cases, @@ -2235,6 +2300,7 @@ static struct kunit_suite vcap_api_encoding_test_suite = { .test_cases = vcap_api_encoding_test_cases, }; +kunit_test_suite(vcap_api_rule_enable_test_suite); kunit_test_suite(vcap_api_rule_remove_test_suite); kunit_test_suite(vcap_api_rule_insert_test_suite); kunit_test_suite(vcap_api_rule_counter_test_suite); diff --git a/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.c index 85a8d8566aa2..6d5d73d00562 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_model_kunit.c @@ -1709,7 +1709,7 @@ static const struct vcap_field es2_mac_etype_keyfield[] = { .offset = 96, .width = 1, }, - [VCAP_KF_MIRROR_ENA] = { + [VCAP_KF_MIRROR_PROBE] = { .type = VCAP_FIELD_U32, .offset = 97, .width = 2, @@ -1847,7 +1847,7 @@ static const struct vcap_field es2_arp_keyfield[] = { .offset = 95, .width = 1, }, - [VCAP_KF_MIRROR_ENA] = { + [VCAP_KF_MIRROR_PROBE] = { .type = VCAP_FIELD_U32, .offset = 96, .width = 2, @@ -2010,7 +2010,7 @@ static const struct vcap_field es2_ip4_tcp_udp_keyfield[] = { .offset = 96, .width = 1, }, - [VCAP_KF_MIRROR_ENA] = { + [VCAP_KF_MIRROR_PROBE] = { .type = VCAP_FIELD_U32, .offset = 97, .width = 2, @@ -2223,7 +2223,7 @@ static const struct vcap_field es2_ip4_other_keyfield[] = { .offset = 96, .width = 1, }, - [VCAP_KF_MIRROR_ENA] = { + [VCAP_KF_MIRROR_PROBE] = { .type = VCAP_FIELD_U32, .offset = 97, .width = 2, @@ -2376,7 +2376,7 @@ static const struct vcap_field es2_ip_7tuple_keyfield[] = { .offset = 93, .width = 1, }, - [VCAP_KF_MIRROR_ENA] = { + [VCAP_KF_MIRROR_PROBE] = { .type = VCAP_FIELD_U32, .offset = 94, .width = 2, @@ -2569,7 +2569,7 @@ static const struct vcap_field es2_ip4_vid_keyfield[] = { .offset = 48, .width = 1, }, - [VCAP_KF_MIRROR_ENA] = { + [VCAP_KF_MIRROR_PROBE] = { .type = VCAP_FIELD_U32, .offset = 49, .width = 2, @@ -3847,7 +3847,7 @@ static const char * const vcap_keyfield_names[] = { [VCAP_KF_LOOKUP_GEN_IDX] = "LOOKUP_GEN_IDX", [VCAP_KF_LOOKUP_GEN_IDX_SEL] = "LOOKUP_GEN_IDX_SEL", [VCAP_KF_LOOKUP_PAG] = "LOOKUP_PAG", - [VCAP_KF_MIRROR_ENA] = "MIRROR_ENA", + [VCAP_KF_MIRROR_PROBE] = "MIRROR_PROBE", [VCAP_KF_OAM_CCM_CNTS_EQ0] = "OAM_CCM_CNTS_EQ0", [VCAP_KF_OAM_DETECTED] = "OAM_DETECTED", [VCAP_KF_OAM_FLAGS] = "OAM_FLAGS", diff --git a/drivers/net/ethernet/microchip/vcap/vcap_tc.c b/drivers/net/ethernet/microchip/vcap/vcap_tc.c new file mode 100644 index 000000000000..09a994a7cec2 --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_tc.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip VCAP TC + * + * Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries. + */ + +#include <net/flow_offload.h> +#include <net/ipv6.h> +#include <net/tcp.h> + +#include "vcap_api_client.h" +#include "vcap_tc.h" + +enum vcap_is2_arp_opcode { + VCAP_IS2_ARP_REQUEST, + VCAP_IS2_ARP_REPLY, + VCAP_IS2_RARP_REQUEST, + VCAP_IS2_RARP_REPLY, +}; + +enum vcap_arp_opcode { + VCAP_ARP_OP_RESERVED, + VCAP_ARP_OP_REQUEST, + VCAP_ARP_OP_REPLY, +}; + +int vcap_tc_flower_handler_ethaddr_usage(struct vcap_tc_flower_parse_usage *st) +{ + enum vcap_key_field smac_key = VCAP_KF_L2_SMAC; + enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC; + struct flow_match_eth_addrs match; + struct vcap_u48_key smac, dmac; + int err = 0; + + flow_rule_match_eth_addrs(st->frule, &match); + + if (!is_zero_ether_addr(match.mask->src)) { + vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN); + vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN); + err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac); + if (err) + goto out; + } + + if (!is_zero_ether_addr(match.mask->dst)) { + vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN); + vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN); + err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ethaddr_usage); + +int vcap_tc_flower_handler_ipv4_usage(struct vcap_tc_flower_parse_usage *st) +{ + int err = 0; + + if (st->l3_proto == ETH_P_IP) { + struct flow_match_ipv4_addrs mt; + + flow_rule_match_ipv4_addrs(st->frule, &mt); + if (mt.mask->src) { + err = vcap_rule_add_key_u32(st->vrule, + VCAP_KF_L3_IP4_SIP, + be32_to_cpu(mt.key->src), + be32_to_cpu(mt.mask->src)); + if (err) + goto out; + } + if (mt.mask->dst) { + err = vcap_rule_add_key_u32(st->vrule, + VCAP_KF_L3_IP4_DIP, + be32_to_cpu(mt.key->dst), + be32_to_cpu(mt.mask->dst)); + if (err) + goto out; + } + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv4_usage); + +int vcap_tc_flower_handler_ipv6_usage(struct vcap_tc_flower_parse_usage *st) +{ + int err = 0; + + if (st->l3_proto == ETH_P_IPV6) { + struct flow_match_ipv6_addrs mt; + struct vcap_u128_key sip; + struct vcap_u128_key dip; + + flow_rule_match_ipv6_addrs(st->frule, &mt); + /* Check if address masks are non-zero */ + if (!ipv6_addr_any(&mt.mask->src)) { + vcap_netbytes_copy(sip.value, mt.key->src.s6_addr, 16); + vcap_netbytes_copy(sip.mask, mt.mask->src.s6_addr, 16); + err = vcap_rule_add_key_u128(st->vrule, + VCAP_KF_L3_IP6_SIP, &sip); + if (err) + goto out; + } + if (!ipv6_addr_any(&mt.mask->dst)) { + vcap_netbytes_copy(dip.value, mt.key->dst.s6_addr, 16); + vcap_netbytes_copy(dip.mask, mt.mask->dst.s6_addr, 16); + err = vcap_rule_add_key_u128(st->vrule, + VCAP_KF_L3_IP6_DIP, &dip); + if (err) + goto out; + } + } + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS); + return err; +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv6_usage); + +int vcap_tc_flower_handler_portnum_usage(struct vcap_tc_flower_parse_usage *st) +{ + struct flow_match_ports mt; + u16 value, mask; + int err = 0; + + flow_rule_match_ports(st->frule, &mt); + + if (mt.mask->src) { + value = be16_to_cpu(mt.key->src); + mask = be16_to_cpu(mt.mask->src); + err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_SPORT, value, + mask); + if (err) + goto out; + } + + if (mt.mask->dst) { + value = be16_to_cpu(mt.key->dst); + mask = be16_to_cpu(mt.mask->dst); + err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_DPORT, value, + mask); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_portnum_usage); + +int vcap_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st) +{ + enum vcap_key_field vid_key = VCAP_KF_8021Q_VID0; + enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP0; + struct flow_match_vlan mt; + u16 tpid; + int err; + + flow_rule_match_cvlan(st->frule, &mt); + + tpid = be16_to_cpu(mt.key->vlan_tpid); + + if (tpid == ETH_P_8021Q) { + vid_key = VCAP_KF_8021Q_VID1; + pcp_key = VCAP_KF_8021Q_PCP1; + } + + if (mt.mask->vlan_id) { + err = vcap_rule_add_key_u32(st->vrule, vid_key, + mt.key->vlan_id, + mt.mask->vlan_id); + if (err) + goto out; + } + + if (mt.mask->vlan_priority) { + err = vcap_rule_add_key_u32(st->vrule, pcp_key, + mt.key->vlan_priority, + mt.mask->vlan_priority); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CVLAN); + + return 0; +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "cvlan parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_cvlan_usage); + +int vcap_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st, + enum vcap_key_field vid_key, + enum vcap_key_field pcp_key) +{ + struct flow_match_vlan mt; + int err; + + flow_rule_match_vlan(st->frule, &mt); + + if (mt.mask->vlan_id) { + err = vcap_rule_add_key_u32(st->vrule, vid_key, + mt.key->vlan_id, + mt.mask->vlan_id); + if (err) + goto out; + } + + if (mt.mask->vlan_priority) { + err = vcap_rule_add_key_u32(st->vrule, pcp_key, + mt.key->vlan_priority, + mt.mask->vlan_priority); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN); + + return 0; +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_vlan_usage); + +int vcap_tc_flower_handler_tcp_usage(struct vcap_tc_flower_parse_usage *st) +{ + struct flow_match_tcp mt; + u16 tcp_flags_mask; + u16 tcp_flags_key; + enum vcap_bit val; + int err = 0; + + flow_rule_match_tcp(st->frule, &mt); + tcp_flags_key = be16_to_cpu(mt.key->flags); + tcp_flags_mask = be16_to_cpu(mt.mask->flags); + + if (tcp_flags_mask & TCPHDR_FIN) { + val = VCAP_BIT_0; + if (tcp_flags_key & TCPHDR_FIN) + val = VCAP_BIT_1; + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_FIN, val); + if (err) + goto out; + } + + if (tcp_flags_mask & TCPHDR_SYN) { + val = VCAP_BIT_0; + if (tcp_flags_key & TCPHDR_SYN) + val = VCAP_BIT_1; + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_SYN, val); + if (err) + goto out; + } + + if (tcp_flags_mask & TCPHDR_RST) { + val = VCAP_BIT_0; + if (tcp_flags_key & TCPHDR_RST) + val = VCAP_BIT_1; + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_RST, val); + if (err) + goto out; + } + + if (tcp_flags_mask & TCPHDR_PSH) { + val = VCAP_BIT_0; + if (tcp_flags_key & TCPHDR_PSH) + val = VCAP_BIT_1; + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_PSH, val); + if (err) + goto out; + } + + if (tcp_flags_mask & TCPHDR_ACK) { + val = VCAP_BIT_0; + if (tcp_flags_key & TCPHDR_ACK) + val = VCAP_BIT_1; + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_ACK, val); + if (err) + goto out; + } + + if (tcp_flags_mask & TCPHDR_URG) { + val = VCAP_BIT_0; + if (tcp_flags_key & TCPHDR_URG) + val = VCAP_BIT_1; + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_URG, val); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_tcp_usage); + +int vcap_tc_flower_handler_arp_usage(struct vcap_tc_flower_parse_usage *st) +{ + struct flow_match_arp mt; + u16 value, mask; + u32 ipval, ipmsk; + int err; + + flow_rule_match_arp(st->frule, &mt); + + if (mt.mask->op) { + mask = 0x3; + if (st->l3_proto == ETH_P_ARP) { + value = mt.key->op == VCAP_ARP_OP_REQUEST ? + VCAP_IS2_ARP_REQUEST : + VCAP_IS2_ARP_REPLY; + } else { /* RARP */ + value = mt.key->op == VCAP_ARP_OP_REQUEST ? + VCAP_IS2_RARP_REQUEST : + VCAP_IS2_RARP_REPLY; + } + err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ARP_OPCODE, + value, mask); + if (err) + goto out; + } + + /* The IS2 ARP keyset does not support ARP hardware addresses */ + if (!is_zero_ether_addr(mt.mask->sha) || + !is_zero_ether_addr(mt.mask->tha)) { + err = -EINVAL; + goto out; + } + + if (mt.mask->sip) { + ipval = be32_to_cpu((__force __be32)mt.key->sip); + ipmsk = be32_to_cpu((__force __be32)mt.mask->sip); + + err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_SIP, + ipval, ipmsk); + if (err) + goto out; + } + + if (mt.mask->tip) { + ipval = be32_to_cpu((__force __be32)mt.key->tip); + ipmsk = be32_to_cpu((__force __be32)mt.mask->tip); + + err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_DIP, + ipval, ipmsk); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ARP); + + return 0; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_arp_usage); + +int vcap_tc_flower_handler_ip_usage(struct vcap_tc_flower_parse_usage *st) +{ + struct flow_match_ip mt; + int err = 0; + + flow_rule_match_ip(st->frule, &mt); + + if (mt.mask->tos) { + err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_TOS, + mt.key->tos, + mt.mask->tos); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IP); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error"); + return err; +} +EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ip_usage); diff --git a/drivers/net/ethernet/microchip/vcap/vcap_tc.h b/drivers/net/ethernet/microchip/vcap/vcap_tc.h new file mode 100644 index 000000000000..5c55ccbee175 --- /dev/null +++ b/drivers/net/ethernet/microchip/vcap/vcap_tc.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP TC + */ + +#ifndef __VCAP_TC__ +#define __VCAP_TC__ + +struct vcap_tc_flower_parse_usage { + struct flow_cls_offload *fco; + struct flow_rule *frule; + struct vcap_rule *vrule; + struct vcap_admin *admin; + u16 l3_proto; + u8 l4_proto; + unsigned int used_keys; +}; + +int vcap_tc_flower_handler_ethaddr_usage(struct vcap_tc_flower_parse_usage *st); +int vcap_tc_flower_handler_ipv4_usage(struct vcap_tc_flower_parse_usage *st); +int vcap_tc_flower_handler_ipv6_usage(struct vcap_tc_flower_parse_usage *st); +int vcap_tc_flower_handler_portnum_usage(struct vcap_tc_flower_parse_usage *st); +int vcap_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st); +int vcap_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st, + enum vcap_key_field vid_key, + enum vcap_key_field pcp_key); +int vcap_tc_flower_handler_tcp_usage(struct vcap_tc_flower_parse_usage *st); +int vcap_tc_flower_handler_arp_usage(struct vcap_tc_flower_parse_usage *st); +int vcap_tc_flower_handler_ip_usage(struct vcap_tc_flower_parse_usage *st); + +#endif /* __VCAP_TC__ */ |