diff options
Diffstat (limited to 'drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c')
-rw-r--r-- | drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c | 198 |
1 files changed, 152 insertions, 46 deletions
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c index ba3fa917d6b7..f960727ecaee 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c @@ -3,53 +3,135 @@ #include "lan966x_main.h" #include "vcap_api.h" #include "vcap_api_client.h" +#include "vcap_tc.h" -struct lan966x_tc_flower_parse_usage { - struct flow_cls_offload *f; - struct flow_rule *frule; - struct vcap_rule *vrule; - unsigned int used_keys; - u16 l3_proto; -}; +static bool lan966x_tc_is_known_etype(u16 etype) +{ + switch (etype) { + case ETH_P_ALL: + case ETH_P_ARP: + case ETH_P_IP: + case ETH_P_IPV6: + return true; + } + + return false; +} -static int lan966x_tc_flower_handler_ethaddr_usage(struct lan966x_tc_flower_parse_usage *st) +static int +lan966x_tc_flower_handler_control_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; + struct flow_match_control match; 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); + flow_rule_match_control(st->frule, &match); + if (match.mask->flags & FLOW_DIS_IS_FRAGMENT) { + if (match.key->flags & FLOW_DIS_IS_FRAGMENT) + err = vcap_rule_add_key_bit(st->vrule, + VCAP_KF_L3_FRAGMENT, + VCAP_BIT_1); + else + err = vcap_rule_add_key_bit(st->vrule, + VCAP_KF_L3_FRAGMENT, + VCAP_BIT_0); 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 (match.mask->flags & FLOW_DIS_FIRST_FRAG) { + if (match.key->flags & FLOW_DIS_FIRST_FRAG) + err = vcap_rule_add_key_bit(st->vrule, + VCAP_KF_L3_FRAG_OFS_GT0, + VCAP_BIT_0); + else + err = vcap_rule_add_key_bit(st->vrule, + VCAP_KF_L3_FRAG_OFS_GT0, + VCAP_BIT_1); if (err) goto out; } - st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS); + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL); return err; out: - NL_SET_ERR_MSG_MOD(st->f->common.extack, "eth_addr parse error"); + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); return err; } static int -(*lan966x_tc_flower_handlers_usage[])(struct lan966x_tc_flower_parse_usage *st) = { - [FLOW_DISSECTOR_KEY_ETH_ADDRS] = lan966x_tc_flower_handler_ethaddr_usage, +lan966x_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st) +{ + struct flow_match_basic match; + int err = 0; + + flow_rule_match_basic(st->frule, &match); + if (match.mask->n_proto) { + st->l3_proto = be16_to_cpu(match.key->n_proto); + if (!lan966x_tc_is_known_etype(st->l3_proto)) { + err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, + st->l3_proto, ~0); + if (err) + goto out; + } else if (st->l3_proto == ETH_P_IP) { + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, + VCAP_BIT_1); + if (err) + goto out; + } + } + if (match.mask->ip_proto) { + st->l4_proto = match.key->ip_proto; + + if (st->l4_proto == IPPROTO_TCP) { + err = vcap_rule_add_key_bit(st->vrule, + VCAP_KF_TCP_IS, + VCAP_BIT_1); + if (err) + goto out; + } else if (st->l4_proto == IPPROTO_UDP) { + err = vcap_rule_add_key_bit(st->vrule, + VCAP_KF_TCP_IS, + VCAP_BIT_0); + if (err) + goto out; + } else { + err = vcap_rule_add_key_u32(st->vrule, + VCAP_KF_L3_IP_PROTO, + st->l4_proto, ~0); + if (err) + goto out; + } + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC); + return err; +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error"); + return err; +} + +static int +lan966x_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st) +{ + return vcap_tc_flower_handler_vlan_usage(st, + VCAP_KF_8021Q_VID_CLS, + VCAP_KF_8021Q_PCP_CLS); +} + +static int +(*lan966x_tc_flower_handlers_usage[])(struct vcap_tc_flower_parse_usage *st) = { + [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage, + [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage, + [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage, + [FLOW_DISSECTOR_KEY_CONTROL] = lan966x_tc_flower_handler_control_usage, + [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage, + [FLOW_DISSECTOR_KEY_BASIC] = lan966x_tc_flower_handler_basic_usage, + [FLOW_DISSECTOR_KEY_VLAN] = lan966x_tc_flower_handler_vlan_usage, + [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage, + [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage, + [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage, }; static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f, @@ -57,8 +139,8 @@ static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f, struct vcap_rule *vrule, u16 *l3_proto) { - struct lan966x_tc_flower_parse_usage state = { - .f = f, + struct vcap_tc_flower_parse_usage state = { + .fco = f, .vrule = vrule, .l3_proto = ETH_P_ALL, }; @@ -82,8 +164,9 @@ static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f, } static int lan966x_tc_flower_action_check(struct vcap_control *vctrl, + struct net_device *dev, struct flow_cls_offload *fco, - struct vcap_admin *admin) + bool ingress) { struct flow_rule *rule = flow_cls_offload_flow_rule(fco); struct flow_action_entry *actent, *last_actent = NULL; @@ -109,21 +192,24 @@ static int lan966x_tc_flower_action_check(struct vcap_control *vctrl, last_actent = actent; /* Save last action for later check */ } - /* Check that last action is a goto */ - if (last_actent->id != FLOW_ACTION_GOTO) { + /* Check that last action is a goto + * The last chain/lookup does not need to have goto action + */ + if (last_actent->id == FLOW_ACTION_GOTO) { + /* Check if the destination chain is in one of the VCAPs */ + if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, + last_actent->chain_index)) { + NL_SET_ERR_MSG_MOD(fco->common.extack, + "Invalid goto chain"); + return -EINVAL; + } + } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index, + ingress)) { NL_SET_ERR_MSG_MOD(fco->common.extack, "Last action must be 'goto'"); return -EINVAL; } - /* Check if the goto chain is in the next lookup */ - if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, - last_actent->chain_index)) { - NL_SET_ERR_MSG_MOD(fco->common.extack, - "Invalid goto chain"); - return -EINVAL; - } - /* Catch unsupported combinations of actions */ if (action_mask & BIT(FLOW_ACTION_TRAP) && action_mask & BIT(FLOW_ACTION_ACCEPT)) { @@ -137,7 +223,8 @@ static int lan966x_tc_flower_action_check(struct vcap_control *vctrl, static int lan966x_tc_flower_add(struct lan966x_port *port, struct flow_cls_offload *f, - struct vcap_admin *admin) + struct vcap_admin *admin, + bool ingress) { struct flow_action_entry *act; u16 l3_proto = ETH_P_ALL; @@ -145,8 +232,8 @@ static int lan966x_tc_flower_add(struct lan966x_port *port, struct vcap_rule *vrule; int err, idx; - err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, f, - admin); + err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, + port->dev, f, ingress); if (err) return err; @@ -174,8 +261,6 @@ static int lan966x_tc_flower_add(struct lan966x_port *port, 0); err |= vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, LAN966X_PMM_REPLACE); - err |= vcap_set_rule_set_actionset(vrule, - VCAP_AFS_BASE_TYPE); if (err) goto out; @@ -229,8 +314,27 @@ static int lan966x_tc_flower_del(struct lan966x_port *port, return err; } +static int lan966x_tc_flower_stats(struct lan966x_port *port, + struct flow_cls_offload *f, + struct vcap_admin *admin) +{ + struct vcap_counter count = {}; + int err; + + err = vcap_get_rule_count_by_cookie(port->lan966x->vcap_ctrl, + &count, f->cookie); + if (err) + return err; + + flow_stats_update(&f->stats, 0x0, count.value, 0, 0, + FLOW_ACTION_HW_STATS_IMMEDIATE); + + return err; +} + int lan966x_tc_flower(struct lan966x_port *port, - struct flow_cls_offload *f) + struct flow_cls_offload *f, + bool ingress) { struct vcap_admin *admin; @@ -243,9 +347,11 @@ int lan966x_tc_flower(struct lan966x_port *port, switch (f->command) { case FLOW_CLS_REPLACE: - return lan966x_tc_flower_add(port, f, admin); + return lan966x_tc_flower_add(port, f, admin, ingress); case FLOW_CLS_DESTROY: return lan966x_tc_flower_del(port, f, admin); + case FLOW_CLS_STATS: + return lan966x_tc_flower_stats(port, f, admin); default: return -EOPNOTSUPP; } |